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