xref: /llvm-project/clang-tools-extra/clangd/index/ProjectAware.cpp (revision d77cab823fc03f6933c3375baaddaae1477bb1d2)
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(External, 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>(std::move(Gen), Sync);
139 }
140 } // namespace clangd
141 } // namespace clang
142