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 | |
20 | namespace clang { |
21 | namespace clangd { |
22 | namespace { |
23 | |
24 | /// A helper class to cache BackgroundIndexStorage operations and keep the |
25 | /// inverse dependency mapping. |
26 | class BackgroundIndexLoader { |
27 | public: |
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 | |
36 | private: |
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 | |
49 | std::pair<const LoadedShard &, std::vector<Path>> |
50 | BackgroundIndexLoader::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 | |
90 | void 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 | |
110 | std::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 | |
119 | std::vector<LoadedShard> |
120 | loadIndexShards(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 | |