diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2021-05-31 15:57:44 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2021-06-18 11:11:17 +0000 |
commit | 41dafc8132ead035b4c02e6f7332ed35fc8dcbc7 (patch) | |
tree | 4be977d002165bd3debadde4866baa5c4f1337a9 /src/plugins/cppeditor | |
parent | de6c7696d2ce8f3424146ebe0b6cf172361b9b87 (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.cpp | 81 | ||||
-rw-r--r-- | src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp | 132 |
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" |