aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/cppeditor
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2021-05-31 15:57:44 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2021-06-18 11:11:17 +0000
commit41dafc8132ead035b4c02e6f7332ed35fc8dcbc7 (patch)
tree4be977d002165bd3debadde4866baa5c4f1337a9 /src/plugins/cppeditor
parentde6c7696d2ce8f3424146ebe0b6cf172361b9b87 (diff)
ClangCodeModel: Implement declaration/definition switch via clangd
Change-Id: I522a415d76fbc5332e5cc1fdfd2d7ab19cb9ed64 Reviewed-by: David Schulz <david.schulz@qt.io>
Diffstat (limited to 'src/plugins/cppeditor')
-rw-r--r--src/plugins/cppeditor/cppeditorwidget.cpp81
-rw-r--r--src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp132
2 files changed, 135 insertions, 78 deletions
diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp
index 7e48d545456..7083707b6d7 100644
--- a/src/plugins/cppeditor/cppeditorwidget.cpp
+++ b/src/plugins/cppeditor/cppeditorwidget.cpp
@@ -711,78 +711,15 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
if (!d->m_modelManager)
return;
- if (!d->m_lastSemanticInfo.doc)
- return;
-
- // Find function declaration or definition under cursor
- Function *functionDefinitionSymbol = nullptr;
- Symbol *functionDeclarationSymbol = nullptr;
- Symbol *declarationSymbol = nullptr;
-
- ASTPath astPathFinder(d->m_lastSemanticInfo.doc);
- const QList<AST *> astPath = astPathFinder(textCursor());
-
- for (AST *ast : astPath) {
- if (FunctionDefinitionAST *functionDefinitionAST = ast->asFunctionDefinition()) {
- if ((functionDefinitionSymbol = functionDefinitionAST->symbol))
- break; // Function definition found!
- } else if (SimpleDeclarationAST *simpleDeclaration = ast->asSimpleDeclaration()) {
- if (List<Symbol *> *symbols = simpleDeclaration->symbols) {
- if (Symbol *symbol = symbols->value) {
- if (symbol->isDeclaration()) {
- declarationSymbol = symbol;
- if (symbol->type()->isFunctionType()) {
- functionDeclarationSymbol = symbol;
- break; // Function declaration found!
- }
- }
- }
- }
- }
- }
-
- // Link to function definition/declaration
- Utils::Link symbolLink;
- if (functionDeclarationSymbol) {
- Symbol *symbol = d->m_modelManager->symbolFinder()
- ->findMatchingDefinition(functionDeclarationSymbol, d->m_modelManager->snapshot());
- if (symbol)
- symbolLink = symbol->toLink();
- } else if (declarationSymbol) {
- Symbol *symbol = d->m_modelManager->symbolFinder()
- ->findMatchingVarDefinition(declarationSymbol, d->m_modelManager->snapshot());
- if (symbol)
- symbolLink = symbol->toLink();
- } else if (functionDefinitionSymbol) {
- const Snapshot snapshot = d->m_modelManager->snapshot();
- LookupContext context(d->m_lastSemanticInfo.doc, snapshot);
- ClassOrNamespace *binding = context.lookupType(functionDefinitionSymbol);
- const QList<LookupItem> declarations
- = context.lookup(functionDefinitionSymbol->name(),
- functionDefinitionSymbol->enclosingScope());
-
- QList<Symbol *> best;
- foreach (const LookupItem &r, declarations) {
- if (Symbol *decl = r.declaration()) {
- if (Function *funTy = decl->type()->asFunctionType()) {
- if (funTy->match(functionDefinitionSymbol)) {
- if (decl != functionDefinitionSymbol && binding == r.binding())
- best.prepend(decl);
- else
- best.append(decl);
- }
- }
- }
- }
-
- if (best.isEmpty())
- return;
- symbolLink = best.first()->toLink();
- }
-
- // Open Editor at link position
- if (symbolLink.hasValidTarget())
- openLink(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit());
+ const CursorInEditor cursor(textCursor(), textDocument()->filePath(), this, textDocument());
+ auto callback = [self = QPointer(this),
+ split = inNextSplit != alwaysOpenLinksInNextSplit()](const Link &link) {
+ if (self && link.hasValidTarget())
+ self->openLink(link, split);
+ };
+ followSymbolInterface().switchDeclDef(cursor, std::move(callback),
+ d->m_modelManager->snapshot(), d->m_lastSemanticInfo.doc,
+ d->m_modelManager->symbolFinder());
}
void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
index 401a7eb39fa..5eefae1e02c 100644
--- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
+++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
@@ -297,14 +297,12 @@ F2TestCase::F2TestCase(CppEditorAction action,
QSKIP("fuzzy matching is not supposed to work with clangd"); // TODO: Implement fallback as we do with libclang
if (tag == "baseClassFunctionIntroducedByUsingDeclaration")
QSKIP("clangd points to the using declaration");
- if (tag == "classDestructor")
+ if (tag == "classDestructor" || tag == "fromDestructorDefinitionSymbol"
+ || tag == "fromDestructorBody") {
QSKIP("clangd wants the cursor before the ~ character");
+ }
if (curTestName == "test_FollowSymbolUnderCursor_classOperator_inOp")
QSKIP("clangd goes to operator name first");
- if (tag == "fromFunctionBody" || tag == "fromReturnType"
- || tag == "conversionOperatorDecl2Def") {
- QSKIP("TODO: explicit decl/def switch not yet supported with clangd");
- }
}
// Write files to disk
@@ -415,7 +413,9 @@ F2TestCase::F2TestCase(CppEditorAction action,
break;
}
case SwitchBetweenMethodDeclarationDefinitionAction:
- if (CppTools::codeModelSettings()->useClangd())
+ // Some test cases were erroneously added as decl/def, but they are really
+ // follow symbol functionality (in commit a0764603d0).
+ if (useClangd && tag.endsWith("Var"))
initialTestFile->m_editorWidget->openLinkUnderCursor();
else
CppEditorPlugin::instance()->switchDeclarationDefinition();
@@ -623,6 +623,126 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data()
"}\n" // Line 10
);
+ QTest::newRow("fromConstructorDeclarationSymbol") << _(
+ "class C\n"
+ "{\n"
+ "public:\n"
+ " C();\n"
+ " int @function();\n" // Line 5
+ "};\n"
+ ) << _(
+ "#include \"file.h\"\n"
+ "\n"
+ "C::C()\n"
+ "{\n"
+ "}\n" // Line 5
+ "\n"
+ "int C::$function()\n"
+ "{\n"
+ " return 1 + 1;\n"
+ "}\n" // Line 10
+ );
+
+ QTest::newRow("fromConstructorDefinitionSymbol") << _(
+ "class C\n"
+ "{\n"
+ "public:\n"
+ " $C();\n"
+ " int function();\n"
+ "};\n"
+ ) << _(
+ "#include \"file.h\"\n"
+ "\n"
+ "C::@C()\n"
+ "{\n"
+ "}\n"
+ "\n"
+ "int C::function()\n"
+ "{\n"
+ " return 1 + 1;\n"
+ "}\n"
+ );
+
+ QTest::newRow("fromConstructorBody") << _(
+ "class C\n"
+ "{\n"
+ "public:\n"
+ " $C();\n"
+ " int function();\n"
+ "};\n"
+ ) << _(
+ "#include \"file.h\"\n"
+ "\n"
+ "C::C()\n"
+ "{@\n"
+ "}\n" // Line 5
+ "\n"
+ "int C::function()\n"
+ "{\n"
+ " return 1 + 1;\n"
+ "}\n" // Line 10
+ );
+
+ QTest::newRow("fromDestructorDeclarationSymbol") << _(
+ "class C\n"
+ "{\n"
+ "public:\n"
+ " @C();\n"
+ " int function();\n" // Line 5
+ "};\n"
+ ) << _(
+ "#include \"file.h\"\n"
+ "\n"
+ "C::$C()\n"
+ "{\n"
+ "}\n" // Line 5
+ "\n"
+ "int C::function()\n"
+ "{\n"
+ " return 1 + 1;\n"
+ "}\n" // Line 10
+ );
+
+ QTest::newRow("fromDestructorDefinitionSymbol") << _(
+ "class C\n"
+ "{\n"
+ "public:\n"
+ " ~$C();\n"
+ " int function();\n"
+ "};\n"
+ ) << _(
+ "#include \"file.h\"\n"
+ "\n"
+ "C::@~C()\n"
+ "{\n"
+ "}\n"
+ "\n"
+ "int C::function()\n"
+ "{\n"
+ " return 1 + 1;\n"
+ "}\n"
+ );
+
+ QTest::newRow("fromDestructorBody") << _(
+ "class C\n"
+ "{\n"
+ "public:\n"
+ " ~$C();\n"
+ " int function();\n"
+ "};\n"
+ ) << _(
+ "#include \"file.h\"\n"
+ "\n"
+ "C::~C()\n"
+ "{@\n"
+ "}\n" // Line 5
+ "\n"
+ "int C::function()\n"
+ "{\n"
+ " return 1 + 1;\n"
+ "}\n" // Line 10
+ );
+
QTest::newRow("fromReturnType") << _(
"class C\n"
"{\n"