1 | //===--- ProjectAware.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 | #include "ProjectAware.h" |
10 | #include "Config.h" |
11 | #include "index/Index.h" |
12 | #include "index/Ref.h" |
13 | #include "index/Symbol.h" |
14 | #include "index/SymbolID.h" |
15 | #include "support/Threading.h" |
16 | #include "support/Trace.h" |
17 | #include "llvm/ADT/DenseMap.h" |
18 | #include "llvm/ADT/StringRef.h" |
19 | #include <map> |
20 | #include <memory> |
21 | #include <mutex> |
22 | #include <tuple> |
23 | |
24 | namespace clang { |
25 | namespace clangd { |
26 | namespace { |
27 | class ProjectAwareIndex : public SymbolIndex { |
28 | public: |
29 | size_t estimateMemoryUsage() const override; |
30 | |
31 | /// Only queries the associated index with the current context. |
32 | void lookup(const LookupRequest &Req, |
33 | llvm::function_ref<void(const Symbol &)> Callback) const override; |
34 | |
35 | /// Query all indexes while prioritizing the associated one (if any). |
36 | bool refs(const RefsRequest &Req, |
37 | llvm::function_ref<void(const Ref &)> Callback) const override; |
38 | /// Query all indexes while prioritizing the associated one (if any). |
39 | bool containedRefs(const ContainedRefsRequest &Req, |
40 | llvm::function_ref<void(const ContainedRefsResult &)> |
41 | Callback) const override; |
42 | |
43 | /// Queries only the associates index when Req.RestrictForCodeCompletion is |
44 | /// set, otherwise queries all. |
45 | bool |
46 | fuzzyFind(const FuzzyFindRequest &Req, |
47 | llvm::function_ref<void(const Symbol &)> Callback) const override; |
48 | |
49 | /// Query all indexes while prioritizing the associated one (if any). |
50 | void relations(const RelationsRequest &Req, |
51 | llvm::function_ref<void(const SymbolID &, const Symbol &)> |
52 | Callback) const override; |
53 | |
54 | llvm::unique_function<IndexContents(llvm::StringRef) const> |
55 | indexedFiles() const override; |
56 | |
57 | ProjectAwareIndex(IndexFactory Gen, bool Sync) : Gen(std::move(Gen)) { |
58 | if (!Sync) |
59 | Tasks = std::make_unique<AsyncTaskRunner>(); |
60 | } |
61 | |
62 | private: |
63 | // Returns the index associated with current context, if any. |
64 | SymbolIndex *getIndex() const; |
65 | |
66 | // Storage for all the external indexes. |
67 | mutable std::mutex Mu; |
68 | mutable llvm::DenseMap<Config::ExternalIndexSpec, |
69 | std::unique_ptr<SymbolIndex>> |
70 | IndexForSpec; |
71 | mutable std::unique_ptr<AsyncTaskRunner> Tasks; |
72 | |
73 | const IndexFactory Gen; |
74 | }; |
75 | |
76 | size_t ProjectAwareIndex::estimateMemoryUsage() const { |
77 | size_t Total = 0; |
78 | std::lock_guard<std::mutex> Lock(Mu); |
79 | for (auto &Entry : IndexForSpec) |
80 | Total += Entry.second->estimateMemoryUsage(); |
81 | return Total; |
82 | } |
83 | |
84 | void ProjectAwareIndex::lookup( |
85 | const LookupRequest &Req, |
86 | llvm::function_ref<void(const Symbol &)> Callback) const { |
87 | trace::Span Tracer("ProjectAwareIndex::lookup" ); |
88 | if (auto *Idx = getIndex()) |
89 | Idx->lookup(Req, Callback); |
90 | } |
91 | |
92 | bool ProjectAwareIndex::refs( |
93 | const RefsRequest &Req, |
94 | llvm::function_ref<void(const Ref &)> Callback) const { |
95 | trace::Span Tracer("ProjectAwareIndex::refs" ); |
96 | if (auto *Idx = getIndex()) |
97 | return Idx->refs(Req, Callback); |
98 | return false; |
99 | } |
100 | |
101 | bool ProjectAwareIndex::containedRefs( |
102 | const ContainedRefsRequest &Req, |
103 | llvm::function_ref<void(const ContainedRefsResult &)> Callback) const { |
104 | trace::Span Tracer("ProjectAwareIndex::refersTo" ); |
105 | if (auto *Idx = getIndex()) |
106 | return Idx->containedRefs(Req, Callback); |
107 | return false; |
108 | } |
109 | |
110 | bool ProjectAwareIndex::fuzzyFind( |
111 | const FuzzyFindRequest &Req, |
112 | llvm::function_ref<void(const Symbol &)> Callback) const { |
113 | trace::Span Tracer("ProjectAwareIndex::fuzzyFind" ); |
114 | if (auto *Idx = getIndex()) |
115 | return Idx->fuzzyFind(Req, Callback); |
116 | return false; |
117 | } |
118 | |
119 | void ProjectAwareIndex::relations( |
120 | const RelationsRequest &Req, |
121 | llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const { |
122 | trace::Span Tracer("ProjectAwareIndex::relations" ); |
123 | if (auto *Idx = getIndex()) |
124 | return Idx->relations(Req, Callback); |
125 | } |
126 | |
127 | llvm::unique_function<IndexContents(llvm::StringRef) const> |
128 | ProjectAwareIndex::indexedFiles() const { |
129 | trace::Span Tracer("ProjectAwareIndex::indexedFiles" ); |
130 | if (auto *Idx = getIndex()) |
131 | return Idx->indexedFiles(); |
132 | return [](llvm::StringRef) { return IndexContents::None; }; |
133 | } |
134 | |
135 | SymbolIndex *ProjectAwareIndex::getIndex() const { |
136 | const auto &C = Config::current(); |
137 | if (C.Index.External.Kind == Config::ExternalIndexSpec::None) |
138 | return nullptr; |
139 | const auto &External = C.Index.External; |
140 | std::lock_guard<std::mutex> Lock(Mu); |
141 | auto Entry = IndexForSpec.try_emplace(Key: External, Args: nullptr); |
142 | if (Entry.second) |
143 | Entry.first->getSecond() = Gen(External, Tasks.get()); |
144 | return Entry.first->second.get(); |
145 | } |
146 | } // namespace |
147 | |
148 | std::unique_ptr<SymbolIndex> createProjectAwareIndex(IndexFactory Gen, |
149 | bool Sync) { |
150 | assert(Gen); |
151 | return std::make_unique<ProjectAwareIndex>(args: std::move(Gen), args&: Sync); |
152 | } |
153 | } // namespace clangd |
154 | } // namespace clang |
155 | |