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