xref: /llvm-project/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp (revision 4d006520b8c0cc3a52913b4665bf741c737e5592)
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:
BackgroundIndexLoader(BackgroundIndexStorage::Factory & IndexStorageFactory)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>>
loadShard(PathRef StartSourceFile,PathRef DependentTU)50 BackgroundIndexLoader::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 
load(PathRef MainFile)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(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 
takeResult()110 std::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 } // namespace
118 
119 std::vector<LoadedShard>
loadIndexShards(llvm::ArrayRef<Path> MainFiles,BackgroundIndexStorage::Factory & IndexStorageFactory,const GlobalCompilationDatabase & CDB)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