llvm-project/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp

133 lines
4.2 KiB
C++

//===-- 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/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