1 //===-- BackgroundIndexLoader.cpp - ---------------------------------------===// 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 "index/BackgroundIndexLoader.h" 10 #include "GlobalCompilationDatabase.h" 11 #include "Logger.h" 12 #include "Path.h" 13 #include "index/Background.h" 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/ADT/DenseSet.h" 16 #include "llvm/ADT/SmallString.h" 17 #include "llvm/ADT/StringMap.h" 18 #include "llvm/Support/Path.h" 19 #include <string> 20 #include <utility> 21 #include <vector> 22 23 namespace clang { 24 namespace clangd { 25 namespace { 26 27 llvm::Optional<Path> uriToAbsolutePath(llvm::StringRef URI, PathRef HintPath) { 28 auto U = URI::parse(URI); 29 if (!U) 30 return llvm::None; 31 auto AbsolutePath = URI::resolve(*U, HintPath); 32 if (!AbsolutePath) 33 return llvm::None; 34 return *AbsolutePath; 35 } 36 37 /// A helper class to cache BackgroundIndexStorage operations and keep the 38 /// inverse dependency mapping. 39 class BackgroundIndexLoader { 40 public: 41 BackgroundIndexLoader(BackgroundIndexStorage::Factory &IndexStorageFactory) 42 : IndexStorageFactory(IndexStorageFactory) {} 43 /// Load the shards for \p MainFile and all of its dependencies. 44 void load(PathRef MainFile); 45 46 /// Consumes the loader and returns all shards. 47 std::vector<LoadedShard> takeResult() &&; 48 49 private: 50 /// Returns the Shard for \p StartSourceFile from cache or loads it from \p 51 /// Storage. Also returns paths for dependencies of \p StartSourceFile if it 52 /// wasn't cached yet. 53 std::pair<const LoadedShard &, std::vector<Path>> 54 loadShard(PathRef StartSourceFile, PathRef DependentTU); 55 56 /// Cache for Storage lookups. 57 llvm::StringMap<LoadedShard> LoadedShards; 58 59 BackgroundIndexStorage::Factory &IndexStorageFactory; 60 }; 61 62 std::pair<const LoadedShard &, std::vector<Path>> 63 BackgroundIndexLoader::loadShard(PathRef StartSourceFile, PathRef DependentTU) { 64 auto It = LoadedShards.try_emplace(StartSourceFile); 65 LoadedShard &LS = It.first->getValue(); 66 std::vector<Path> Edges = {}; 67 // Return the cached shard. 68 if (!It.second) 69 return {LS, Edges}; 70 71 LS.AbsolutePath = StartSourceFile.str(); 72 LS.DependentTU = DependentTU; 73 BackgroundIndexStorage *Storage = IndexStorageFactory(LS.AbsolutePath); 74 auto Shard = Storage->loadShard(StartSourceFile); 75 if (!Shard || !Shard->Sources) { 76 vlog("Failed to load shard: {0}", StartSourceFile); 77 return {LS, Edges}; 78 } 79 80 LS.Shard = std::move(Shard); 81 for (const auto &It : *LS.Shard->Sources) { 82 auto AbsPath = uriToAbsolutePath(It.getKey(), StartSourceFile); 83 if (!AbsPath) 84 continue; 85 // A shard contains only edges for non main-file sources. 86 if (*AbsPath != StartSourceFile) { 87 Edges.push_back(*AbsPath); 88 continue; 89 } 90 91 // Fill in shard metadata. 92 const IncludeGraphNode &IGN = It.getValue(); 93 LS.Digest = IGN.Digest; 94 LS.CountReferences = IGN.Flags & IncludeGraphNode::SourceFlag::IsTU; 95 LS.HadErrors = IGN.Flags & IncludeGraphNode::SourceFlag::HadErrors; 96 } 97 assert(LS.Digest != FileDigest{{0}} && "Digest is empty?"); 98 return {LS, Edges}; 99 } 100 101 void BackgroundIndexLoader::load(PathRef MainFile) { 102 llvm::StringSet<> InQueue; 103 // Following containers points to strings inside InQueue. 104 std::queue<PathRef> ToVisit; 105 InQueue.insert(MainFile); 106 ToVisit.push(MainFile); 107 108 while (!ToVisit.empty()) { 109 PathRef SourceFile = ToVisit.front(); 110 ToVisit.pop(); 111 112 auto ShardAndEdges = loadShard(SourceFile, MainFile); 113 for (PathRef Edge : ShardAndEdges.second) { 114 auto It = InQueue.insert(Edge); 115 if (It.second) 116 ToVisit.push(It.first->getKey()); 117 } 118 } 119 } 120 121 std::vector<LoadedShard> BackgroundIndexLoader::takeResult() && { 122 std::vector<LoadedShard> Result; 123 Result.reserve(LoadedShards.size()); 124 for (auto &It : LoadedShards) 125 Result.push_back(std::move(It.getValue())); 126 return Result; 127 } 128 } // namespace 129 130 std::vector<LoadedShard> 131 loadIndexShards(llvm::ArrayRef<Path> MainFiles, 132 BackgroundIndexStorage::Factory &IndexStorageFactory, 133 const GlobalCompilationDatabase &CDB) { 134 BackgroundIndexLoader Loader(IndexStorageFactory); 135 for (llvm::StringRef MainFile : MainFiles) { 136 assert(llvm::sys::path::is_absolute(MainFile)); 137 Loader.load(MainFile); 138 } 139 return std::move(Loader).takeResult(); 140 } 141 142 } // namespace clangd 143 } // namespace clang 144