Index: clangd/index/IndexAction.h =================================================================== --- clangd/index/IndexAction.h +++ clangd/index/IndexAction.h @@ -21,9 +21,9 @@ // Only a subset of SymbolCollector::Options are respected: // - include paths are always collected, and canonicalized appropriately // - references are always counted -// - main-file refs are collected (if RefsCallback is non-null) +// - refs in main file and #included headers are collected (if RefsCallback +// is non-null) // - the symbol origin is always Static -// FIXME: refs from headers should also be collected. std::unique_ptr createStaticIndexingAction(SymbolCollector::Options Opts, std::function SymbolsCallback, Index: clangd/index/IndexAction.cpp =================================================================== --- clangd/index/IndexAction.cpp +++ clangd/index/IndexAction.cpp @@ -66,8 +66,10 @@ Opts.CollectIncludePath = true; Opts.CountReferences = true; Opts.Origin = SymbolOrigin::Static; - if (RefsCallback != nullptr) + if (RefsCallback != nullptr) { Opts.RefFilter = RefKind::All; + Opts.RefMainFileOnly = false; // collect refs for #included headers. + } auto Includes = llvm::make_unique(); addSystemHeadersMapping(Includes.get()); Opts.Includes = Includes.get(); Index: clangd/index/SymbolCollector.h =================================================================== --- clangd/index/SymbolCollector.h +++ clangd/index/SymbolCollector.h @@ -57,6 +57,10 @@ /// The symbol ref kinds that will be collected. /// If not set, SymbolCollector will not collect refs. RefKind RefFilter = RefKind::Unknown; + /// If set to true, SymbolCollector will collect refs from main file only; + /// otherwise, refs from headers included by main file will be collected. + /// This flag is only available when RefFilter is set. + bool RefMainFileOnly = true; // Every symbol collected will be stamped with this origin. SymbolOrigin Origin = SymbolOrigin::Unknown; /// Collect macros. Index: clangd/index/SymbolCollector.cpp =================================================================== --- clangd/index/SymbolCollector.cpp +++ clangd/index/SymbolCollector.cpp @@ -354,7 +354,8 @@ return true; if (!shouldCollectSymbol(*ND, *ASTCtx, Opts)) return true; - if (CollectRef && SM.getFileID(SpellingLoc) == SM.getMainFileID()) + if (CollectRef && + (!Opts.RefMainFileOnly || SM.getFileID(SpellingLoc) == SM.getMainFileID())) DeclRefs[ND].emplace_back(SpellingLoc, Roles); // Don't continue indexing if this is a mere reference. if (IsOnlyRef) @@ -476,17 +477,35 @@ const auto &SM = ASTCtx->getSourceManager(); auto* MainFileEntry = SM.getFileEntryForID(SM.getMainFileID()); + llvm::DenseMap URICache; if (auto MainFileURI = toURI(SM, MainFileEntry->getName(), Opts)) { - std::string MainURI = *MainFileURI; + URICache.insert({SM.getMainFileID(), *MainFileURI}); for (const auto &It : DeclRefs) { if (auto ID = getSymbolID(It.first)) { for (const auto &LocAndRole : It.second) { - Ref R; + auto FileID = SM.getFileID(LocAndRole.first); + auto Found = URICache.find(FileID); + if (Found == URICache.end()) { + if (auto* FileEntry = SM.getFileEntryForID(FileID)) { + auto FileURI = toURI(SM, FileEntry->getName(), Opts); + if (!FileURI) { + log("Failed to create URI for file: {0}\n", FileEntry); + continue; + } + Found = URICache.insert({FileID, *FileURI}).first; + } else { + // Ignore cases where we can not find a corresponding file entry + // for the loc, thoses are not interesting, e.g. symbols formed + // via macro concatenation. + continue; + } + } auto Range = getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts()); + Ref R; R.Location.Start = Range.first; R.Location.End = Range.second; - R.Location.FileURI = MainURI; + R.Location.FileURI = Found->second; R.Kind = toRefKind(LocAndRole.second); Refs.insert(*ID, R); } Index: unittests/clangd/SymbolCollectorTests.cpp =================================================================== --- unittests/clangd/SymbolCollectorTests.cpp +++ unittests/clangd/SymbolCollectorTests.cpp @@ -479,6 +479,17 @@ EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "c").ID, _)))); } +TEST_F(SymbolCollectorTest, RefsInHeaders) { + CollectorOpts.RefFilter = RefKind::All; + CollectorOpts.RefMainFileOnly = false; + Annotations Header(R"( + class [[Foo]] {}; + )"); + runSymbolCollector(Header.code(), ""); + EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID, + HaveRanges(Header.ranges())))); +} + TEST_F(SymbolCollectorTest, References) { const std::string Header = R"( class W;