diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -213,8 +213,12 @@ URIForFile uri; Range range; + /// clangd extension: If this a reference, name of the function in which the + /// reference occurs + std::string container; + friend bool operator==(const Location &LHS, const Location &RHS) { - return LHS.uri == RHS.uri && LHS.range == RHS.range; + return LHS.uri == RHS.uri && LHS.range == RHS.range && LHS.container == RHS.container; } friend bool operator!=(const Location &LHS, const Location &RHS) { @@ -222,7 +226,7 @@ } friend bool operator<(const Location &LHS, const Location &RHS) { - return std::tie(LHS.uri, LHS.range) < std::tie(RHS.uri, RHS.range); + return std::tie(LHS.uri, LHS.range, LHS.container) < std::tie(RHS.uri, RHS.range, RHS.container); } }; llvm::json::Value toJSON(const Location &); diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -154,11 +154,12 @@ return llvm::json::Object{ {"uri", P.uri}, {"range", P.range}, + {"container", P.container}, }; } llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) { - return OS << L.range << '@' << L.uri; + return OS << L.range << '@' << L.uri << "(inside " << L.container << ")"; } bool fromJSON(const llvm::json::Value &Params, TextDocumentItem &R, diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -235,7 +235,7 @@ LocatedSymbol File; File.Name = std::string(llvm::sys::path::filename(Inc.Resolved)); File.PreferredDeclaration = { - URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}}; + URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}, ""}; File.Definition = File.PreferredDeclaration; // We're not going to find any further symbols on #include lines. return File; @@ -859,6 +859,7 @@ syntax::Token SpelledTok; index::SymbolRoleSet Role; SymbolID Target; + const DeclContext *Context; Range range(const SourceManager &SM) const { return halfOpenToRange(SM, SpelledTok.range(SM).toCharRange(SM)); @@ -927,7 +928,8 @@ for (SourceLocation L : Locs) { L = SM.getFileLoc(L); if (const auto *Tok = TB.spelledTokenAt(L)) - References.push_back({*Tok, Roles, DeclID->getSecond()}); + References.push_back( + {*Tok, Roles, DeclID->getSecond(), ASTNode.ContainerDC}); } return true; } @@ -1394,6 +1396,8 @@ ReferencesResult::Reference Result; Result.Loc.range = Ref.range(SM); Result.Loc.uri = URIMainFile; + if (const auto *ND = llvm::dyn_cast(Ref.Context)) + Result.Loc.container = ND->getQualifiedNameAsString(); if (Ref.Role & static_cast(index::SymbolRole::Declaration)) Result.Attributes |= ReferencesResult::Declaration; // clang-index doesn't report definitions as declarations, but they are. @@ -1448,6 +1452,8 @@ Req.Limit = Limit - Results.References.size(); } } + LookupRequest ContainerLookup; + llvm::DenseMap RefIndexForContainer; Results.HasMore |= Index->refs(Req, [&](const Ref &R) { auto LSPLoc = toLSPLocation(R.Location, MainFilePath); // Avoid indexed results for the main file - the AST is authoritative. @@ -1464,7 +1470,18 @@ Result.Attributes |= ReferencesResult::Declaration | ReferencesResult::Definition; } + SymbolID Container = R.Container; + ContainerLookup.IDs.insert(Container); Results.References.push_back(std::move(Result)); + RefIndexForContainer[Container] = Results.References.size() - 1; + }); + + Index->lookup(ContainerLookup, [&](const Symbol &Container) { + auto Ref = RefIndexForContainer.find(Container.ID); + assert(Ref != RefIndexForContainer.end()); + Results.References[Ref->getSecond()].Loc.container = + Container.Scope.str() + Container.Name.str() + + Container.Signature.str(); }); }; QueryIndex(std::move(IDsToQuery), /*AllowAttributes=*/true,