1 | //===--- Index.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 | |
9 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H |
10 | #define |
11 | |
12 | #include "index/Ref.h" |
13 | #include "index/Relation.h" |
14 | #include "index/Symbol.h" |
15 | #include "index/SymbolID.h" |
16 | #include "llvm/ADT/DenseSet.h" |
17 | #include "llvm/ADT/FunctionExtras.h" |
18 | #include "llvm/Support/JSON.h" |
19 | #include <mutex> |
20 | #include <optional> |
21 | #include <string> |
22 | |
23 | namespace clang { |
24 | namespace clangd { |
25 | |
26 | struct FuzzyFindRequest { |
27 | /// A query string for the fuzzy find. This is matched against symbols' |
28 | /// un-qualified identifiers and should not contain qualifiers like "::". |
29 | std::string Query; |
30 | /// If this is non-empty, symbols must be in at least one of the scopes |
31 | /// (e.g. namespaces) excluding nested scopes. For example, if a scope "xyz::" |
32 | /// is provided, the matched symbols must be defined in namespace xyz but not |
33 | /// namespace xyz::abc. |
34 | /// |
35 | /// The global scope is "", a top level scope is "foo::", etc. |
36 | std::vector<std::string> Scopes; |
37 | /// If set to true, allow symbols from any scope. Scopes explicitly listed |
38 | /// above will be ranked higher. |
39 | bool AnyScope = false; |
40 | /// The number of top candidates to return. The index may choose to |
41 | /// return more than this, e.g. if it doesn't know which candidates are best. |
42 | std::optional<uint32_t> Limit; |
43 | /// If set to true, only symbols for completion support will be considered. |
44 | bool RestrictForCodeCompletion = false; |
45 | /// Contextually relevant files (e.g. the file we're code-completing in). |
46 | /// Paths should be absolute. |
47 | std::vector<std::string> ProximityPaths; |
48 | /// Preferred types of symbols. These are raw representation of `OpaqueType`. |
49 | std::vector<std::string> PreferredTypes; |
50 | |
51 | bool operator==(const FuzzyFindRequest &Req) const { |
52 | return std::tie(args: Query, args: Scopes, args: Limit, args: RestrictForCodeCompletion, |
53 | args: ProximityPaths, args: PreferredTypes) == |
54 | std::tie(args: Req.Query, args: Req.Scopes, args: Req.Limit, |
55 | args: Req.RestrictForCodeCompletion, args: Req.ProximityPaths, |
56 | args: Req.PreferredTypes); |
57 | } |
58 | bool operator!=(const FuzzyFindRequest &Req) const { return !(*this == Req); } |
59 | }; |
60 | bool fromJSON(const llvm::json::Value &Value, FuzzyFindRequest &Request, |
61 | llvm::json::Path); |
62 | llvm::json::Value toJSON(const FuzzyFindRequest &Request); |
63 | |
64 | struct LookupRequest { |
65 | llvm::DenseSet<SymbolID> IDs; |
66 | }; |
67 | |
68 | struct RefsRequest { |
69 | llvm::DenseSet<SymbolID> IDs; |
70 | RefKind Filter = RefKind::All; |
71 | /// If set, limit the number of refers returned from the index. The index may |
72 | /// choose to return less than this, e.g. it tries to avoid returning stale |
73 | /// results. |
74 | std::optional<uint32_t> Limit; |
75 | /// If set, populates the container of the reference. |
76 | /// Index implementations may chose to populate containers no matter what. |
77 | bool WantContainer = false; |
78 | }; |
79 | |
80 | struct RelationsRequest { |
81 | llvm::DenseSet<SymbolID> Subjects; |
82 | RelationKind Predicate; |
83 | /// If set, limit the number of relations returned from the index. |
84 | std::optional<uint32_t> Limit; |
85 | }; |
86 | |
87 | /// Describes what data is covered by an index. |
88 | /// |
89 | /// Indexes may contain symbols but not references from a file, etc. |
90 | /// This affects merging: if a staler index contains a reference but a fresher |
91 | /// one does not, we want to trust the fresher index *only* if it actually |
92 | /// includes references in general. |
93 | enum class IndexContents : uint8_t { |
94 | None = 0, |
95 | Symbols = 1 << 1, |
96 | References = 1 << 2, |
97 | Relations = 1 << 3, |
98 | All = Symbols | References | Relations |
99 | }; |
100 | |
101 | inline constexpr IndexContents operator&(IndexContents L, IndexContents R) { |
102 | return static_cast<IndexContents>(static_cast<uint8_t>(L) & |
103 | static_cast<uint8_t>(R)); |
104 | } |
105 | |
106 | inline constexpr IndexContents operator|(IndexContents L, IndexContents R) { |
107 | return static_cast<IndexContents>(static_cast<uint8_t>(L) | |
108 | static_cast<uint8_t>(R)); |
109 | } |
110 | |
111 | /// Interface for symbol indexes that can be used for searching or |
112 | /// matching symbols among a set of symbols based on names or unique IDs. |
113 | class SymbolIndex { |
114 | public: |
115 | virtual ~SymbolIndex() = default; |
116 | |
117 | /// Matches symbols in the index fuzzily and applies \p Callback on |
118 | /// each matched symbol before returning. |
119 | /// If returned Symbols are used outside Callback, they must be deep-copied! |
120 | /// |
121 | /// Returns true if there may be more results (limited by Req.Limit). |
122 | virtual bool |
123 | fuzzyFind(const FuzzyFindRequest &Req, |
124 | llvm::function_ref<void(const Symbol &)> Callback) const = 0; |
125 | |
126 | /// Looks up symbols with any of the given symbol IDs and applies \p Callback |
127 | /// on each matched symbol. |
128 | /// The returned symbol must be deep-copied if it's used outside Callback. |
129 | virtual void |
130 | lookup(const LookupRequest &Req, |
131 | llvm::function_ref<void(const Symbol &)> Callback) const = 0; |
132 | |
133 | /// Finds all occurrences (e.g. references, declarations, definitions) of |
134 | /// symbols and applies \p Callback on each result. |
135 | /// |
136 | /// Results should be returned in arbitrary order. |
137 | /// The returned result must be deep-copied if it's used outside Callback. |
138 | /// FIXME: there's no indication which result references which symbol. |
139 | /// |
140 | /// Returns true if there will be more results (limited by Req.Limit); |
141 | virtual bool refs(const RefsRequest &Req, |
142 | llvm::function_ref<void(const Ref &)> Callback) const = 0; |
143 | |
144 | /// Finds all relations (S, P, O) stored in the index such that S is among |
145 | /// Req.Subjects and P is Req.Predicate, and invokes \p Callback for (S, O) in |
146 | /// each. |
147 | virtual void relations( |
148 | const RelationsRequest &Req, |
149 | llvm::function_ref<void(const SymbolID &Subject, const Symbol &Object)> |
150 | Callback) const = 0; |
151 | |
152 | /// Returns function which checks if the specified file was used to build this |
153 | /// index or not. The function must only be called while the index is alive. |
154 | using IndexedFiles = |
155 | llvm::unique_function<IndexContents(llvm::StringRef) const>; |
156 | virtual IndexedFiles indexedFiles() const = 0; |
157 | |
158 | /// Returns estimated size of index (in bytes). |
159 | virtual size_t estimateMemoryUsage() const = 0; |
160 | }; |
161 | |
162 | // Delegating implementation of SymbolIndex whose delegate can be swapped out. |
163 | class SwapIndex : public SymbolIndex { |
164 | public: |
165 | // If an index is not provided, reset() must be called. |
166 | SwapIndex(std::unique_ptr<SymbolIndex> Index = nullptr) |
167 | : Index(std::move(Index)) {} |
168 | void reset(std::unique_ptr<SymbolIndex>); |
169 | |
170 | // SymbolIndex methods delegate to the current index, which is kept alive |
171 | // until the call returns (even if reset() is called). |
172 | bool fuzzyFind(const FuzzyFindRequest &, |
173 | llvm::function_ref<void(const Symbol &)>) const override; |
174 | void lookup(const LookupRequest &, |
175 | llvm::function_ref<void(const Symbol &)>) const override; |
176 | bool refs(const RefsRequest &, |
177 | llvm::function_ref<void(const Ref &)>) const override; |
178 | void relations(const RelationsRequest &, |
179 | llvm::function_ref<void(const SymbolID &, const Symbol &)>) |
180 | const override; |
181 | |
182 | llvm::unique_function<IndexContents(llvm::StringRef) const> |
183 | indexedFiles() const override; |
184 | |
185 | size_t estimateMemoryUsage() const override; |
186 | |
187 | private: |
188 | std::shared_ptr<SymbolIndex> snapshot() const; |
189 | mutable std::mutex Mutex; |
190 | std::shared_ptr<SymbolIndex> Index; |
191 | }; |
192 | |
193 | } // namespace clangd |
194 | } // namespace clang |
195 | |
196 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H |
197 | |