[clang-tools-extra] r336553 - [clangd] Support indexing MACROs.

Eric Liu via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 9 08:31:07 PDT 2018


Author: ioeric
Date: Mon Jul  9 08:31:07 2018
New Revision: 336553

URL: http://llvm.org/viewvc/llvm-project?rev=336553&view=rev
Log:
[clangd] Support indexing MACROs.

Summary: This is not enabled in the global-symbol-builder or dynamic index yet.

Reviewers: sammccall

Reviewed By: sammccall

Subscribers: ilya-biryukov, MaskRay, jkorous, cfe-commits

Differential Revision: https://reviews.llvm.org/D49028

Modified:
    clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
    clang-tools-extra/trunk/clangd/index/SymbolCollector.h
    clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp

Modified: clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp?rev=336553&r1=336552&r2=336553&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp (original)
+++ clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp Mon Jul  9 08:31:07 2018
@@ -183,22 +183,19 @@ getIncludeHeader(llvm::StringRef QName,
   return toURI(SM, Header, Opts);
 }
 
-// Return the symbol location of the given declaration `D`.
-//
-// For symbols defined inside macros:
-//   * use expansion location, if the symbol is formed via macro concatenation.
-//   * use spelling location, otherwise.
-llvm::Optional<SymbolLocation> getSymbolLocation(
-    const NamedDecl &D, SourceManager &SM, const SymbolCollector::Options &Opts,
-    const clang::LangOptions &LangOpts, std::string &FileURIStorage) {
-  SourceLocation NameLoc = findNameLoc(&D);
-  auto U = toURI(SM, SM.getFilename(NameLoc), Opts);
+// Return the symbol location of the token at \p Loc.
+llvm::Optional<SymbolLocation>
+getTokenLocation(SourceLocation TokLoc, const SourceManager &SM,
+                 const SymbolCollector::Options &Opts,
+                 const clang::LangOptions &LangOpts,
+                 std::string &FileURIStorage) {
+  auto U = toURI(SM, SM.getFilename(TokLoc), Opts);
   if (!U)
     return llvm::None;
   FileURIStorage = std::move(*U);
   SymbolLocation Result;
   Result.FileURI = FileURIStorage;
-  auto TokenLength = clang::Lexer::MeasureTokenLength(NameLoc, SM, LangOpts);
+  auto TokenLength = clang::Lexer::MeasureTokenLength(TokLoc, SM, LangOpts);
 
   auto CreatePosition = [&SM](SourceLocation Loc) {
     auto LSPLoc = sourceLocToPosition(SM, Loc);
@@ -208,8 +205,8 @@ llvm::Optional<SymbolLocation> getSymbol
     return Pos;
   };
 
-  Result.Start = CreatePosition(NameLoc);
-  auto EndLoc = NameLoc.getLocWithOffset(TokenLength);
+  Result.Start = CreatePosition(TokLoc);
+  auto EndLoc = TokLoc.getLocWithOffset(TokenLength);
   Result.End = CreatePosition(EndLoc);
 
   return std::move(Result);
@@ -345,18 +342,106 @@ bool SymbolCollector::handleDeclOccurenc
   return true;
 }
 
+bool SymbolCollector::handleMacroOccurence(const IdentifierInfo *Name,
+                                           const MacroInfo *MI,
+                                           index::SymbolRoleSet Roles,
+                                           SourceLocation Loc) {
+  if (!Opts.CollectMacro)
+    return true;
+  assert(PP.get());
+
+  const auto &SM = PP->getSourceManager();
+  if (SM.isInMainFile(SM.getExpansionLoc(MI->getDefinitionLoc())))
+    return true;
+  // Header guards are not interesting in index. Builtin macros don't have
+  // useful locations and are not needed for code completions.
+  if (MI->isUsedForHeaderGuard() || MI->isBuiltinMacro())
+    return true;
+
+  // Mark the macro as referenced if this is a reference coming from the main
+  // file. The macro may not be an interesting symbol, but it's cheaper to check
+  // at the end.
+  if (Opts.CountReferences &&
+      (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
+      SM.getFileID(SM.getSpellingLoc(Loc)) == SM.getMainFileID())
+    ReferencedMacros.insert(Name);
+  // Don't continue indexing if this is a mere reference.
+  // FIXME: remove macro with ID if it is undefined.
+  if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
+        Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
+    return true;
+
+
+  llvm::SmallString<128> USR;
+  if (index::generateUSRForMacro(Name->getName(), MI->getDefinitionLoc(), SM,
+                                 USR))
+    return true;
+  SymbolID ID(USR);
+
+  // Only collect one instance in case there are multiple.
+  if (Symbols.find(ID) != nullptr)
+    return true;
+
+  Symbol S;
+  S.ID = std::move(ID);
+  S.Name = Name->getName();
+  S.IsIndexedForCodeCompletion = true;
+  S.SymInfo = index::getSymbolInfoForMacro(*MI);
+  std::string FileURI;
+  if (auto DeclLoc = getTokenLocation(MI->getDefinitionLoc(), SM, Opts,
+                                      PP->getLangOpts(), FileURI))
+    S.CanonicalDeclaration = *DeclLoc;
+
+  CodeCompletionResult SymbolCompletion(Name);
+  const auto *CCS = SymbolCompletion.CreateCodeCompletionStringForMacro(
+      *PP, *CompletionAllocator, *CompletionTUInfo);
+  std::string Signature;
+  std::string SnippetSuffix;
+  getSignature(*CCS, &Signature, &SnippetSuffix);
+
+  std::string Include;
+  if (Opts.CollectIncludePath && shouldCollectIncludePath(S.SymInfo.Kind)) {
+    if (auto Header =
+            getIncludeHeader(Name->getName(), SM,
+                             SM.getExpansionLoc(MI->getDefinitionLoc()), Opts))
+      Include = std::move(*Header);
+  }
+  S.Signature = Signature;
+  S.CompletionSnippetSuffix = SnippetSuffix;
+  Symbol::Details Detail;
+  Detail.IncludeHeader = Include;
+  S.Detail = &Detail;
+  Symbols.insert(S);
+  return true;
+}
+
 void SymbolCollector::finish() {
-  // At the end of the TU, add 1 to the refcount of the ReferencedDecls.
-  for (const auto *ND : ReferencedDecls) {
+  // At the end of the TU, add 1 to the refcount of all referenced symbols.
+  auto IncRef = [this](const SymbolID &ID) {
+    if (const auto *S = Symbols.find(ID)) {
+      Symbol Inc = *S;
+      ++Inc.References;
+      Symbols.insert(Inc);
+    }
+  };
+  for (const NamedDecl *ND : ReferencedDecls) {
     llvm::SmallString<128> USR;
     if (!index::generateUSRForDecl(ND, USR))
-      if (const auto *S = Symbols.find(SymbolID(USR))) {
-        Symbol Inc = *S;
-        ++Inc.References;
-        Symbols.insert(Inc);
-      }
+      IncRef(SymbolID(USR));
+  }
+  if (Opts.CollectMacro) {
+    assert(PP);
+    for (const IdentifierInfo *II : ReferencedMacros) {
+      llvm::SmallString<128> USR;
+      if (!index::generateUSRForMacro(
+              II->getName(),
+              PP->getMacroDefinition(II).getMacroInfo()->getDefinitionLoc(),
+              PP->getSourceManager(), USR))
+        IncRef(SymbolID(USR));
+    }
   }
   ReferencedDecls.clear();
+  ReferencedMacros.clear();
 }
 
 const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND,
@@ -374,8 +459,8 @@ const Symbol *SymbolCollector::addDeclar
   S.IsIndexedForCodeCompletion = isIndexedForCodeCompletion(ND, Ctx);
   S.SymInfo = index::getSymbolInfo(&ND);
   std::string FileURI;
-  if (auto DeclLoc =
-          getSymbolLocation(ND, SM, Opts, ASTCtx->getLangOpts(), FileURI))
+  if (auto DeclLoc = getTokenLocation(findNameLoc(&ND), SM, Opts,
+                                      ASTCtx->getLangOpts(), FileURI))
     S.CanonicalDeclaration = *DeclLoc;
 
   // Add completion info.
@@ -425,8 +510,9 @@ void SymbolCollector::addDefinition(cons
   // in clang::index. We should only see one definition.
   Symbol S = DeclSym;
   std::string FileURI;
-  if (auto DefLoc = getSymbolLocation(ND, ND.getASTContext().getSourceManager(),
-                                      Opts, ASTCtx->getLangOpts(), FileURI))
+  if (auto DefLoc = getTokenLocation(findNameLoc(&ND),
+                                     ND.getASTContext().getSourceManager(),
+                                     Opts, ASTCtx->getLangOpts(), FileURI))
     S.Definition = *DefLoc;
   Symbols.insert(S);
 }

Modified: clang-tools-extra/trunk/clangd/index/SymbolCollector.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/index/SymbolCollector.h?rev=336553&r1=336552&r2=336553&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/index/SymbolCollector.h (original)
+++ clang-tools-extra/trunk/clangd/index/SymbolCollector.h Mon Jul  9 08:31:07 2018
@@ -54,6 +54,11 @@ public:
     bool CountReferences = false;
     // Every symbol collected will be stamped with this origin.
     SymbolOrigin Origin = SymbolOrigin::Unknown;
+    /// Collect macros.
+    /// Note that SymbolCollector must be run with preprocessor in order to
+    /// collect macros. For example, `indexTopLevelDecls` will not index any
+    /// macro even if this is true.
+    bool CollectMacro = false;
   };
 
   SymbolCollector(Options Opts);
@@ -75,6 +80,10 @@ public:
                       SourceLocation Loc,
                       index::IndexDataConsumer::ASTNodeInfo ASTNode) override;
 
+  bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI,
+                            index::SymbolRoleSet Roles,
+                            SourceLocation Loc) override;
+
   SymbolSlab takeSymbols() { return std::move(Symbols).build(); }
 
   void finish() override;
