xref: /llvm-project/clang-tools-extra/clangd/index/ProjectAware.cpp (revision 61fe67a4017375fd675f75652e857e837f77fa51)
1067ffbfeSKadir Cetinkaya //===--- ProjectAware.h ------------------------------------------*- C++-*-===//
2067ffbfeSKadir Cetinkaya //
3067ffbfeSKadir Cetinkaya // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4067ffbfeSKadir Cetinkaya // See https://llvm.org/LICENSE.txt for license information.
5067ffbfeSKadir Cetinkaya // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6067ffbfeSKadir Cetinkaya //
7067ffbfeSKadir Cetinkaya //===----------------------------------------------------------------------===//
8067ffbfeSKadir Cetinkaya 
9067ffbfeSKadir Cetinkaya #include "ProjectAware.h"
10067ffbfeSKadir Cetinkaya #include "Config.h"
11067ffbfeSKadir Cetinkaya #include "index/Index.h"
12067ffbfeSKadir Cetinkaya #include "index/Ref.h"
13067ffbfeSKadir Cetinkaya #include "index/Symbol.h"
14067ffbfeSKadir Cetinkaya #include "index/SymbolID.h"
15067ffbfeSKadir Cetinkaya #include "support/Threading.h"
16067ffbfeSKadir Cetinkaya #include "support/Trace.h"
17067ffbfeSKadir Cetinkaya #include "llvm/ADT/DenseMap.h"
18067ffbfeSKadir Cetinkaya #include "llvm/ADT/StringRef.h"
19067ffbfeSKadir Cetinkaya #include <map>
20067ffbfeSKadir Cetinkaya #include <memory>
21067ffbfeSKadir Cetinkaya #include <mutex>
22067ffbfeSKadir Cetinkaya #include <tuple>
23067ffbfeSKadir Cetinkaya 
24067ffbfeSKadir Cetinkaya namespace clang {
25067ffbfeSKadir Cetinkaya namespace clangd {
26067ffbfeSKadir Cetinkaya namespace {
27067ffbfeSKadir Cetinkaya class ProjectAwareIndex : public SymbolIndex {
28067ffbfeSKadir Cetinkaya public:
29067ffbfeSKadir Cetinkaya   size_t estimateMemoryUsage() const override;
30067ffbfeSKadir Cetinkaya 
31067ffbfeSKadir Cetinkaya   /// Only queries the associated index with the current context.
32067ffbfeSKadir Cetinkaya   void lookup(const LookupRequest &Req,
33067ffbfeSKadir Cetinkaya               llvm::function_ref<void(const Symbol &)> Callback) const override;
34067ffbfeSKadir Cetinkaya 
35067ffbfeSKadir Cetinkaya   /// Query all indexes while prioritizing the associated one (if any).
36067ffbfeSKadir Cetinkaya   bool refs(const RefsRequest &Req,
37067ffbfeSKadir Cetinkaya             llvm::function_ref<void(const Ref &)> Callback) const override;
38*61fe67a4SNathan Ridge   /// Query all indexes while prioritizing the associated one (if any).
39*61fe67a4SNathan Ridge   bool containedRefs(const ContainedRefsRequest &Req,
40*61fe67a4SNathan Ridge                      llvm::function_ref<void(const ContainedRefsResult &)>
41*61fe67a4SNathan Ridge                          Callback) const override;
42067ffbfeSKadir Cetinkaya 
43067ffbfeSKadir Cetinkaya   /// Queries only the associates index when Req.RestrictForCodeCompletion is
44067ffbfeSKadir Cetinkaya   /// set, otherwise queries all.
45067ffbfeSKadir Cetinkaya   bool
46067ffbfeSKadir Cetinkaya   fuzzyFind(const FuzzyFindRequest &Req,
47067ffbfeSKadir Cetinkaya             llvm::function_ref<void(const Symbol &)> Callback) const override;
48067ffbfeSKadir Cetinkaya 
49067ffbfeSKadir Cetinkaya   /// Query all indexes while prioritizing the associated one (if any).
50067ffbfeSKadir Cetinkaya   void relations(const RelationsRequest &Req,
51067ffbfeSKadir Cetinkaya                  llvm::function_ref<void(const SymbolID &, const Symbol &)>
52067ffbfeSKadir Cetinkaya                      Callback) const override;
53067ffbfeSKadir Cetinkaya 
5491698fe4SAleksandr Platonov   llvm::unique_function<IndexContents(llvm::StringRef) const>
55e35f9229SAleksandr Platonov   indexedFiles() const override;
56e35f9229SAleksandr Platonov 
57dc9c0963SKadir Cetinkaya   ProjectAwareIndex(IndexFactory Gen, bool Sync) : Gen(std::move(Gen)) {
58dc9c0963SKadir Cetinkaya     if (!Sync)
59dc9c0963SKadir Cetinkaya       Tasks = std::make_unique<AsyncTaskRunner>();
60dc9c0963SKadir Cetinkaya   }
61067ffbfeSKadir Cetinkaya 
62067ffbfeSKadir Cetinkaya private:
63067ffbfeSKadir Cetinkaya   // Returns the index associated with current context, if any.
64067ffbfeSKadir Cetinkaya   SymbolIndex *getIndex() const;
65067ffbfeSKadir Cetinkaya 
66067ffbfeSKadir Cetinkaya   // Storage for all the external indexes.
67067ffbfeSKadir Cetinkaya   mutable std::mutex Mu;
68067ffbfeSKadir Cetinkaya   mutable llvm::DenseMap<Config::ExternalIndexSpec,
69067ffbfeSKadir Cetinkaya                          std::unique_ptr<SymbolIndex>>
70067ffbfeSKadir Cetinkaya       IndexForSpec;
71dc9c0963SKadir Cetinkaya   mutable std::unique_ptr<AsyncTaskRunner> Tasks;
72067ffbfeSKadir Cetinkaya 
73067ffbfeSKadir Cetinkaya   const IndexFactory Gen;
74067ffbfeSKadir Cetinkaya };
75067ffbfeSKadir Cetinkaya 
76067ffbfeSKadir Cetinkaya size_t ProjectAwareIndex::estimateMemoryUsage() const {
77067ffbfeSKadir Cetinkaya   size_t Total = 0;
78067ffbfeSKadir Cetinkaya   std::lock_guard<std::mutex> Lock(Mu);
79067ffbfeSKadir Cetinkaya   for (auto &Entry : IndexForSpec)
80067ffbfeSKadir Cetinkaya     Total += Entry.second->estimateMemoryUsage();
81067ffbfeSKadir Cetinkaya   return Total;
82067ffbfeSKadir Cetinkaya }
83067ffbfeSKadir Cetinkaya 
84067ffbfeSKadir Cetinkaya void ProjectAwareIndex::lookup(
85067ffbfeSKadir Cetinkaya     const LookupRequest &Req,
86067ffbfeSKadir Cetinkaya     llvm::function_ref<void(const Symbol &)> Callback) const {
87067ffbfeSKadir Cetinkaya   trace::Span Tracer("ProjectAwareIndex::lookup");
88067ffbfeSKadir Cetinkaya   if (auto *Idx = getIndex())
89067ffbfeSKadir Cetinkaya     Idx->lookup(Req, Callback);
90067ffbfeSKadir Cetinkaya }
91067ffbfeSKadir Cetinkaya 
92067ffbfeSKadir Cetinkaya bool ProjectAwareIndex::refs(
93067ffbfeSKadir Cetinkaya     const RefsRequest &Req,
94067ffbfeSKadir Cetinkaya     llvm::function_ref<void(const Ref &)> Callback) const {
95067ffbfeSKadir Cetinkaya   trace::Span Tracer("ProjectAwareIndex::refs");
96067ffbfeSKadir Cetinkaya   if (auto *Idx = getIndex())
97067ffbfeSKadir Cetinkaya     return Idx->refs(Req, Callback);
98067ffbfeSKadir Cetinkaya   return false;
99067ffbfeSKadir Cetinkaya }
100067ffbfeSKadir Cetinkaya 
101*61fe67a4SNathan Ridge bool ProjectAwareIndex::containedRefs(
102*61fe67a4SNathan Ridge     const ContainedRefsRequest &Req,
103*61fe67a4SNathan Ridge     llvm::function_ref<void(const ContainedRefsResult &)> Callback) const {
104*61fe67a4SNathan Ridge   trace::Span Tracer("ProjectAwareIndex::refersTo");
105*61fe67a4SNathan Ridge   if (auto *Idx = getIndex())
106*61fe67a4SNathan Ridge     return Idx->containedRefs(Req, Callback);
107*61fe67a4SNathan Ridge   return false;
108*61fe67a4SNathan Ridge }
109*61fe67a4SNathan Ridge 
110067ffbfeSKadir Cetinkaya bool ProjectAwareIndex::fuzzyFind(
111067ffbfeSKadir Cetinkaya     const FuzzyFindRequest &Req,
112067ffbfeSKadir Cetinkaya     llvm::function_ref<void(const Symbol &)> Callback) const {
113067ffbfeSKadir Cetinkaya   trace::Span Tracer("ProjectAwareIndex::fuzzyFind");
114067ffbfeSKadir Cetinkaya   if (auto *Idx = getIndex())
115067ffbfeSKadir Cetinkaya     return Idx->fuzzyFind(Req, Callback);
116067ffbfeSKadir Cetinkaya   return false;
117067ffbfeSKadir Cetinkaya }
118067ffbfeSKadir Cetinkaya 
119067ffbfeSKadir Cetinkaya void ProjectAwareIndex::relations(
120067ffbfeSKadir Cetinkaya     const RelationsRequest &Req,
121067ffbfeSKadir Cetinkaya     llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const {
122067ffbfeSKadir Cetinkaya   trace::Span Tracer("ProjectAwareIndex::relations");
123067ffbfeSKadir Cetinkaya   if (auto *Idx = getIndex())
124067ffbfeSKadir Cetinkaya     return Idx->relations(Req, Callback);
125067ffbfeSKadir Cetinkaya }
126067ffbfeSKadir Cetinkaya 
12791698fe4SAleksandr Platonov llvm::unique_function<IndexContents(llvm::StringRef) const>
128e35f9229SAleksandr Platonov ProjectAwareIndex::indexedFiles() const {
129e35f9229SAleksandr Platonov   trace::Span Tracer("ProjectAwareIndex::indexedFiles");
130e35f9229SAleksandr Platonov   if (auto *Idx = getIndex())
131e35f9229SAleksandr Platonov     return Idx->indexedFiles();
13291698fe4SAleksandr Platonov   return [](llvm::StringRef) { return IndexContents::None; };
133e35f9229SAleksandr Platonov }
134e35f9229SAleksandr Platonov 
135067ffbfeSKadir Cetinkaya SymbolIndex *ProjectAwareIndex::getIndex() const {
136067ffbfeSKadir Cetinkaya   const auto &C = Config::current();
1379e9ac413SKadir Cetinkaya   if (C.Index.External.Kind == Config::ExternalIndexSpec::None)
138067ffbfeSKadir Cetinkaya     return nullptr;
1399e9ac413SKadir Cetinkaya   const auto &External = C.Index.External;
140067ffbfeSKadir Cetinkaya   std::lock_guard<std::mutex> Lock(Mu);
141067ffbfeSKadir Cetinkaya   auto Entry = IndexForSpec.try_emplace(External, nullptr);
142067ffbfeSKadir Cetinkaya   if (Entry.second)
143dc9c0963SKadir Cetinkaya     Entry.first->getSecond() = Gen(External, Tasks.get());
144067ffbfeSKadir Cetinkaya   return Entry.first->second.get();
145067ffbfeSKadir Cetinkaya }
146067ffbfeSKadir Cetinkaya } // namespace
147067ffbfeSKadir Cetinkaya 
148dc9c0963SKadir Cetinkaya std::unique_ptr<SymbolIndex> createProjectAwareIndex(IndexFactory Gen,
149dc9c0963SKadir Cetinkaya                                                      bool Sync) {
150cab31368SKadir Cetinkaya   assert(Gen);
151dc9c0963SKadir Cetinkaya   return std::make_unique<ProjectAwareIndex>(std::move(Gen), Sync);
152067ffbfeSKadir Cetinkaya }
153067ffbfeSKadir Cetinkaya } // namespace clangd
154067ffbfeSKadir Cetinkaya } // namespace clang
155