hokein created this revision.
hokein added a reviewer: sammccall.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay, ioeric, 
ilya-biryukov.

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).


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D53322

Files:
  clangd/index/IndexAction.cpp
  clangd/index/IndexAction.h
  clangd/index/SymbolCollector.cpp
  clangd/index/SymbolCollector.h
  unittests/clangd/SymbolCollectorTests.cpp

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;
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<clang::FileID, std::string> 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: 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<FrontendAction>
 createStaticIndexingAction(SymbolCollector::Options Opts,
                            std::function<void(SymbolSlab)> 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<CanonicalIncludes>();
   addSystemHeadersMapping(Includes.get());
   Opts.Includes = Includes.get();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to