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