Line data Source code
1 : //===--- SymbolCollector.h ---------------------------------------*- C++-*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_COLLECTOR_H
10 : #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_COLLECTOR_H
11 :
12 : #include "CanonicalIncludes.h"
13 : #include "Index.h"
14 : #include "clang/AST/ASTContext.h"
15 : #include "clang/AST/Decl.h"
16 : #include "clang/Index/IndexDataConsumer.h"
17 : #include "clang/Index/IndexSymbol.h"
18 : #include "clang/Sema/CodeCompleteConsumer.h"
19 :
20 : namespace clang {
21 : namespace clangd {
22 :
23 : /// \brief Collect declarations (symbols) from an AST.
24 : /// It collects most declarations except:
25 : /// - Implicit declarations
26 : /// - Anonymous declarations (anonymous enum/class/struct, etc)
27 : /// - Declarations in anonymous namespaces
28 : /// - Local declarations (in function bodies, blocks, etc)
29 : /// - Declarations in main files
30 : /// - Template specializations
31 : /// - Library-specific private declarations (e.g. private declaration generated
32 : /// by protobuf compiler)
33 : ///
34 : /// See also shouldCollectSymbol(...).
35 : ///
36 : /// Clients (e.g. clangd) can use SymbolCollector together with
37 : /// index::indexTopLevelDecls to retrieve all symbols when the source file is
38 : /// changed.
39 : class SymbolCollector : public index::IndexDataConsumer {
40 : public:
41 : struct Options {
42 : /// When symbol paths cannot be resolved to absolute paths (e.g. files in
43 : /// VFS that does not have absolute path), combine the fallback directory
44 : /// with symbols' paths to get absolute paths. This must be an absolute
45 : /// path.
46 : std::string FallbackDir;
47 : /// Specifies URI schemes that can be used to generate URIs for file paths
48 : /// in symbols. The list of schemes will be tried in order until a working
49 : /// scheme is found. If no scheme works, symbol location will be dropped.
50 : std::vector<std::string> URISchemes = {"file"};
51 : bool CollectIncludePath = false;
52 : /// If set, this is used to map symbol #include path to a potentially
53 : /// different #include path.
54 : const CanonicalIncludes *Includes = nullptr;
55 : // Populate the Symbol.References field.
56 : bool CountReferences = false;
57 : /// The symbol ref kinds that will be collected.
58 : /// If not set, SymbolCollector will not collect refs.
59 : RefKind RefFilter = RefKind::Unknown;
60 : /// If set to true, SymbolCollector will collect all refs (from main file
61 : /// and included headers); otherwise, only refs from main file will be
62 : /// collected.
63 : /// This flag is only meaningful when RefFilter is set.
64 : bool RefsInHeaders = false;
65 : // Every symbol collected will be stamped with this origin.
66 : SymbolOrigin Origin = SymbolOrigin::Unknown;
67 : /// Collect macros.
68 : /// Note that SymbolCollector must be run with preprocessor in order to
69 : /// collect macros. For example, `indexTopLevelDecls` will not index any
70 : /// macro even if this is true.
71 : bool CollectMacro = false;
72 : };
73 :
74 : SymbolCollector(Options Opts);
75 :
76 : /// Returns true is \p ND should be collected.
77 : /// AST matchers require non-const ASTContext.
78 : static bool shouldCollectSymbol(const NamedDecl &ND, ASTContext &ASTCtx,
79 : const Options &Opts);
80 :
81 : void initialize(ASTContext &Ctx) override;
82 :
83 0 : void setPreprocessor(std::shared_ptr<Preprocessor> PP) override {
84 : this->PP = std::move(PP);
85 0 : }
86 :
87 : bool
88 : handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
89 : ArrayRef<index::SymbolRelation> Relations,
90 : SourceLocation Loc,
91 : index::IndexDataConsumer::ASTNodeInfo ASTNode) override;
92 :
93 : bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI,
94 : index::SymbolRoleSet Roles,
95 : SourceLocation Loc) override;
96 :
97 0 : SymbolSlab takeSymbols() { return std::move(Symbols).build(); }
98 0 : RefSlab takeRefs() { return std::move(Refs).build(); }
99 :
100 : void finish() override;
101 :
102 : private:
103 : const Symbol *addDeclaration(const NamedDecl &, SymbolID);
104 : void addDefinition(const NamedDecl &, const Symbol &DeclSymbol);
105 :
106 : // All Symbols collected from the AST.
107 : SymbolSlab::Builder Symbols;
108 : // All refs collected from the AST.
109 : // Only symbols declared in preamble (from #include) and referenced from the
110 : // main file will be included.
111 : RefSlab::Builder Refs;
112 : ASTContext *ASTCtx;
113 : std::shared_ptr<Preprocessor> PP;
114 : std::shared_ptr<GlobalCodeCompletionAllocator> CompletionAllocator;
115 : std::unique_ptr<CodeCompletionTUInfo> CompletionTUInfo;
116 : Options Opts;
117 : using DeclRef = std::pair<SourceLocation, index::SymbolRoleSet>;
118 : // Symbols referenced from the current TU, flushed on finish().
119 : llvm::DenseSet<const NamedDecl *> ReferencedDecls;
120 : llvm::DenseSet<const IdentifierInfo *> ReferencedMacros;
121 : llvm::DenseMap<const NamedDecl *, std::vector<DeclRef>> DeclRefs;
122 : // Maps canonical declaration provided by clang to canonical declaration for
123 : // an index symbol, if clangd prefers a different declaration than that
124 : // provided by clang. For example, friend declaration might be considered
125 : // canonical by clang but should not be considered canonical in the index
126 : // unless it's a definition.
127 : llvm::DenseMap<const Decl *, const Decl *> CanonicalDecls;
128 : };
129 :
130 : } // namespace clangd
131 : } // namespace clang
132 : #endif
|