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 57 llvm::unique_function<IndexContents(llvm::StringRef) const> 58 indexedFiles() const override; 59 60 ProjectAwareIndex(IndexFactory Gen, bool Sync) : Gen(std::move(Gen)) { 61 if (!Sync) 62 Tasks = std::make_unique<AsyncTaskRunner>(); 63 } 64 65 private: 66 // Returns the index associated with current context, if any. 67 SymbolIndex *getIndex() const; 68 69 // Storage for all the external indexes. 70 mutable std::mutex Mu; 71 mutable llvm::DenseMap<Config::ExternalIndexSpec, 72 std::unique_ptr<SymbolIndex>> 73 IndexForSpec; 74 mutable std::unique_ptr<AsyncTaskRunner> Tasks; 75 76 const IndexFactory Gen; 77 }; 78 79 size_t ProjectAwareIndex::estimateMemoryUsage() const { 80 size_t Total = 0; 81 std::lock_guard<std::mutex> Lock(Mu); 82 for (auto &Entry : IndexForSpec) 83 Total += Entry.second->estimateMemoryUsage(); 84 return Total; 85 } 86 87 void ProjectAwareIndex::lookup( 88 const LookupRequest &Req, 89 llvm::function_ref<void(const Symbol &)> Callback) const { 90 trace::Span Tracer("ProjectAwareIndex::lookup"); 91 if (auto *Idx = getIndex()) 92 Idx->lookup(Req, Callback); 93 } 94 95 bool ProjectAwareIndex::refs( 96 const RefsRequest &Req, 97 llvm::function_ref<void(const Ref &)> Callback) const { 98 trace::Span Tracer("ProjectAwareIndex::refs"); 99 if (auto *Idx = getIndex()) 100 return Idx->refs(Req, Callback); 101 return false; 102 } 103 104 bool ProjectAwareIndex::fuzzyFind( 105 const FuzzyFindRequest &Req, 106 llvm::function_ref<void(const Symbol &)> Callback) const { 107 trace::Span Tracer("ProjectAwareIndex::fuzzyFind"); 108 if (auto *Idx = getIndex()) 109 return Idx->fuzzyFind(Req, Callback); 110 return false; 111 } 112 113 void ProjectAwareIndex::relations( 114 const RelationsRequest &Req, 115 llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const { 116 trace::Span Tracer("ProjectAwareIndex::relations"); 117 if (auto *Idx = getIndex()) 118 return Idx->relations(Req, Callback); 119 } 120 121 llvm::unique_function<IndexContents(llvm::StringRef) const> 122 ProjectAwareIndex::indexedFiles() const { 123 trace::Span Tracer("ProjectAwareIndex::indexedFiles"); 124 if (auto *Idx = getIndex()) 125 return Idx->indexedFiles(); 126 return [](llvm::StringRef) { return IndexContents::None; }; 127 } 128 129 SymbolIndex *ProjectAwareIndex::getIndex() const { 130 const auto &C = Config::current(); 131 if (C.Index.External.Kind == Config::ExternalIndexSpec::None) 132 return nullptr; 133 const auto &External = C.Index.External; 134 std::lock_guard<std::mutex> Lock(Mu); 135 auto Entry = IndexForSpec.try_emplace(External, nullptr); 136 if (Entry.second) 137 Entry.first->getSecond() = Gen(External, Tasks.get()); 138 return Entry.first->second.get(); 139 } 140 } // namespace 141 142 std::unique_ptr<SymbolIndex> createProjectAwareIndex(IndexFactory Gen, 143 bool Sync) { 144 assert(Gen); 145 return std::make_unique<ProjectAwareIndex>(std::move(Gen), Sync); 146 } 147 } // namespace clangd 148 } // namespace clang 149