blob: ef83abf295038ec14220f198873840bb2cdecdf7 [file] [log] [blame]
Sam McCall8dc9dbb2018-10-15 13:34:10 +00001//===-- Background.cpp - Build an index in a background thread ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "index/Background.h"
11#include "ClangdUnit.h"
12#include "Compiler.h"
13#include "Logger.h"
Kadir Cetinkaya6675be82018-10-30 12:13:27 +000014#include "Threading.h"
Sam McCall8dc9dbb2018-10-15 13:34:10 +000015#include "Trace.h"
Eric Liuad588af2018-11-06 10:55:21 +000016#include "URI.h"
Sam McCall8dc9dbb2018-10-15 13:34:10 +000017#include "index/IndexAction.h"
18#include "index/MemIndex.h"
19#include "index/Serialization.h"
Eric Liuad588af2018-11-06 10:55:21 +000020#include "index/SymbolCollector.h"
21#include "clang/Basic/SourceLocation.h"
22#include "clang/Basic/SourceManager.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/StringMap.h"
25#include "llvm/ADT/StringRef.h"
Sam McCall8dc9dbb2018-10-15 13:34:10 +000026#include "llvm/Support/SHA1.h"
Kadir Cetinkayacb8407c2018-11-15 10:31:15 +000027#include <memory>
28#include <queue>
Sam McCall8dc9dbb2018-10-15 13:34:10 +000029#include <random>
Eric Liuad588af2018-11-06 10:55:21 +000030#include <string>
Sam McCall8dc9dbb2018-10-15 13:34:10 +000031
32using namespace llvm;
33namespace clang {
34namespace clangd {
35
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +000036namespace {
37
38static BackgroundIndex::FileDigest digest(StringRef Content) {
39 return SHA1::hash({(const uint8_t *)Content.data(), Content.size()});
40}
41
42static Optional<BackgroundIndex::FileDigest> digestFile(const SourceManager &SM,
43 FileID FID) {
44 bool Invalid = false;
45 StringRef Content = SM.getBufferData(FID, &Invalid);
46 if (Invalid)
47 return None;
48 return digest(Content);
49}
50
51llvm::SmallString<128>
52getShardPathFromFilePath(llvm::SmallString<128> ShardRoot,
53 llvm::StringRef FilePath) {
54 sys::path::append(ShardRoot, sys::path::filename(FilePath) +
55 toHex(digest(FilePath)) + ".idx");
56 return ShardRoot;
57}
58
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000059// Uses disk as a storage for index shards. Creates a directory called
60// ".clangd-index/" under the path provided during initialize.
61// Note: Requires initialize to be called before storing or retrieval.
62// This class is thread-safe.
63class DiskBackedIndexStorage : public BackgroundIndexStorage {
64 llvm::SmallString<128> DiskShardRoot;
65
66public:
67 llvm::Expected<IndexFileIn>
68 retrieveShard(llvm::StringRef ShardIdentifier) const override {
69 auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
70 auto Buffer = MemoryBuffer::getFile(ShardPath);
71 if (!Buffer) {
72 elog("Couldn't retrieve {0}: {1}", ShardPath,
73 Buffer.getError().message());
74 return llvm::make_error<llvm::StringError>(Buffer.getError());
75 }
76 // FIXME: Change readIndexFile to also look at Hash of the source that
77 // generated index and skip if there is a mismatch.
78 return readIndexFile(Buffer->get()->getBuffer());
79 }
80
81 bool storeShard(llvm::StringRef ShardIdentifier,
82 IndexFileOut Shard) const override {
83 auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
84 std::error_code EC;
85 llvm::raw_fd_ostream OS(ShardPath, EC);
86 if (EC) {
87 elog("Failed to open {0} for writing: {1}", ShardPath, EC.message());
88 return false;
89 }
90 OS << Shard;
91 return true;
92 }
93
94 // Initializes DiskShardRoot to (Directory + ".clangd-index/") which is the
95 // base directory for all shard files. After the initialization succeeds all
96 // subsequent calls are no-op.
97 DiskBackedIndexStorage(llvm::StringRef Directory) : DiskShardRoot(Directory) {
98 sys::path::append(DiskShardRoot, ".clangd-index/");
99 if (!llvm::sys::fs::exists(DiskShardRoot)) {
100 std::error_code OK;
101 std::error_code EC = llvm::sys::fs::create_directory(DiskShardRoot);
102 if (EC != OK) {
103 elog("Failed to create {0}: {1}", DiskShardRoot, EC.message());
104 }
105 }
106 }
107};
108
109SmallString<128> getAbsolutePath(const tooling::CompileCommand &Cmd) {
110 SmallString<128> AbsolutePath;
111 if (sys::path::is_absolute(Cmd.Filename)) {
112 AbsolutePath = Cmd.Filename;
113 } else {
114 AbsolutePath = Cmd.Directory;
115 sys::path::append(AbsolutePath, Cmd.Filename);
116 }
117 return AbsolutePath;
118}
119
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000120} // namespace
121
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000122BackgroundIndex::BackgroundIndex(Context BackgroundContext,
123 StringRef ResourceDir,
124 const FileSystemProvider &FSProvider,
125 ArrayRef<std::string> URISchemes,
126 size_t ThreadPoolSize)
Sam McCallc008af62018-10-20 15:30:37 +0000127 : SwapIndex(make_unique<MemIndex>()), ResourceDir(ResourceDir),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000128 FSProvider(FSProvider), BackgroundContext(std::move(BackgroundContext)),
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000129 URISchemes(URISchemes) {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000130 assert(ThreadPoolSize > 0 && "Thread pool size can't be zero.");
131 while (ThreadPoolSize--) {
132 ThreadPool.emplace_back([this] { run(); });
133 // Set priority to low, since background indexing is a long running task we
134 // do not want to eat up cpu when there are any other high priority threads.
135 // FIXME: In the future we might want a more general way of handling this to
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000136 // support tasks with various priorities.
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000137 setThreadPriority(ThreadPool.back(), ThreadPriority::Low);
138 }
139}
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000140
141BackgroundIndex::~BackgroundIndex() {
142 stop();
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000143 for (auto &Thread : ThreadPool)
144 Thread.join();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000145}
146
147void BackgroundIndex::stop() {
148 {
149 std::lock_guard<std::mutex> Lock(QueueMu);
150 ShouldStop = true;
151 }
152 QueueCV.notify_all();
153}
154
155void BackgroundIndex::run() {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000156 WithContext Background(BackgroundContext.clone());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000157 while (true) {
Sam McCallc008af62018-10-20 15:30:37 +0000158 Optional<Task> Task;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000159 {
160 std::unique_lock<std::mutex> Lock(QueueMu);
161 QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); });
162 if (ShouldStop) {
163 Queue.clear();
164 QueueCV.notify_all();
165 return;
166 }
167 ++NumActiveTasks;
168 Task = std::move(Queue.front());
169 Queue.pop_front();
170 }
171 (*Task)();
172 {
173 std::unique_lock<std::mutex> Lock(QueueMu);
174 assert(NumActiveTasks > 0 && "before decrementing");
175 --NumActiveTasks;
176 }
177 QueueCV.notify_all();
178 }
179}
180
181void BackgroundIndex::blockUntilIdleForTest() {
182 std::unique_lock<std::mutex> Lock(QueueMu);
183 QueueCV.wait(Lock, [&] { return Queue.empty() && NumActiveTasks == 0; });
184}
185
186void BackgroundIndex::enqueue(StringRef Directory,
187 tooling::CompileCommand Cmd) {
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000188 auto IndexStorage = BackgroundIndexStorage::getForDirectory(Directory);
189 if (IndexStorage)
190 loadShard(IndexStorage.get(), Cmd);
191 else
192 elog("No index storage for: {0}", Directory);
Sam McCallbca624a2018-10-16 09:05:13 +0000193 {
194 std::lock_guard<std::mutex> Lock(QueueMu);
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000195 enqueueLocked(std::move(Cmd), std::move(IndexStorage));
Sam McCallbca624a2018-10-16 09:05:13 +0000196 }
197 QueueCV.notify_all();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000198}
199
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000200void BackgroundIndex::loadShard(BackgroundIndexStorage *IndexStorage,
201 const tooling::CompileCommand &Cmd) {
202 assert(IndexStorage && "No index storage to load from?");
203 auto AbsolutePath = getAbsolutePath(Cmd);
204 auto Shard = IndexStorage->retrieveShard(AbsolutePath);
205 if (Shard) {
206 // FIXME: Updated hashes once we have them in serialized format.
207 // IndexedFileDigests[AbsolutePath] = Hash;
208 IndexedSymbols.update(AbsolutePath,
209 make_unique<SymbolSlab>(std::move(*Shard->Symbols)),
210 make_unique<RefSlab>(std::move(*Shard->Refs)));
211
212 vlog("Loaded {0} from storage", AbsolutePath);
213 }
214}
215
216void BackgroundIndex::loadShards(
217 BackgroundIndexStorage *IndexStorage,
218 const std::vector<tooling::CompileCommand> &Cmds) {
219 assert(IndexStorage && "No index storage to load from?");
220 for (const auto &Cmd : Cmds)
221 loadShard(IndexStorage, Cmd);
222 // FIXME: Maybe we should get rid of this one once we start building index
223 // periodically? Especially if we also offload this task onto the queue.
224 vlog("Rebuilding automatic index");
225 reset(IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge,
226 URISchemes));
227}
228
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000229void BackgroundIndex::enqueueAll(StringRef Directory,
230 const tooling::CompilationDatabase &CDB) {
231 trace::Span Tracer("BackgroundIndexEnqueueCDB");
232 // FIXME: this function may be slow. Perhaps enqueue a task to re-read the CDB
233 // from disk and enqueue the commands asynchronously?
234 auto Cmds = CDB.getAllCompileCommands();
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000235 auto IndexStorage = BackgroundIndexStorage::getForDirectory(Directory);
236 if (IndexStorage)
237 loadShards(IndexStorage.get(), Cmds);
238 else
239 elog("No index storage for: {0}", Directory);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000240 SPAN_ATTACH(Tracer, "commands", int64_t(Cmds.size()));
241 std::mt19937 Generator(std::random_device{}());
242 std::shuffle(Cmds.begin(), Cmds.end(), Generator);
243 log("Enqueueing {0} commands for indexing from {1}", Cmds.size(), Directory);
244 {
245 std::lock_guard<std::mutex> Lock(QueueMu);
246 for (auto &Cmd : Cmds)
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000247 enqueueLocked(std::move(Cmd), IndexStorage);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000248 }
249 QueueCV.notify_all();
250}
251
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000252void BackgroundIndex::enqueueLocked(
253 tooling::CompileCommand Cmd,
254 std::shared_ptr<BackgroundIndexStorage> IndexStorage) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000255 Queue.push_back(Bind(
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000256 [this](tooling::CompileCommand Cmd,
257 std::shared_ptr<BackgroundIndexStorage> IndexStorage) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000258 std::string Filename = Cmd.Filename;
259 Cmd.CommandLine.push_back("-resource-dir=" + ResourceDir);
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000260 if (auto Error = index(std::move(Cmd), IndexStorage.get()))
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000261 log("Indexing {0} failed: {1}", Filename, std::move(Error));
262 },
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000263 std::move(Cmd), std::move(IndexStorage)));
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000264}
265
Eric Liuad588af2018-11-06 10:55:21 +0000266// Resolves URI to file paths with cache.
267class URIToFileCache {
268public:
269 URIToFileCache(llvm::StringRef HintPath) : HintPath(HintPath) {}
270
271 llvm::StringRef resolve(llvm::StringRef FileURI) {
272 auto I = URIToPathCache.try_emplace(FileURI);
273 if (I.second) {
274 auto U = URI::parse(FileURI);
275 if (!U) {
276 elog("Failed to parse URI {0}: {1}", FileURI, U.takeError());
277 assert(false && "Failed to parse URI");
278 return "";
279 }
280 auto Path = URI::resolve(*U, HintPath);
281 if (!Path) {
282 elog("Failed to resolve URI {0}: {1}", FileURI, Path.takeError());
283 assert(false && "Failed to resolve URI");
284 return "";
285 }
286 I.first->second = *Path;
287 }
288 return I.first->second;
289 }
290
291private:
292 std::string HintPath;
293 llvm::StringMap<std::string> URIToPathCache;
294};
295
296/// Given index results from a TU, only update files in \p FilesToUpdate.
297void BackgroundIndex::update(StringRef MainFile, SymbolSlab Symbols,
298 RefSlab Refs,
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000299 const StringMap<FileDigest> &FilesToUpdate,
300 BackgroundIndexStorage *IndexStorage) {
Eric Liuad588af2018-11-06 10:55:21 +0000301 // Partition symbols/references into files.
302 struct File {
303 DenseSet<const Symbol *> Symbols;
304 DenseSet<const Ref *> Refs;
305 };
306 StringMap<File> Files;
307 URIToFileCache URICache(MainFile);
308 for (const auto &Sym : Symbols) {
309 if (Sym.CanonicalDeclaration) {
310 auto DeclPath = URICache.resolve(Sym.CanonicalDeclaration.FileURI);
311 if (FilesToUpdate.count(DeclPath) != 0)
312 Files[DeclPath].Symbols.insert(&Sym);
313 }
314 // For symbols with different declaration and definition locations, we store
315 // the full symbol in both the header file and the implementation file, so
316 // that merging can tell the preferred symbols (from canonical headers) from
317 // other symbols (e.g. forward declarations).
318 if (Sym.Definition &&
319 Sym.Definition.FileURI != Sym.CanonicalDeclaration.FileURI) {
320 auto DefPath = URICache.resolve(Sym.Definition.FileURI);
321 if (FilesToUpdate.count(DefPath) != 0)
322 Files[DefPath].Symbols.insert(&Sym);
323 }
324 }
325 DenseMap<const Ref *, SymbolID> RefToIDs;
326 for (const auto &SymRefs : Refs) {
327 for (const auto &R : SymRefs.second) {
328 auto Path = URICache.resolve(R.Location.FileURI);
329 if (FilesToUpdate.count(Path) != 0) {
330 auto &F = Files[Path];
331 RefToIDs[&R] = SymRefs.first;
332 F.Refs.insert(&R);
333 }
334 }
335 }
336
337 // Build and store new slabs for each updated file.
338 for (const auto &F : Files) {
339 StringRef Path = F.first();
340 vlog("Update symbols in {0}", Path);
341 SymbolSlab::Builder Syms;
342 RefSlab::Builder Refs;
343 for (const auto *S : F.second.Symbols)
344 Syms.insert(*S);
345 for (const auto *R : F.second.Refs)
346 Refs.insert(RefToIDs[R], *R);
347
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000348 auto SS = llvm::make_unique<SymbolSlab>(std::move(Syms).build());
349 auto RS = llvm::make_unique<RefSlab>(std::move(Refs).build());
350
351 auto Hash = FilesToUpdate.lookup(Path);
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000352 // We need to store shards before updating the index, since the latter
353 // consumes slabs.
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000354 // FIXME: Store Hash in the Shard.
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000355 if (IndexStorage) {
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000356 IndexFileOut Shard;
357 Shard.Symbols = SS.get();
358 Shard.Refs = RS.get();
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000359 IndexStorage->storeShard(Path, Shard);
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000360 }
361
Eric Liuad588af2018-11-06 10:55:21 +0000362 std::lock_guard<std::mutex> Lock(DigestsMu);
363 // This can override a newer version that is added in another thread,
364 // if this thread sees the older version but finishes later. This should be
365 // rare in practice.
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000366 IndexedFileDigests[Path] = Hash;
367 IndexedSymbols.update(Path, std::move(SS), std::move(RS));
Eric Liuad588af2018-11-06 10:55:21 +0000368 }
369}
370
371// Creates a filter to not collect index results from files with unchanged
372// digests.
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000373// \p FileDigests contains file digests for the current indexed files, and all
374// changed files will be added to \p FilesToUpdate.
Eric Liuad588af2018-11-06 10:55:21 +0000375decltype(SymbolCollector::Options::FileFilter) createFileFilter(
376 const llvm::StringMap<BackgroundIndex::FileDigest> &FileDigests,
377 llvm::StringMap<BackgroundIndex::FileDigest> &FilesToUpdate) {
378 return [&FileDigests, &FilesToUpdate](const SourceManager &SM, FileID FID) {
379 StringRef Path;
380 if (const auto *F = SM.getFileEntryForID(FID))
381 Path = F->getName();
382 if (Path.empty())
383 return false; // Skip invalid files.
384 SmallString<128> AbsPath(Path);
385 if (std::error_code EC =
386 SM.getFileManager().getVirtualFileSystem()->makeAbsolute(AbsPath)) {
387 elog("Warning: could not make absolute file: {0}", EC.message());
388 return false; // Skip files without absolute path.
389 }
390 sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);
391 auto Digest = digestFile(SM, FID);
392 if (!Digest)
393 return false;
394 auto D = FileDigests.find(AbsPath);
395 if (D != FileDigests.end() && D->second == Digest)
396 return false; // Skip files that haven't changed.
397
398 FilesToUpdate[AbsPath] = *Digest;
399 return true;
400 };
401}
402
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000403Error BackgroundIndex::index(tooling::CompileCommand Cmd,
404 BackgroundIndexStorage *IndexStorage) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000405 trace::Span Tracer("BackgroundIndex");
406 SPAN_ATTACH(Tracer, "file", Cmd.Filename);
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000407 SmallString<128> AbsolutePath = getAbsolutePath(Cmd);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000408
409 auto FS = FSProvider.getFileSystem();
410 auto Buf = FS->getBufferForFile(AbsolutePath);
411 if (!Buf)
412 return errorCodeToError(Buf.getError());
Eric Liuad588af2018-11-06 10:55:21 +0000413 auto Hash = digest(Buf->get()->getBuffer());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000414
Eric Liuad588af2018-11-06 10:55:21 +0000415 // Take a snapshot of the digests to avoid locking for each file in the TU.
416 llvm::StringMap<FileDigest> DigestsSnapshot;
417 {
418 std::lock_guard<std::mutex> Lock(DigestsMu);
419 if (IndexedFileDigests.lookup(AbsolutePath) == Hash) {
420 vlog("No need to index {0}, already up to date", AbsolutePath);
421 return Error::success();
422 }
423
424 DigestsSnapshot = IndexedFileDigests;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000425 }
426
427 log("Indexing {0}", Cmd.Filename, toHex(Hash));
428 ParseInputs Inputs;
429 Inputs.FS = std::move(FS);
430 Inputs.FS->setCurrentWorkingDirectory(Cmd.Directory);
431 Inputs.CompileCommand = std::move(Cmd);
432 auto CI = buildCompilerInvocation(Inputs);
433 if (!CI)
Sam McCallc008af62018-10-20 15:30:37 +0000434 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000435 "Couldn't build compiler invocation");
436 IgnoreDiagnostics IgnoreDiags;
437 auto Clang = prepareCompilerInstance(
438 std::move(CI), /*Preamble=*/nullptr, std::move(*Buf),
439 std::make_shared<PCHContainerOperations>(), Inputs.FS, IgnoreDiags);
440 if (!Clang)
Sam McCallc008af62018-10-20 15:30:37 +0000441 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000442 "Couldn't build compiler instance");
443
444 SymbolCollector::Options IndexOpts;
Eric Liuad588af2018-11-06 10:55:21 +0000445 IndexOpts.URISchemes = URISchemes;
446 StringMap<FileDigest> FilesToUpdate;
447 IndexOpts.FileFilter = createFileFilter(DigestsSnapshot, FilesToUpdate);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000448 SymbolSlab Symbols;
449 RefSlab Refs;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000450 auto Action = createStaticIndexingAction(
451 IndexOpts, [&](SymbolSlab S) { Symbols = std::move(S); },
452 [&](RefSlab R) { Refs = std::move(R); });
453
454 // We're going to run clang here, and it could potentially crash.
455 // We could use CrashRecoveryContext to try to make indexing crashes nonfatal,
456 // but the leaky "recovery" is pretty scary too in a long-running process.
457 // If crashes are a real problem, maybe we should fork a child process.
458
459 const FrontendInputFile &Input = Clang->getFrontendOpts().Inputs.front();
460 if (!Action->BeginSourceFile(*Clang, Input))
Sam McCallc008af62018-10-20 15:30:37 +0000461 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000462 "BeginSourceFile() failed");
463 if (!Action->Execute())
Sam McCallc008af62018-10-20 15:30:37 +0000464 return createStringError(inconvertibleErrorCode(), "Execute() failed");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000465 Action->EndSourceFile();
466
467 log("Indexed {0} ({1} symbols, {2} refs)", Inputs.CompileCommand.Filename,
Haojian Wu6ece6e72018-10-18 15:33:20 +0000468 Symbols.size(), Refs.numRefs());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000469 SPAN_ATTACH(Tracer, "symbols", int(Symbols.size()));
Haojian Wu6ece6e72018-10-18 15:33:20 +0000470 SPAN_ATTACH(Tracer, "refs", int(Refs.numRefs()));
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000471 update(AbsolutePath, std::move(Symbols), std::move(Refs), FilesToUpdate,
472 IndexStorage);
Eric Liuad588af2018-11-06 10:55:21 +0000473 {
474 // Make sure hash for the main file is always updated even if there is no
475 // index data in it.
476 std::lock_guard<std::mutex> Lock(DigestsMu);
477 IndexedFileDigests[AbsolutePath] = Hash;
478 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000479
480 // FIXME: this should rebuild once-in-a-while, not after every file.
481 // At that point we should use Dex, too.
482 vlog("Rebuilding automatic index");
Eric Liuad588af2018-11-06 10:55:21 +0000483 reset(IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge,
484 URISchemes));
485
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000486 return Error::success();
487}
488
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000489std::function<std::shared_ptr<BackgroundIndexStorage>(llvm::StringRef)>
490 BackgroundIndexStorage::Factory = nullptr;
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000491
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000492} // namespace clangd
493} // namespace clang