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 "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 the
25/// 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 \p
38 /// Storage. Also returns paths for dependencies of \p StartSourceFile if it
39 /// 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(Key: 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(ShardIdentifier: StartSourceFile);
62 if (!Shard || !Shard->Sources) {
63 vlog(Fmt: "Failed to load shard: {0}", Vals&: 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(FileURI: It.getKey(), HintPath: StartSourceFile);
70 if (!AbsPath) {
71 elog(Fmt: "Failed to resolve URI: {0}", Vals: AbsPath.takeError());
72 continue;
73 }
74 // A shard contains only edges for non main-file sources.
75 if (*AbsPath != StartSourceFile) {
76 Edges.push_back(x: *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(key: MainFile);
95 ToVisit.push(x: MainFile);
96
97 while (!ToVisit.empty()) {
98 PathRef SourceFile = ToVisit.front();
99 ToVisit.pop();
100
101 auto ShardAndEdges = loadShard(StartSourceFile: SourceFile, DependentTU: MainFile);
102 for (PathRef Edge : ShardAndEdges.second) {
103 auto It = InQueue.insert(key: Edge);
104 if (It.second)
105 ToVisit.push(x: It.first->getKey());
106 }
107 }
108}
109
110std::vector<LoadedShard> BackgroundIndexLoader::takeResult() && {
111 std::vector<LoadedShard> Result;
112 Result.reserve(n: LoadedShards.size());
113 for (auto &It : LoadedShards)
114 Result.push_back(x: std::move(It.getValue()));
115 return Result;
116}
117} // namespace
118
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 clangd
132} // namespace clang
133

source code of clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp