From: Haojian Wu Date: Wed, 17 Oct 2018 08:38:36 +0000 (+0000) Subject: [clangd] Collect refs from headers. X-Git-Tag: llvmorg-8.0.0-rc1~6368 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7dd4950ea52bdc9f295ea2fcbe7328a018b7dd98;p=platform%2Fupstream%2Fllvm.git [clangd] Collect refs from headers. Summary: Add a flag to SymbolCollector to collect refs fdrom headers. Note that we collect refs from headers in static index, and we don't do it for dynamic index because of the preamble (we skip function body in preamble, collecting it will result incomplete results). Reviewers: sammccall Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits Differential Revision: https://reviews.llvm.org/D53322 llvm-svn: 344678 --- diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp index 2aad948..25d08ff 100644 --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -66,8 +66,10 @@ createStaticIndexingAction(SymbolCollector::Options Opts, Opts.CollectIncludePath = true; Opts.CountReferences = true; Opts.Origin = SymbolOrigin::Static; - if (RefsCallback != nullptr) + if (RefsCallback != nullptr) { Opts.RefFilter = RefKind::All; + Opts.RefsInHeaders = true; + } auto Includes = llvm::make_unique(); addSystemHeadersMapping(Includes.get()); Opts.Includes = Includes.get(); diff --git a/clang-tools-extra/clangd/index/IndexAction.h b/clang-tools-extra/clangd/index/IndexAction.h index 2330afc..64ec3e7 100644 --- a/clang-tools-extra/clangd/index/IndexAction.h +++ b/clang-tools-extra/clangd/index/IndexAction.h @@ -21,9 +21,8 @@ namespace clangd { // 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) +// - all references 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, diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 0d1281e..73728df 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" #include "clang/Index/IndexSymbol.h" @@ -354,7 +355,8 @@ bool SymbolCollector::handleDeclOccurence( return true; if (!shouldCollectSymbol(*ND, *ASTCtx, Opts)) return true; - if (CollectRef && SM.getFileID(SpellingLoc) == SM.getMainFileID()) + if (CollectRef && + (Opts.RefsInHeaders || SM.getFileID(SpellingLoc) == SM.getMainFileID())) DeclRefs[ND].emplace_back(SpellingLoc, Roles); // Don't continue indexing if this is a mere reference. if (IsOnlyRef) @@ -474,26 +476,43 @@ void SymbolCollector::finish() { } const auto &SM = ASTCtx->getSourceManager(); - auto* MainFileEntry = SM.getFileEntryForID(SM.getMainFileID()); + llvm::DenseMap URICache; + auto GetURI = [&](FileID FID) -> llvm::Optional { + auto Found = URICache.find(FID); + if (Found == URICache.end()) { + // 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. + if (auto *FileEntry = SM.getFileEntryForID(FID)) { + auto FileURI = toURI(SM, FileEntry->getName(), Opts); + if (!FileURI) { + log("Failed to create URI for file: {0}\n", FileEntry); + FileURI = ""; // reset to empty as we also want to cache this case. + } + Found = URICache.insert({FID, *FileURI}).first; + } + } + return Found->second; + }; - if (auto MainFileURI = toURI(SM, MainFileEntry->getName(), Opts)) { - std::string MainURI = *MainFileURI; + if (auto MainFileURI = GetURI(SM.getMainFileID())) { for (const auto &It : DeclRefs) { if (auto ID = getSymbolID(It.first)) { for (const auto &LocAndRole : It.second) { - Ref R; - auto Range = - getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts()); - R.Location.Start = Range.first; - R.Location.End = Range.second; - R.Location.FileURI = MainURI; - R.Kind = toRefKind(LocAndRole.second); - Refs.insert(*ID, R); + auto FileID = SM.getFileID(LocAndRole.first); + if (auto FileURI = GetURI(FileID)) { + auto Range = + getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts()); + Ref R; + R.Location.Start = Range.first; + R.Location.End = Range.second; + R.Location.FileURI = *FileURI; + R.Kind = toRefKind(LocAndRole.second); + Refs.insert(*ID, R); + } } } } - } else { - log("Failed to create URI for main file: {0}", MainFileEntry->getName()); } ReferencedDecls.clear(); diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h index 1994183..1148fbb 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.h +++ b/clang-tools-extra/clangd/index/SymbolCollector.h @@ -57,6 +57,11 @@ public: /// 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 all refs (from main file + /// and included headers); otherwise, only refs from main file will be + /// collected. + /// This flag is only meaningful when RefFilter is set. + bool RefsInHeaders = false; // Every symbol collected will be stamped with this origin. SymbolOrigin Origin = SymbolOrigin::Unknown; /// Collect macros. diff --git a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp index 7c18e7e..506d355 100644 --- a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp +++ b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp @@ -479,6 +479,17 @@ TEST_F(SymbolCollectorTest, Refs) { EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "c").ID, _)))); } +TEST_F(SymbolCollectorTest, RefsInHeaders) { + CollectorOpts.RefFilter = RefKind::All; + CollectorOpts.RefsInHeaders = true; + 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;