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