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