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 LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
11 
12 #include "Ref.h"
13 #include "Relation.h"
14 #include "Symbol.h"
15 #include "SymbolID.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/Support/JSON.h"
20 #include <mutex>
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   llvm::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(Query, Scopes, Limit, RestrictForCodeCompletion,
53                     ProximityPaths, PreferredTypes) ==
54            std::tie(Req.Query, Req.Scopes, Req.Limit,
55                     Req.RestrictForCodeCompletion, Req.ProximityPaths,
56                     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::Value toJSON(const FuzzyFindRequest &Request);
62 
63 struct LookupRequest {
64   llvm::DenseSet<SymbolID> IDs;
65 };
66 
67 struct RefsRequest {
68   llvm::DenseSet<SymbolID> IDs;
69   RefKind Filter = RefKind::All;
70   /// If set, limit the number of refers returned from the index. The index may
71   /// choose to return less than this, e.g. it tries to avoid returning stale
72   /// results.
73   llvm::Optional<uint32_t> Limit;
74 };
75 
76 struct RelationsRequest {
77   llvm::DenseSet<SymbolID> Subjects;
78   RelationKind Predicate;
79   /// If set, limit the number of relations returned from the index.
80   llvm::Optional<uint32_t> Limit;
81 };
82 
83 /// Interface for symbol indexes that can be used for searching or
84 /// matching symbols among a set of symbols based on names or unique IDs.
85 class SymbolIndex {
86 public:
87   virtual ~SymbolIndex() = default;
88 
89   /// Matches symbols in the index fuzzily and applies \p Callback on
90   /// each matched symbol before returning.
91   /// If returned Symbols are used outside Callback, they must be deep-copied!
92   ///
93   /// Returns true if there may be more results (limited by Req.Limit).
94   virtual bool
95   fuzzyFind(const FuzzyFindRequest &Req,
96             llvm::function_ref<void(const Symbol &)> Callback) const = 0;
97 
98   /// Looks up symbols with any of the given symbol IDs and applies \p Callback
99   /// on each matched symbol.
100   /// The returned symbol must be deep-copied if it's used outside Callback.
101   virtual void
102   lookup(const LookupRequest &Req,
103          llvm::function_ref<void(const Symbol &)> Callback) const = 0;
104 
105   /// Finds all occurrences (e.g. references, declarations, definitions) of a
106   /// symbol and applies \p Callback on each result.
107   ///
108   /// Results should be returned in arbitrary order.
109   /// The returned result must be deep-copied if it's used outside Callback.
110   ///
111   /// Returns true if there will be more results (limited by Req.Limit);
112   virtual bool refs(const RefsRequest &Req,
113                     llvm::function_ref<void(const Ref &)> Callback) const = 0;
114 
115   /// Finds all relations (S, P, O) stored in the index such that S is among
116   /// Req.Subjects and P is Req.Predicate, and invokes \p Callback for (S, O) in
117   /// each.
118   virtual void relations(
119       const RelationsRequest &Req,
120       llvm::function_ref<void(const SymbolID &Subject, const Symbol &Object)>
121           Callback) const = 0;
122 
123   /// Returns estimated size of index (in bytes).
124   virtual size_t estimateMemoryUsage() const = 0;
125 };
126 
127 // Delegating implementation of SymbolIndex whose delegate can be swapped out.
128 class SwapIndex : public SymbolIndex {
129 public:
130   // If an index is not provided, reset() must be called.
131   SwapIndex(std::unique_ptr<SymbolIndex> Index = nullptr)
Index(std::move (Index))132       : Index(std::move(Index)) {}
133   void reset(std::unique_ptr<SymbolIndex>);
134 
135   // SymbolIndex methods delegate to the current index, which is kept alive
136   // until the call returns (even if reset() is called).
137   bool fuzzyFind(const FuzzyFindRequest &,
138                  llvm::function_ref<void(const Symbol &)>) const override;
139   void lookup(const LookupRequest &,
140               llvm::function_ref<void(const Symbol &)>) const override;
141   bool refs(const RefsRequest &,
142             llvm::function_ref<void(const Ref &)>) const override;
143   void relations(const RelationsRequest &,
144                  llvm::function_ref<void(const SymbolID &, const Symbol &)>)
145       const override;
146 
147   size_t estimateMemoryUsage() const override;
148 
149 private:
150   std::shared_ptr<SymbolIndex> snapshot() const;
151   mutable std::mutex Mutex;
152   std::shared_ptr<SymbolIndex> Index;
153 };
154 
155 } // namespace clangd
156 } // namespace clang
157 
158 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
159