1 //===--- SymbolCollector.h ---------------------------------------*- C++-*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLCOLLECTOR_H 9 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLCOLLECTOR_H 10 11 #include "CollectMacros.h" 12 #include "index/CanonicalIncludes.h" 13 #include "index/Ref.h" 14 #include "index/Relation.h" 15 #include "index/Symbol.h" 16 #include "index/SymbolID.h" 17 #include "index/SymbolOrigin.h" 18 #include "clang/AST/ASTContext.h" 19 #include "clang/AST/Decl.h" 20 #include "clang/Basic/SourceLocation.h" 21 #include "clang/Basic/SourceManager.h" 22 #include "clang/Index/IndexDataConsumer.h" 23 #include "clang/Index/IndexSymbol.h" 24 #include "clang/Sema/CodeCompleteConsumer.h" 25 #include "llvm/ADT/ArrayRef.h" 26 #include "llvm/ADT/DenseMap.h" 27 #include <functional> 28 29 namespace clang { 30 namespace clangd { 31 32 /// Collect declarations (symbols) from an AST. 33 /// It collects most declarations except: 34 /// - Implicit declarations 35 /// - Anonymous declarations (anonymous enum/class/struct, etc) 36 /// - Declarations in anonymous namespaces in headers 37 /// - Local declarations (in function bodies, blocks, etc) 38 /// - Template specializations 39 /// - Library-specific private declarations (e.g. private declaration generated 40 /// by protobuf compiler) 41 /// 42 /// References to main-file symbols are not collected. 43 /// 44 /// See also shouldCollectSymbol(...). 45 /// 46 /// Clients (e.g. clangd) can use SymbolCollector together with 47 /// index::indexTopLevelDecls to retrieve all symbols when the source file is 48 /// changed. 49 class SymbolCollector : public index::IndexDataConsumer { 50 public: 51 struct Options { 52 /// When symbol paths cannot be resolved to absolute paths (e.g. files in 53 /// VFS that does not have absolute path), combine the fallback directory 54 /// with symbols' paths to get absolute paths. This must be an absolute 55 /// path. 56 std::string FallbackDir; 57 bool CollectIncludePath = false; 58 /// If set, this is used to map symbol #include path to a potentially 59 /// different #include path. 60 const CanonicalIncludes *Includes = nullptr; 61 // Populate the Symbol.References field. 62 bool CountReferences = false; 63 /// The symbol ref kinds that will be collected. 64 /// If not set, SymbolCollector will not collect refs. 65 /// Note that references of namespace decls are not collected, as they 66 /// contribute large part of the index, and they are less useful compared 67 /// with other decls. 68 RefKind RefFilter = RefKind::Unknown; 69 /// If set to true, SymbolCollector will collect all refs (from main file 70 /// and included headers); otherwise, only refs from main file will be 71 /// collected. 72 /// This flag is only meaningful when RefFilter is set. 73 bool RefsInHeaders = false; 74 // Every symbol collected will be stamped with this origin. 75 SymbolOrigin Origin = SymbolOrigin::Unknown; 76 /// Collect macros. 77 /// Note that SymbolCollector must be run with preprocessor in order to 78 /// collect macros. For example, `indexTopLevelDecls` will not index any 79 /// macro even if this is true. 80 bool CollectMacro = false; 81 /// Collect symbols local to main-files, such as static functions, symbols 82 /// inside an anonymous namespace, function-local classes and its member 83 /// functions. 84 bool CollectMainFileSymbols = true; 85 /// Collect references to main-file symbols. 86 bool CollectMainFileRefs = false; 87 /// Collect symbols with reserved names, like __Vector_base. 88 /// This does not currently affect macros (many like _WIN32 are important!) 89 bool CollectReserved = false; 90 /// If set to true, SymbolCollector will collect doc for all symbols. 91 /// Note that documents of symbols being indexed for completion will always 92 /// be collected regardless of this option. 93 bool StoreAllDocumentation = false; 94 /// If this is set, only collect symbols/references from a file if 95 /// `FileFilter(SM, FID)` is true. If not set, all files are indexed. 96 std::function<bool(const SourceManager &, FileID)> FileFilter = nullptr; 97 }; 98 99 SymbolCollector(Options Opts); 100 ~SymbolCollector(); 101 102 /// Returns true is \p ND should be collected. 103 static bool shouldCollectSymbol(const NamedDecl &ND, const ASTContext &ASTCtx, 104 const Options &Opts, bool IsMainFileSymbol); 105 106 void initialize(ASTContext &Ctx) override; 107 setPreprocessor(std::shared_ptr<Preprocessor> PP)108 void setPreprocessor(std::shared_ptr<Preprocessor> PP) override { 109 this->PP = PP.get(); 110 } setPreprocessor(Preprocessor & PP)111 void setPreprocessor(Preprocessor &PP) { this->PP = &PP; } 112 113 bool 114 handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles, 115 ArrayRef<index::SymbolRelation> Relations, 116 SourceLocation Loc, 117 index::IndexDataConsumer::ASTNodeInfo ASTNode) override; 118 119 bool handleMacroOccurrence(const IdentifierInfo *Name, const MacroInfo *MI, 120 index::SymbolRoleSet Roles, 121 SourceLocation Loc) override; 122 123 void handleMacros(const MainFileMacros &MacroRefsToIndex); 124 takeSymbols()125 SymbolSlab takeSymbols() { return std::move(Symbols).build(); } takeRefs()126 RefSlab takeRefs() { return std::move(Refs).build(); } takeRelations()127 RelationSlab takeRelations() { return std::move(Relations).build(); } 128 129 /// Returns true if we are interested in references and declarations from \p 130 /// FID. If this function return false, bodies of functions inside those files 131 /// will be skipped to decrease indexing time. 132 bool shouldIndexFile(FileID FID); 133 134 void finish() override; 135 136 private: 137 const Symbol *addDeclaration(const NamedDecl &, SymbolID, 138 bool IsMainFileSymbol); 139 void addDefinition(const NamedDecl &, const Symbol &DeclSymbol); 140 void processRelations(const NamedDecl &ND, const SymbolID &ID, 141 ArrayRef<index::SymbolRelation> Relations); 142 143 llvm::Optional<SymbolLocation> getTokenLocation(SourceLocation TokLoc); 144 145 llvm::Optional<std::string> getIncludeHeader(const Symbol &S, FileID); 146 147 SymbolID getSymbolIDCached(const Decl *D); 148 SymbolID getSymbolIDCached(const llvm::StringRef MacroName, 149 const MacroInfo *MI, const SourceManager &SM); 150 151 // All Symbols collected from the AST. 152 SymbolSlab::Builder Symbols; 153 // File IDs for Symbol.IncludeHeaders. 154 // The final spelling is calculated in finish(). 155 llvm::DenseMap<SymbolID, FileID> IncludeFiles; 156 void setIncludeLocation(const Symbol &S, SourceLocation); 157 // Indexed macros, to be erased if they turned out to be include guards. 158 llvm::DenseSet<const IdentifierInfo *> IndexedMacros; 159 // All refs collected from the AST. It includes: 160 // 1) symbols declared in the preamble and referenced from the main file ( 161 // which is not a header), or 162 // 2) symbols declared and referenced from the main file (which is a header) 163 RefSlab::Builder Refs; 164 // All relations collected from the AST. 165 RelationSlab::Builder Relations; 166 ASTContext *ASTCtx; 167 Preprocessor *PP = nullptr; 168 std::shared_ptr<GlobalCodeCompletionAllocator> CompletionAllocator; 169 std::unique_ptr<CodeCompletionTUInfo> CompletionTUInfo; 170 Options Opts; 171 struct SymbolRef { 172 SourceLocation Loc; 173 FileID FID; 174 index::SymbolRoleSet Roles; 175 const Decl *Container; 176 bool Spelled; 177 }; 178 void addRef(SymbolID ID, const SymbolRef &SR); 179 // Symbols referenced from the current TU, flushed on finish(). 180 llvm::DenseSet<SymbolID> ReferencedSymbols; 181 // Maps canonical declaration provided by clang to canonical declaration for 182 // an index symbol, if clangd prefers a different declaration than that 183 // provided by clang. For example, friend declaration might be considered 184 // canonical by clang but should not be considered canonical in the index 185 // unless it's a definition. 186 llvm::DenseMap<const Decl *, const Decl *> CanonicalDecls; 187 // Cache whether to index a file or not. 188 llvm::DenseMap<FileID, bool> FilesToIndexCache; 189 // Encapsulates calculations and caches around header paths, which headers 190 // to insert for which symbol, etc. 191 class HeaderFileURICache; 192 std::unique_ptr<HeaderFileURICache> HeaderFileURIs; 193 llvm::DenseMap<const Decl *, SymbolID> DeclToIDCache; 194 llvm::DenseMap<const MacroInfo *, SymbolID> MacroToIDCache; 195 }; 196 197 } // namespace clangd 198 } // namespace clang 199 200 #endif 201