usaxena95 created this revision. Herald added subscribers: cfe-commits, kadircet, arphaman. Herald added a project: clang. usaxena95 requested review of this revision. Herald added subscribers: MaskRay, ilya-biryukov.
Implements textdocument/implementation (https://microsoft.github.io/language-server-protocol/specification#textDocument_implementation) There is no clear semantic in LSP, but VSCode has some documentation about the behaviour: "For an interface, this shows all the implementors of that interface and for abstract methods, this shows all concrete implementations of that method." This currently shows all concrete methods that overrides a virtual function. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D91702 Files: clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/XRefs.h clang-tools-extra/clangd/unittests/XRefsTests.cpp
Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -43,6 +43,7 @@ using ::testing::Matcher; using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAreArray; +using ::testing::UnorderedPointwise; MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; @@ -1161,12 +1162,12 @@ )cpp", }; - for (const auto* Case : Tests) { + for (const auto *Case : Tests) { SCOPED_TRACE(Case); auto T = Annotations(Case); auto AST = TestTU::withCode(T.code()).build(); EXPECT_THAT(locateSymbolAt(AST, T.point()), - ::testing::UnorderedPointwise(DeclRange(), T.ranges())); + UnorderedPointwise(DeclRange(), T.ranges())); } } @@ -1464,6 +1465,64 @@ } } +TEST(FindImplementations, Inheritance) { + llvm::StringRef Test = R"cpp( + struct Base { + virtual void F$1^oo(); + }; + struct Child1 : Base { + void $1[[Fo$3^o]]() override; + virtual void B$2^ar(); + }; + struct Child2 : Child1 { + void $3[[Foo]]() override; + void $2[[Bar]]() override; + }; + void FromReference() { + Base* B; + B->Fo$1^o(); + &Base::Fo$1^o; + Child1 * C1; + C1->B$2^ar(); + C1->Fo$3^o(); + } + )cpp"; + + Annotations Code(Test); + auto TU = TestTU::withCode(Code.code()); + auto AST = TU.build(); + for (const std::string &Label : {"1", "2", "3"}) { + for (const auto &Point : Code.points(Label)) { + EXPECT_THAT(findImplementations(AST, Point, TU.index().get()), + UnorderedPointwise(DeclRange(), Code.ranges(Label))) + << Code.code() << " at " << Point << " for Label " << Label; + } + } +} + +TEST(FindImplementations, CaptureDefintion) { + llvm::StringRef Test = R"cpp( + struct Base { + virtual void F^oo(); + }; + struct Child1 : Base { + void $Decl[[Foo]]() override; + }; + struct Child2 : Base { + void $Child2[[Foo]]() override; + }; + void Child1::$Def[[Foo]]() { /* Definition */ } + )cpp"; + Annotations Code(Test); + auto TU = TestTU::withCode(Code.code()); + auto AST = TU.build(); + EXPECT_THAT(findImplementations(AST, Code.point(), TU.index().get()), + UnorderedElementsAre( + Sym("Foo", Code.range("Decl"), Code.range("Def")), + Sym("Foo", Code.range("Child2"), Code.range("Child2")))) + << Test; +} + TEST(FindReferences, WithinAST) { const char *Tests[] = { R"cpp(// Local variable Index: clang-tools-extra/clangd/XRefs.h =================================================================== --- clang-tools-extra/clangd/XRefs.h +++ clang-tools-extra/clangd/XRefs.h @@ -82,6 +82,11 @@ std::vector<Location> References; bool HasMore = false; }; + +/// Returns implementations of the virtual function at a specified \p Pos. +std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos, + const SymbolIndex *Index); + /// Returns references of the symbol at a specified \p Pos. /// \p Limit limits the number of results returned (0 means no limit). ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, Index: clang-tools-extra/clangd/XRefs.cpp =================================================================== --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -1124,6 +1124,46 @@ return Result; } +std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos, + const SymbolIndex *Index) { + std::vector<LocatedSymbol> Results; + // We rely on index to find the implementations in subclasses. + if (!Index) + return Results; + const SourceManager &SM = AST.getSourceManager(); + auto MainFilePath = + getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM); + if (!MainFilePath) { + elog("Failed to get a path for the main file, so no implementations."); + return Results; + } + auto CurLoc = sourceLocationInMainFile(SM, Pos); + + DeclRelationSet Relations = + DeclRelation::TemplatePattern | DeclRelation::Alias; + RelationsRequest Req; + Req.Predicate = RelationKind::OverriddenBy; + for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) + if (const CXXMethodDecl *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) + if (CXXMD->isVirtual()) + Req.Subjects.insert(getSymbolID(ND)); + + if (Req.Subjects.empty()) + return Results; + Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) { + if (auto DeclLoc = + indexToLSPLocation(Object.CanonicalDeclaration, *MainFilePath)) { + LocatedSymbol Loc; + Loc.Name = Object.Name.str(); + Loc.PreferredDeclaration = *DeclLoc; + auto DefLoc = indexToLSPLocation(Object.Definition, *MainFilePath); + Loc.Definition = DefLoc ? *DefLoc : *DeclLoc; + Results.push_back(Loc); + } + }); + return Results; +} + ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index) { if (!Limit)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits