return Result;
}
+std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos,
+ const SymbolIndex *Index) {
+ // We rely on index to find the implementations in subclasses.
+ // FIXME: Index can be stale, so we may loose some latest results from the
+ // main file.
+ if (!Index)
+ return {};
+ 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 {};
+ }
+ auto CurLoc = sourceLocationInMainFile(SM, Pos);
+ if (!CurLoc) {
+ elog("Failed to convert position to source location: {0}",
+ CurLoc.takeError());
+ return {};
+ }
+ std::vector<LocatedSymbol> Results;
+ 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;
+ if (auto DefLoc = indexToLSPLocation(Object.Definition, *MainFilePath))
+ Loc.Definition = *DefLoc;
+ Results.push_back(Loc);
+ }
+ });
+ return Results;
+}
+
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
const SymbolIndex *Index) {
if (!Limit)
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,
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;
)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()));
}
}
}
}
+TEST(FindImplementations, Inheritance) {
+ llvm::StringRef Test = R"cpp(
+ struct Base {
+ virtual void F$1^oo();
+ void C$4^oncrete();
+ };
+ struct Child1 : Base {
+ void $1[[Fo$3^o]]() override;
+ virtual void B$2^ar();
+ void Concrete(); // No implementations for concrete methods.
+ };
+ struct Child2 : Child1 {
+ void $3[[Foo]]() override;
+ void $2[[Bar]]() override;
+ };
+ void FromReference() {
+ Base* B;
+ B->Fo$1^o();
+ B->C$4^oncrete();
+ &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", "4"}) {
+ 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"), llvm::None)))
+ << Test;
+}
+
TEST(FindReferences, WithinAST) {
const char *Tests[] = {
R"cpp(// Local variable