|  | //===-- BackgroundIndexLoader.cpp - ---------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "index/BackgroundIndexLoader.h" | 
|  | #include "GlobalCompilationDatabase.h" | 
|  | #include "index/Background.h" | 
|  | #include "support/Logger.h" | 
|  | #include "support/Path.h" | 
|  | #include "llvm/ADT/DenseMap.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/ADT/StringMap.h" | 
|  | #include "llvm/Support/Path.h" | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | namespace clang { | 
|  | namespace clangd { | 
|  | namespace { | 
|  |  | 
|  | /// A helper class to cache BackgroundIndexStorage operations and keep the | 
|  | /// inverse dependency mapping. | 
|  | class BackgroundIndexLoader { | 
|  | public: | 
|  | BackgroundIndexLoader(BackgroundIndexStorage::Factory &IndexStorageFactory) | 
|  | : IndexStorageFactory(IndexStorageFactory) {} | 
|  | /// Load the shards for \p MainFile and all of its dependencies. | 
|  | void load(PathRef MainFile); | 
|  |  | 
|  | /// Consumes the loader and returns all shards. | 
|  | std::vector<LoadedShard> takeResult() &&; | 
|  |  | 
|  | private: | 
|  | /// Returns the Shard for \p StartSourceFile from cache or loads it from \p | 
|  | /// Storage. Also returns paths for dependencies of \p StartSourceFile if it | 
|  | /// wasn't cached yet. | 
|  | std::pair<const LoadedShard &, std::vector<Path>> | 
|  | loadShard(PathRef StartSourceFile, PathRef DependentTU); | 
|  |  | 
|  | /// Cache for Storage lookups. | 
|  | llvm::StringMap<LoadedShard> LoadedShards; | 
|  |  | 
|  | BackgroundIndexStorage::Factory &IndexStorageFactory; | 
|  | }; | 
|  |  | 
|  | std::pair<const LoadedShard &, std::vector<Path>> | 
|  | BackgroundIndexLoader::loadShard(PathRef StartSourceFile, PathRef DependentTU) { | 
|  | auto It = LoadedShards.try_emplace(StartSourceFile); | 
|  | LoadedShard &LS = It.first->getValue(); | 
|  | std::vector<Path> Edges = {}; | 
|  | // Return the cached shard. | 
|  | if (!It.second) | 
|  | return {LS, Edges}; | 
|  |  | 
|  | LS.AbsolutePath = StartSourceFile.str(); | 
|  | LS.DependentTU = std::string(DependentTU); | 
|  | BackgroundIndexStorage *Storage = IndexStorageFactory(LS.AbsolutePath); | 
|  | auto Shard = Storage->loadShard(StartSourceFile); | 
|  | if (!Shard || !Shard->Sources) { | 
|  | vlog("Failed to load shard: {0}", StartSourceFile); | 
|  | return {LS, Edges}; | 
|  | } | 
|  |  | 
|  | LS.Shard = std::move(Shard); | 
|  | for (const auto &It : *LS.Shard->Sources) { | 
|  | auto AbsPath = URI::resolve(It.getKey(), StartSourceFile); | 
|  | if (!AbsPath) { | 
|  | elog("Failed to resolve URI: {0}", AbsPath.takeError()); | 
|  | continue; | 
|  | } | 
|  | // A shard contains only edges for non main-file sources. | 
|  | if (*AbsPath != StartSourceFile) { | 
|  | Edges.push_back(*AbsPath); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Fill in shard metadata. | 
|  | const IncludeGraphNode &IGN = It.getValue(); | 
|  | LS.Digest = IGN.Digest; | 
|  | LS.CountReferences = IGN.Flags & IncludeGraphNode::SourceFlag::IsTU; | 
|  | LS.HadErrors = IGN.Flags & IncludeGraphNode::SourceFlag::HadErrors; | 
|  | } | 
|  | assert(LS.Digest != FileDigest{{0}} && "Digest is empty?"); | 
|  | return {LS, Edges}; | 
|  | } | 
|  |  | 
|  | void BackgroundIndexLoader::load(PathRef MainFile) { | 
|  | llvm::StringSet<> InQueue; | 
|  | // Following containers points to strings inside InQueue. | 
|  | std::queue<PathRef> ToVisit; | 
|  | InQueue.insert(MainFile); | 
|  | ToVisit.push(MainFile); | 
|  |  | 
|  | while (!ToVisit.empty()) { | 
|  | PathRef SourceFile = ToVisit.front(); | 
|  | ToVisit.pop(); | 
|  |  | 
|  | auto ShardAndEdges = loadShard(SourceFile, MainFile); | 
|  | for (PathRef Edge : ShardAndEdges.second) { | 
|  | auto It = InQueue.insert(Edge); | 
|  | if (It.second) | 
|  | ToVisit.push(It.first->getKey()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | std::vector<LoadedShard> BackgroundIndexLoader::takeResult() && { | 
|  | std::vector<LoadedShard> Result; | 
|  | Result.reserve(LoadedShards.size()); | 
|  | for (auto &It : LoadedShards) | 
|  | Result.push_back(std::move(It.getValue())); | 
|  | return Result; | 
|  | } | 
|  | } // namespace | 
|  |  | 
|  | std::vector<LoadedShard> | 
|  | loadIndexShards(llvm::ArrayRef<Path> MainFiles, | 
|  | BackgroundIndexStorage::Factory &IndexStorageFactory, | 
|  | const GlobalCompilationDatabase &CDB) { | 
|  | BackgroundIndexLoader Loader(IndexStorageFactory); | 
|  | for (llvm::StringRef MainFile : MainFiles) { | 
|  | assert(llvm::sys::path::is_absolute(MainFile)); | 
|  | Loader.load(MainFile); | 
|  | } | 
|  | return std::move(Loader).takeResult(); | 
|  | } | 
|  |  | 
|  | } // namespace clangd | 
|  | } // namespace clang |