From 2b5e1ea62ec084fc4706e2aa8db0ba819b74c4c2 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 16 Oct 2020 16:38:25 +0200 Subject: CppEditor: Fix some "convert to camel case" edge cases Fixes: QTCREATORBUG-16560 Change-Id: I8573ae6c5dce0956c868addc69a921c62f1d571a Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfix_test.cpp | 33 ++++++++++++++++ src/plugins/cppeditor/cppquickfixes.cpp | 54 +++++++++++++++++--------- src/plugins/cppeditor/cppquickfixes.h | 5 +++ src/plugins/cpptools/cpprefactoringchanges.cpp | 2 +- src/plugins/cpptools/cpprefactoringchanges.h | 2 +- 5 files changed, 76 insertions(+), 20 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 4da9174b4f..1dbfeafedf 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -2047,6 +2047,39 @@ void CppEditorPlugin::test_quickfix_data() << CppQuickFixFactoryPtr(new InsertQtPropertyMembers) << _("class C { @Q_PROPERTY(typeid foo READ foo) };\n") << _(); + + QTest::newRow("convert to camel case: normal") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void @lower_case_function();\n") + << _("void lowerCaseFunction();\n"); + QTest::newRow("convert to camel case: already camel case") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void @camelCaseFunction();\n") + << _(); + QTest::newRow("convert to camel case: no underscores (lower case)") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void @lowercasefunction();\n") + << _(); + QTest::newRow("convert to camel case: no underscores (upper case)") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void @UPPERCASEFUNCTION();\n") + << _(); + QTest::newRow("convert to camel case: non-applicable underscore") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void @m_a_member;\n") + << _("void m_aMember;\n"); + QTest::newRow("convert to camel case: upper case") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void @UPPER_CASE_FUNCTION();\n") + << _("void upperCaseFunction();\n"); + QTest::newRow("convert to camel case: partially camel case already") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void mixed@_andCamelCase();\n") + << _("void mixedAndCamelCase();\n"); + QTest::newRow("convert to camel case: wild mix") + << CppQuickFixFactoryPtr(new ConvertToCamelCase(true)) + << _("void @WhAt_TODO_hErE();\n") + << _("void WhAtTODOHErE();\n"); } void CppEditorPlugin::test_quickfix() diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index c8929a6ff9..50d0da5aff 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -2002,9 +2002,13 @@ namespace { class ConvertToCamelCaseOp: public CppQuickFixOperation { public: - ConvertToCamelCaseOp(const CppQuickFixInterface &interface, const QString &newName) + ConvertToCamelCaseOp(const CppQuickFixInterface &interface, const QString &name, + const AST *nameAst, bool test) : CppQuickFixOperation(interface, -1) - , m_name(newName) + , m_name(name) + , m_nameAst(nameAst) + , m_isAllUpper(name.isUpper()) + , m_test(test) { setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Camel Case")); } @@ -2014,17 +2018,24 @@ public: CppRefactoringChanges refactoring(snapshot()); CppRefactoringFilePtr currentFile = refactoring.file(filePath().toString()); - for (int i = 1; i < m_name.length(); ++i) { - const QChar c = m_name.at(i); - if (c.isUpper()) { - m_name[i] = c.toLower(); - } else if (i < m_name.length() - 1 - && isConvertibleUnderscore(m_name, i)) { - m_name.remove(i, 1); - m_name[i] = m_name.at(i).toUpper(); + QString newName = m_isAllUpper ? m_name.toLower() : m_name; + for (int i = 1; i < newName.length(); ++i) { + const QChar c = newName.at(i); + if (c.isUpper() && m_isAllUpper) { + newName[i] = c.toLower(); + } else if (i < newName.length() - 1 && isConvertibleUnderscore(newName, i)) { + newName.remove(i, 1); + newName[i] = newName.at(i).toUpper(); } } - editor()->renameUsages(m_name); + if (m_test) { + ChangeSet changeSet; + changeSet.replace(currentFile->range(m_nameAst), newName); + currentFile->setChangeSet(changeSet); + currentFile->apply(); + } else { + editor()->renameUsages(newName); + } } static bool isConvertibleUnderscore(const QString &name, int pos) @@ -2034,7 +2045,10 @@ public: } private: - QString m_name; + const QString m_name; + const AST * const m_nameAst; + const bool m_isAllUpper; + const bool m_test; }; } // anonymous namespace @@ -2048,22 +2062,26 @@ void ConvertToCamelCase::match(const CppQuickFixInterface &interface, QuickFixOp AST * const ast = path.last(); const Name *name = nullptr; + const AST *astForName = nullptr; if (const NameAST * const nameAst = ast->asName()) { - if (nameAst->name && nameAst->name->asNameId()) + if (nameAst->name && nameAst->name->asNameId()) { + astForName = nameAst; name = nameAst->name; + } } else if (const NamespaceAST * const namespaceAst = ast->asNamespace()) { + astForName = namespaceAst; name = namespaceAst->symbol->name(); } if (!name) return; - QString newName = QString::fromUtf8(name->identifier()->chars()); - if (newName.length() < 3) + QString nameString = QString::fromUtf8(name->identifier()->chars()); + if (nameString.length() < 3) return; - for (int i = 1; i < newName.length() - 1; ++i) { - if (ConvertToCamelCaseOp::isConvertibleUnderscore(newName, i)) { - result << new ConvertToCamelCaseOp(interface, newName); + for (int i = 1; i < nameString.length() - 1; ++i) { + if (ConvertToCamelCaseOp::isConvertibleUnderscore(nameString, i)) { + result << new ConvertToCamelCaseOp(interface, nameString, astForName, m_test); return; } } diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h index 91bd8c9a62..4a9d1ab357 100644 --- a/src/plugins/cppeditor/cppquickfixes.h +++ b/src/plugins/cppeditor/cppquickfixes.h @@ -221,7 +221,12 @@ public: class ConvertToCamelCase : public CppQuickFixFactory { public: + ConvertToCamelCase(bool test = false) : CppQuickFixFactory(), m_test(test) {} + void match(const CppQuickFixInterface &interface, QuickFixOperations &result) override; + +private: + const bool m_test; }; /*! diff --git a/src/plugins/cpptools/cpprefactoringchanges.cpp b/src/plugins/cpptools/cpprefactoringchanges.cpp index 509506d5a1..a86dd6451b 100644 --- a/src/plugins/cpptools/cpprefactoringchanges.cpp +++ b/src/plugins/cpptools/cpprefactoringchanges.cpp @@ -213,7 +213,7 @@ Utils::ChangeSet::Range CppRefactoringFile::range(unsigned tokenIndex) const return {start, start + token.utf16chars()}; } -Utils::ChangeSet::Range CppRefactoringFile::range(AST *ast) const +Utils::ChangeSet::Range CppRefactoringFile::range(const AST *ast) const { return {startOf(ast), endOf(ast)}; } diff --git a/src/plugins/cpptools/cpprefactoringchanges.h b/src/plugins/cpptools/cpprefactoringchanges.h index 3a547a90c5..58fbf39eee 100644 --- a/src/plugins/cpptools/cpprefactoringchanges.h +++ b/src/plugins/cpptools/cpprefactoringchanges.h @@ -52,7 +52,7 @@ public: Range range(int start, int end) const; Range range(unsigned tokenIndex) const; - Range range(CPlusPlus::AST *ast) const; + Range range(const CPlusPlus::AST *ast) const; const CPlusPlus::Token &tokenAt(unsigned index) const; -- cgit v1.2.3