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 | |
39 | /// Queries only the associates index when Req.RestrictForCodeCompletion is |
40 | /// set, otherwise queries all. |
41 | bool |
42 | fuzzyFind(const FuzzyFindRequest &Req, |
43 | llvm::function_ref<void(const Symbol &)> Callback) const override; |
44 | |
45 | /// Query all indexes while prioritizing the associated one (if any). |
46 | void relations(const RelationsRequest &Req, |
47 | llvm::function_ref<void(const SymbolID &, const Symbol &)> |
48 | Callback) const override; |
49 | |
50 | llvm::unique_function<IndexContents(llvm::StringRef) const> |
51 | indexedFiles() const override; |
52 | |
53 | ProjectAwareIndex(IndexFactory Gen, bool Sync) : Gen(std::move(Gen)) { |
54 | if (!Sync) |
55 | Tasks = std::make_unique<AsyncTaskRunner>(); |
56 | } |
57 | |
58 | private: |
59 | // Returns the index associated with current context, if any. |
60 | SymbolIndex *getIndex() const; |
61 | |
62 | // Storage for all the external indexes. |
63 | mutable std::mutex Mu; |
64 | mutable llvm::DenseMap<Config::ExternalIndexSpec, |
65 | std::unique_ptr<SymbolIndex>> |
66 | IndexForSpec; |
67 | mutable std::unique_ptr<AsyncTaskRunner> Tasks; |
68 | |
69 | const IndexFactory Gen; |
70 | }; |
71 | |
72 | size_t ProjectAwareIndex::estimateMemoryUsage() const { |
73 | size_t Total = 0; |
74 | std::lock_guard<std::mutex> Lock(Mu); |
75 | for (auto &Entry : IndexForSpec) |
76 | Total += Entry.second->estimateMemoryUsage(); |
77 | return Total; |
78 | } |
79 | |
80 | void ProjectAwareIndex::lookup( |
81 | const LookupRequest &Req, |
82 | llvm::function_ref<void(const Symbol &)> Callback) const { |
83 | trace::Span Tracer("ProjectAwareIndex::lookup" ); |
84 | if (auto *Idx = getIndex()) |
85 | Idx->lookup(Req, Callback); |
86 | } |
87 | |
88 | bool ProjectAwareIndex::refs( |
89 | const RefsRequest &Req, |
90 | llvm::function_ref<void(const Ref &)> Callback) const { |
91 | trace::Span Tracer("ProjectAwareIndex::refs" ); |
92 | if (auto *Idx = getIndex()) |
93 | return Idx->refs(Req, Callback); |
94 | return false; |
95 | } |
96 | |
97 | bool ProjectAwareIndex::fuzzyFind( |
98 | const FuzzyFindRequest &Req, |
99 | llvm::function_ref<void(const Symbol &)> Callback) const { |
100 | trace::Span Tracer("ProjectAwareIndex::fuzzyFind" ); |
101 | if (auto *Idx = getIndex()) |
102 | return Idx->fuzzyFind(Req, Callback); |
103 | return false; |
104 | } |
105 | |
106 | void ProjectAwareIndex::relations( |
107 | const RelationsRequest &Req, |
108 | llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const { |
109 | trace::Span Tracer("ProjectAwareIndex::relations" ); |
110 | if (auto *Idx = getIndex()) |
111 | return Idx->relations(Req, Callback); |
112 | } |
113 | |
114 | llvm::unique_function<IndexContents(llvm::StringRef) const> |
115 | ProjectAwareIndex::indexedFiles() const { |
116 | trace::Span Tracer("ProjectAwareIndex::indexedFiles" ); |
117 | if (auto *Idx = getIndex()) |
118 | return Idx->indexedFiles(); |
119 | return [](llvm::StringRef) { return IndexContents::None; }; |
120 | } |
121 | |
122 | SymbolIndex *ProjectAwareIndex::getIndex() const { |
123 | const auto &C = Config::current(); |
124 | if (C.Index.External.Kind == Config::ExternalIndexSpec::None) |
125 | return nullptr; |
126 | const auto &External = C.Index.External; |
127 | std::lock_guard<std::mutex> Lock(Mu); |
128 | auto Entry = IndexForSpec.try_emplace(Key: External, Args: nullptr); |
129 | if (Entry.second) |
130 | Entry.first->getSecond() = Gen(External, Tasks.get()); |
131 | return Entry.first->second.get(); |
132 | } |
133 | } // namespace |
134 | |
135 | std::unique_ptr<SymbolIndex> createProjectAwareIndex(IndexFactory Gen, |
136 | bool Sync) { |
137 | assert(Gen); |
138 | return std::make_unique<ProjectAwareIndex>(args: std::move(Gen), args&: Sync); |
139 | } |
140 | } // namespace clangd |
141 | } // namespace clang |
142 | |