Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -360,11 +360,11 @@ void ClangdServer::findDefinitions(PathRef File, Position Pos, Callback> CB) { auto FS = FSProvider.getFileSystem(); - auto Action = [Pos, FS](Callback> CB, + auto Action = [Pos, FS, this](Callback> CB, llvm::Expected InpAST) { if (!InpAST) return CB(InpAST.takeError()); - CB(clangd::findDefinitions(InpAST->AST, Pos)); + CB(clangd::findDefinitions(InpAST->AST, Pos, this->FileIdx.get())); }; WorkScheduler.runWithAST("Definitions", File, Bind(Action, std::move(CB))); Index: clangd/XRefs.h =================================================================== --- clangd/XRefs.h +++ clangd/XRefs.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_XREFS_H #include "ClangdUnit.h" +#include "index/Index.h" #include "Protocol.h" #include @@ -21,7 +22,8 @@ namespace clangd { /// Get definition of symbol at a specified \p Pos. -std::vector findDefinitions(ParsedAST &AST, Position Pos); +std::vector findDefinitions(ParsedAST &AST, Position Pos, + const SymbolIndex *const Index = nullptr); /// Returns highlights for all usages of a symbol at \p Pos. std::vector findDocumentHighlights(ParsedAST &AST, Index: clangd/XRefs.cpp =================================================================== --- clangd/XRefs.cpp +++ clangd/XRefs.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/Index/IndexDataConsumer.h" #include "clang/Index/IndexingAction.h" +#include "clang/Index/USRGeneration.h" #include "llvm/Support/Path.h" namespace clang { namespace clangd { @@ -128,6 +129,20 @@ } }; +llvm::Optional +getAbsoluteFilePath(const FileEntry *F, const SourceManager &SourceMgr) { + SmallString<64> FilePath = F->tryGetRealPathName(); + if (FilePath.empty()) + FilePath = F->getName(); + if (!llvm::sys::path::is_absolute(FilePath)) { + if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) { + log("Could not turn relative path to absolute: " + FilePath); + return llvm::None; + } + } + return FilePath.str().str(); +} + llvm::Optional makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) { const SourceManager &SourceMgr = AST.getASTContext().getSourceManager(); @@ -145,24 +160,19 @@ Range R = {Begin, End}; Location L; - SmallString<64> FilePath = F->tryGetRealPathName(); - if (FilePath.empty()) - FilePath = F->getName(); - if (!llvm::sys::path::is_absolute(FilePath)) { - if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) { - log("Could not turn relative path to absolute: " + FilePath); - return llvm::None; - } - } - - L.uri = URIForFile(FilePath.str()); + auto FilePath = getAbsoluteFilePath(F, SourceMgr); + if (!FilePath) + return llvm::None; + L.uri = URIForFile(*FilePath); L.range = R; return L; } } // namespace -std::vector findDefinitions(ParsedAST &AST, Position Pos) { +std::vector +findDefinitions(ParsedAST &AST, Position Pos, + const SymbolIndex *const Index) { const SourceManager &SourceMgr = AST.getASTContext().getSourceManager(); const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); if (!FE) @@ -196,13 +206,61 @@ std::vector Decls = DeclMacrosFinder->takeDecls(); std::vector MacroInfos = DeclMacrosFinder->takeMacroInfos(); + llvm::DenseSet QuerySyms; + llvm::DenseMap ResultCandidates; for (auto D : Decls) { auto Loc = findNameLoc(D); auto L = makeLocation(AST, SourceRange(Loc, Loc)); - if (L) - Result.push_back(*L); + if (!L) { + log("Could not creat location for Loc"); + continue; + } + llvm::SmallString<128> USR; + if (index::generateUSRForDecl(D, USR)) + continue; + auto ID = SymbolID(USR); + ResultCandidates.insert({ID, *L}); + bool IsDef = GetDefinition(D) == D; + // Query the index if there is no definition point in the local AST. + if (!IsDef) + QuerySyms.insert(ID); } + if (Index && !QuerySyms.empty()) { + LookupRequest IndexQuery; + IndexQuery.IDs = QuerySyms; + std::string HintPath; + if (auto Path = getAbsoluteFilePath(FE, SourceMgr)) + HintPath = *Path; + Index->lookup( + IndexQuery, [&HintPath, &ResultCandidates](const Symbol &Sym) { + auto it = ResultCandidates.find(Sym.ID); + assert(it != ResultCandidates.end()); + if (Sym.Definition) { + auto Uri = URI::parse(Sym.Definition.FileURI); + if (!Uri) { + log("Could not parse URI: " + Sym.Definition.FileURI); + return; + } + auto Path = URI::resolve(*Uri, HintPath); + if (!Path) { + log("Could not resolve URI"); + return; + } + Location LSPLoc; + LSPLoc.uri = URIForFile(*Path); + LSPLoc.range.start.line = Sym.Definition.Start.Line; + LSPLoc.range.start.character = Sym.Definition.Start.Column; + LSPLoc.range.end.line = Sym.Definition.End.Line; + LSPLoc.range.end.character = Sym.Definition.End.Column; + it->second = std::move(LSPLoc); + } + }); + } + + for (auto It : ResultCandidates) + Result.push_back(It.second); + for (auto Item : MacroInfos) { auto Loc = Item.Info->getDefinitionLoc(); auto L = makeLocation(AST, SourceRange(Loc, Loc)); Index: unittests/clangd/XRefsTests.cpp =================================================================== --- unittests/clangd/XRefsTests.cpp +++ unittests/clangd/XRefsTests.cpp @@ -106,6 +106,44 @@ MATCHER_P(RangeIs, R, "") { return arg.range == R; } +TEST(GoToDefinition, WithIndex) { + MockFSProvider FS; + IgnoreDiagnostics DiagConsumer; + MockCompilationDatabase CDB; + auto option = ClangdServer::optsForTest(); + option.BuildDynamicSymbolIndex = true; + ClangdServer Server(CDB, FS, DiagConsumer, option); + + const char *DefHeaderSource = "void ff();"; + auto DefCpp = testPath("def.cpp"); + auto DefHeader = testPath("def.h"); + auto TestCpp = testPath("test.cpp"); + Annotations Def(R"cpp( + #include "def.h" + void [[ff]]() {} + )cpp"); + Annotations Test(R"cpp( + #include "def.h" + void f() { + ^ff(); + } + )cpp"); + FS.Files[DefCpp] = Def.code(); + FS.Files[TestCpp] = Test.code(); + FS.Files[DefHeader] = DefHeaderSource; + + runAddDocument(Server, TestCpp, Test.code()); + runAddDocument(Server, DefCpp, Def.code()); + std::vector> ExpectedLocations; + for (const auto &R : Def.ranges()) + ExpectedLocations.push_back(RangeIs(R)); + + auto Locations = runFindDefinitions(Server, TestCpp, Test.point()); + EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error"; + EXPECT_THAT(*Locations, ElementsAreArray(ExpectedLocations)) + << Test.code(); +} + TEST(GoToDefinition, All) { const char *Tests[] = { R"cpp(// Local variable