@@ -90,8 +99,9 @@ private:
   std::shared_ptr<GlobalCodeCompletionAllocator> CompletionAllocator;
   std::unique_ptr<CodeCompletionTUInfo> CompletionTUInfo;
   Options Opts;
-  // Decls referenced from the current TU, flushed on finish().
+  // Symbols referenced from the current TU, flushed on finish().
   llvm::DenseSet<const NamedDecl *> ReferencedDecls;
+  llvm::DenseSet<const IdentifierInfo *> ReferencedMacros;
   // Maps canonical declaration provided by clang to canonical declaration for
   // an index symbol, if clangd prefers a different declaration than that
   // provided by clang. For example, friend declaration might be considered

Modified: clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp?rev=336553&r1=336552&r2=336553&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp Mon Jul  9 08:31:07 2018
@@ -992,6 +992,32 @@ TEST_F(SymbolCollectorTest, Origin) {
                            Field(&Symbol::Origin, SymbolOrigin::Static)));
 }
 
+TEST_F(SymbolCollectorTest, CollectMacros) {
+  CollectorOpts.CollectIncludePath = true;
+  Annotations Header(R"(
+    #define X 1
+    #define $mac[[MAC]](x) int x
+    #define $used[[USED]](y) float y;
+
+    MAC(p);
+  )");
+  const std::string Main = R"(
+    #define MAIN 1  // not indexed
+    USED(t);
+  )";
+  CollectorOpts.CountReferences = true;
+  CollectorOpts.CollectMacro = true;
+  runSymbolCollector(Header.code(), Main);
+  EXPECT_THAT(
+      Symbols,
+      UnorderedElementsAre(
+          QName("p"),
+          AllOf(QName("X"), DeclURI(TestHeaderURI),
+                IncludeHeader(TestHeaderURI)),
+          AllOf(Labeled("MAC(x)"), Refs(0), DeclRange(Header.range("mac"))),
+          AllOf(Labeled("USED(y)"), Refs(1), DeclRange(Header.range("used")))));
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang




More information about the cfe-commits mailing list