xref: /llvm-project/clang-tools-extra/clangd/index/ProjectAware.cpp (revision 61fe67a4017375fd675f75652e857e837f77fa51)
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(External, 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>(std::move(Gen), Sync);
152 }
153 } // namespace clangd
154 } // namespace clang
155