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