blob: 94708d6217ad90eb7433b360a484242a553507c5 [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
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000051std::string getShardPathFromFilePath(llvm::StringRef ShardRoot,
52 llvm::StringRef FilePath) {
53 llvm::SmallString<128> ShardRootSS(ShardRoot);
54 sys::path::append(ShardRootSS, sys::path::filename(FilePath) +
55 toHex(digest(FilePath)) + ".idx");
56 return ShardRoot.str();
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +000057}
58
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000059// Uses disk as a storage for index shards. Creates a directory called
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000060// ".clangd-index/" under the path provided during construction.
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000061// This class is thread-safe.
62class DiskBackedIndexStorage : public BackgroundIndexStorage {
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000063 std::string DiskShardRoot;
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000064
65public:
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000066 llvm::Expected<IndexFileIn> loadShard(llvm::StringRef ShardIdentifier) const {
67 const std::string ShardPath =
68 getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000069 auto Buffer = MemoryBuffer::getFile(ShardPath);
70 if (!Buffer) {
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000071 elog("Couldn't load {0}: {1}", ShardPath, Buffer.getError().message());
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000072 return llvm::make_error<llvm::StringError>(Buffer.getError());
73 }
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000074 return readIndexFile(Buffer->get()->getBuffer());
75 }
76
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000077 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
78 IndexFileOut Shard) const override {
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000079 auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
80 std::error_code EC;
81 llvm::raw_fd_ostream OS(ShardPath, EC);
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000082 if (EC)
83 return errorCodeToError(EC);
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000084 OS << Shard;
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000085 return llvm::Error::success();
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000086 }
87
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +000088 // Sets DiskShardRoot to (Directory + ".clangd-index/") which is the base
89 // directory for all shard files.
90 DiskBackedIndexStorage(llvm::StringRef Directory) {
91 llvm::SmallString<128> CDBDirectory(Directory);
92 sys::path::append(CDBDirectory, ".clangd-index/");
93 DiskShardRoot = CDBDirectory.str();
Kadir Cetinkaya89a76912018-11-15 10:31:19 +000094 if (!llvm::sys::fs::exists(DiskShardRoot)) {
95 std::error_code OK;
96 std::error_code EC = llvm::sys::fs::create_directory(DiskShardRoot);
97 if (EC != OK) {
98 elog("Failed to create {0}: {1}", DiskShardRoot, EC.message());
99 }
100 }
101 }
102};
103
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000104std::string getAbsoluteFilePath(const tooling::CompileCommand &Cmd) {
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000105 SmallString<128> AbsolutePath;
106 if (sys::path::is_absolute(Cmd.Filename)) {
107 AbsolutePath = Cmd.Filename;
108 } else {
109 AbsolutePath = Cmd.Directory;
110 sys::path::append(AbsolutePath, Cmd.Filename);
111 }
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000112 return AbsolutePath.str();
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000113}
114
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000115} // namespace
116
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000117BackgroundIndex::BackgroundIndex(Context BackgroundContext,
118 StringRef ResourceDir,
119 const FileSystemProvider &FSProvider,
120 ArrayRef<std::string> URISchemes,
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000121 IndexStorageFactory IndexStorageCreator,
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000122 size_t ThreadPoolSize)
Sam McCallc008af62018-10-20 15:30:37 +0000123 : SwapIndex(make_unique<MemIndex>()), ResourceDir(ResourceDir),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000124 FSProvider(FSProvider), BackgroundContext(std::move(BackgroundContext)),
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000125 URISchemes(URISchemes),
126 IndexStorageCreator(std::move(IndexStorageCreator)) {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000127 assert(ThreadPoolSize > 0 && "Thread pool size can't be zero.");
128 while (ThreadPoolSize--) {
129 ThreadPool.emplace_back([this] { run(); });
130 // Set priority to low, since background indexing is a long running task we
131 // do not want to eat up cpu when there are any other high priority threads.
132 // FIXME: In the future we might want a more general way of handling this to
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000133 // support tasks with various priorities.
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000134 setThreadPriority(ThreadPool.back(), ThreadPriority::Low);
135 }
136}
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000137
138BackgroundIndex::~BackgroundIndex() {
139 stop();
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000140 for (auto &Thread : ThreadPool)
141 Thread.join();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000142}
143
144void BackgroundIndex::stop() {
145 {
146 std::lock_guard<std::mutex> Lock(QueueMu);
147 ShouldStop = true;
148 }
149 QueueCV.notify_all();
150}
151
152void BackgroundIndex::run() {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000153 WithContext Background(BackgroundContext.clone());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000154 while (true) {
Sam McCallc008af62018-10-20 15:30:37 +0000155 Optional<Task> Task;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000156 {
157 std::unique_lock<std::mutex> Lock(QueueMu);
158 QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); });
159 if (ShouldStop) {
160 Queue.clear();
161 QueueCV.notify_all();
162 return;
163 }
164 ++NumActiveTasks;
165 Task = std::move(Queue.front());
166 Queue.pop_front();
167 }
168 (*Task)();
169 {
170 std::unique_lock<std::mutex> Lock(QueueMu);
171 assert(NumActiveTasks > 0 && "before decrementing");
172 --NumActiveTasks;
173 }
174 QueueCV.notify_all();
175 }
176}
177
178void BackgroundIndex::blockUntilIdleForTest() {
179 std::unique_lock<std::mutex> Lock(QueueMu);
180 QueueCV.wait(Lock, [&] { return Queue.empty() && NumActiveTasks == 0; });
181}
182
183void BackgroundIndex::enqueue(StringRef Directory,
184 tooling::CompileCommand Cmd) {
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000185 BackgroundIndexStorage *IndexStorage = getIndexStorage(Directory);
186 if (!IndexStorage)
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000187 elog("No index storage for: {0}", Directory);
Sam McCallbca624a2018-10-16 09:05:13 +0000188 {
189 std::lock_guard<std::mutex> Lock(QueueMu);
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000190 enqueueLocked(std::move(Cmd), IndexStorage);
Sam McCallbca624a2018-10-16 09:05:13 +0000191 }
192 QueueCV.notify_all();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000193}
194
195void BackgroundIndex::enqueueAll(StringRef Directory,
196 const tooling::CompilationDatabase &CDB) {
197 trace::Span Tracer("BackgroundIndexEnqueueCDB");
198 // FIXME: this function may be slow. Perhaps enqueue a task to re-read the CDB
199 // from disk and enqueue the commands asynchronously?
200 auto Cmds = CDB.getAllCompileCommands();
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000201 BackgroundIndexStorage *IndexStorage = getIndexStorage(Directory);
202 if (!IndexStorage)
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000203 elog("No index storage for: {0}", Directory);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000204 SPAN_ATTACH(Tracer, "commands", int64_t(Cmds.size()));
205 std::mt19937 Generator(std::random_device{}());
206 std::shuffle(Cmds.begin(), Cmds.end(), Generator);
207 log("Enqueueing {0} commands for indexing from {1}", Cmds.size(), Directory);
208 {
209 std::lock_guard<std::mutex> Lock(QueueMu);
210 for (auto &Cmd : Cmds)
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000211 enqueueLocked(std::move(Cmd), IndexStorage);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000212 }
213 QueueCV.notify_all();
214}
215
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000216void BackgroundIndex::enqueueLocked(tooling::CompileCommand Cmd,
217 BackgroundIndexStorage *IndexStorage) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000218 Queue.push_back(Bind(
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000219 [this, IndexStorage](tooling::CompileCommand Cmd) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000220 std::string Filename = Cmd.Filename;
221 Cmd.CommandLine.push_back("-resource-dir=" + ResourceDir);
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000222 if (auto Error = index(std::move(Cmd), IndexStorage))
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000223 log("Indexing {0} failed: {1}", Filename, std::move(Error));
224 },
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000225 std::move(Cmd)));
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000226}
227
Eric Liuad588af2018-11-06 10:55:21 +0000228// Resolves URI to file paths with cache.
229class URIToFileCache {
230public:
231 URIToFileCache(llvm::StringRef HintPath) : HintPath(HintPath) {}
232
233 llvm::StringRef resolve(llvm::StringRef FileURI) {
234 auto I = URIToPathCache.try_emplace(FileURI);
235 if (I.second) {
236 auto U = URI::parse(FileURI);
237 if (!U) {
238 elog("Failed to parse URI {0}: {1}", FileURI, U.takeError());
239 assert(false && "Failed to parse URI");
240 return "";
241 }
242 auto Path = URI::resolve(*U, HintPath);
243 if (!Path) {
244 elog("Failed to resolve URI {0}: {1}", FileURI, Path.takeError());
245 assert(false && "Failed to resolve URI");
246 return "";
247 }
248 I.first->second = *Path;
249 }
250 return I.first->second;
251 }
252
253private:
254 std::string HintPath;
255 llvm::StringMap<std::string> URIToPathCache;
256};
257
258/// Given index results from a TU, only update files in \p FilesToUpdate.
259void BackgroundIndex::update(StringRef MainFile, SymbolSlab Symbols,
260 RefSlab Refs,
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000261 const StringMap<FileDigest> &FilesToUpdate,
262 BackgroundIndexStorage *IndexStorage) {
Eric Liuad588af2018-11-06 10:55:21 +0000263 // Partition symbols/references into files.
264 struct File {
265 DenseSet<const Symbol *> Symbols;
266 DenseSet<const Ref *> Refs;
267 };
268 StringMap<File> Files;
269 URIToFileCache URICache(MainFile);
270 for (const auto &Sym : Symbols) {
271 if (Sym.CanonicalDeclaration) {
272 auto DeclPath = URICache.resolve(Sym.CanonicalDeclaration.FileURI);
273 if (FilesToUpdate.count(DeclPath) != 0)
274 Files[DeclPath].Symbols.insert(&Sym);
275 }
276 // For symbols with different declaration and definition locations, we store
277 // the full symbol in both the header file and the implementation file, so
278 // that merging can tell the preferred symbols (from canonical headers) from
279 // other symbols (e.g. forward declarations).
280 if (Sym.Definition &&
281 Sym.Definition.FileURI != Sym.CanonicalDeclaration.FileURI) {
282 auto DefPath = URICache.resolve(Sym.Definition.FileURI);
283 if (FilesToUpdate.count(DefPath) != 0)
284 Files[DefPath].Symbols.insert(&Sym);
285 }
286 }
287 DenseMap<const Ref *, SymbolID> RefToIDs;
288 for (const auto &SymRefs : Refs) {
289 for (const auto &R : SymRefs.second) {
290 auto Path = URICache.resolve(R.Location.FileURI);
291 if (FilesToUpdate.count(Path) != 0) {
292 auto &F = Files[Path];
293 RefToIDs[&R] = SymRefs.first;
294 F.Refs.insert(&R);
295 }
296 }
297 }
298
299 // Build and store new slabs for each updated file.
300 for (const auto &F : Files) {
301 StringRef Path = F.first();
302 vlog("Update symbols in {0}", Path);
303 SymbolSlab::Builder Syms;
304 RefSlab::Builder Refs;
305 for (const auto *S : F.second.Symbols)
306 Syms.insert(*S);
307 for (const auto *R : F.second.Refs)
308 Refs.insert(RefToIDs[R], *R);
309
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000310 auto SS = llvm::make_unique<SymbolSlab>(std::move(Syms).build());
311 auto RS = llvm::make_unique<RefSlab>(std::move(Refs).build());
312
313 auto Hash = FilesToUpdate.lookup(Path);
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000314 // We need to store shards before updating the index, since the latter
315 // consumes slabs.
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000316 // FIXME: Store Hash in the Shard.
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000317 if (IndexStorage) {
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000318 IndexFileOut Shard;
319 Shard.Symbols = SS.get();
320 Shard.Refs = RS.get();
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000321 if (auto Error = IndexStorage->storeShard(Path, Shard))
322 elog("Failed to store shard for {0}: {1}", Path, std::move(Error));
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000323 }
324
Eric Liuad588af2018-11-06 10:55:21 +0000325 std::lock_guard<std::mutex> Lock(DigestsMu);
326 // This can override a newer version that is added in another thread,
327 // if this thread sees the older version but finishes later. This should be
328 // rare in practice.
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000329 IndexedFileDigests[Path] = Hash;
330 IndexedSymbols.update(Path, std::move(SS), std::move(RS));
Eric Liuad588af2018-11-06 10:55:21 +0000331 }
332}
333
334// Creates a filter to not collect index results from files with unchanged
335// digests.
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000336// \p FileDigests contains file digests for the current indexed files, and all
337// changed files will be added to \p FilesToUpdate.
Eric Liuad588af2018-11-06 10:55:21 +0000338decltype(SymbolCollector::Options::FileFilter) createFileFilter(
339 const llvm::StringMap<BackgroundIndex::FileDigest> &FileDigests,
340 llvm::StringMap<BackgroundIndex::FileDigest> &FilesToUpdate) {
341 return [&FileDigests, &FilesToUpdate](const SourceManager &SM, FileID FID) {
342 StringRef Path;
343 if (const auto *F = SM.getFileEntryForID(FID))
344 Path = F->getName();
345 if (Path.empty())
346 return false; // Skip invalid files.
347 SmallString<128> AbsPath(Path);
348 if (std::error_code EC =
349 SM.getFileManager().getVirtualFileSystem()->makeAbsolute(AbsPath)) {
350 elog("Warning: could not make absolute file: {0}", EC.message());
351 return false; // Skip files without absolute path.
352 }
353 sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);
354 auto Digest = digestFile(SM, FID);
355 if (!Digest)
356 return false;
357 auto D = FileDigests.find(AbsPath);
358 if (D != FileDigests.end() && D->second == Digest)
359 return false; // Skip files that haven't changed.
360
361 FilesToUpdate[AbsPath] = *Digest;
362 return true;
363 };
364}
365
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000366Error BackgroundIndex::index(tooling::CompileCommand Cmd,
367 BackgroundIndexStorage *IndexStorage) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000368 trace::Span Tracer("BackgroundIndex");
369 SPAN_ATTACH(Tracer, "file", Cmd.Filename);
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000370 const std::string AbsolutePath = getAbsoluteFilePath(Cmd);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000371
372 auto FS = FSProvider.getFileSystem();
373 auto Buf = FS->getBufferForFile(AbsolutePath);
374 if (!Buf)
375 return errorCodeToError(Buf.getError());
Eric Liuad588af2018-11-06 10:55:21 +0000376 auto Hash = digest(Buf->get()->getBuffer());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000377
Eric Liuad588af2018-11-06 10:55:21 +0000378 // Take a snapshot of the digests to avoid locking for each file in the TU.
379 llvm::StringMap<FileDigest> DigestsSnapshot;
380 {
381 std::lock_guard<std::mutex> Lock(DigestsMu);
382 if (IndexedFileDigests.lookup(AbsolutePath) == Hash) {
383 vlog("No need to index {0}, already up to date", AbsolutePath);
384 return Error::success();
385 }
386
387 DigestsSnapshot = IndexedFileDigests;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000388 }
389
390 log("Indexing {0}", Cmd.Filename, toHex(Hash));
391 ParseInputs Inputs;
392 Inputs.FS = std::move(FS);
393 Inputs.FS->setCurrentWorkingDirectory(Cmd.Directory);
394 Inputs.CompileCommand = std::move(Cmd);
395 auto CI = buildCompilerInvocation(Inputs);
396 if (!CI)
Sam McCallc008af62018-10-20 15:30:37 +0000397 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000398 "Couldn't build compiler invocation");
399 IgnoreDiagnostics IgnoreDiags;
400 auto Clang = prepareCompilerInstance(
401 std::move(CI), /*Preamble=*/nullptr, std::move(*Buf),
402 std::make_shared<PCHContainerOperations>(), Inputs.FS, IgnoreDiags);
403 if (!Clang)
Sam McCallc008af62018-10-20 15:30:37 +0000404 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000405 "Couldn't build compiler instance");
406
407 SymbolCollector::Options IndexOpts;
Eric Liuad588af2018-11-06 10:55:21 +0000408 IndexOpts.URISchemes = URISchemes;
409 StringMap<FileDigest> FilesToUpdate;
410 IndexOpts.FileFilter = createFileFilter(DigestsSnapshot, FilesToUpdate);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000411 SymbolSlab Symbols;
412 RefSlab Refs;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000413 auto Action = createStaticIndexingAction(
414 IndexOpts, [&](SymbolSlab S) { Symbols = std::move(S); },
415 [&](RefSlab R) { Refs = std::move(R); });
416
417 // We're going to run clang here, and it could potentially crash.
418 // We could use CrashRecoveryContext to try to make indexing crashes nonfatal,
419 // but the leaky "recovery" is pretty scary too in a long-running process.
420 // If crashes are a real problem, maybe we should fork a child process.
421
422 const FrontendInputFile &Input = Clang->getFrontendOpts().Inputs.front();
423 if (!Action->BeginSourceFile(*Clang, Input))
Sam McCallc008af62018-10-20 15:30:37 +0000424 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000425 "BeginSourceFile() failed");
426 if (!Action->Execute())
Sam McCallc008af62018-10-20 15:30:37 +0000427 return createStringError(inconvertibleErrorCode(), "Execute() failed");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000428 Action->EndSourceFile();
429
430 log("Indexed {0} ({1} symbols, {2} refs)", Inputs.CompileCommand.Filename,
Haojian Wu6ece6e72018-10-18 15:33:20 +0000431 Symbols.size(), Refs.numRefs());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000432 SPAN_ATTACH(Tracer, "symbols", int(Symbols.size()));
Haojian Wu6ece6e72018-10-18 15:33:20 +0000433 SPAN_ATTACH(Tracer, "refs", int(Refs.numRefs()));
Kadir Cetinkaya89a76912018-11-15 10:31:19 +0000434 update(AbsolutePath, std::move(Symbols), std::move(Refs), FilesToUpdate,
435 IndexStorage);
Eric Liuad588af2018-11-06 10:55:21 +0000436 {
437 // Make sure hash for the main file is always updated even if there is no
438 // index data in it.
439 std::lock_guard<std::mutex> Lock(DigestsMu);
440 IndexedFileDigests[AbsolutePath] = Hash;
441 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000442
443 // FIXME: this should rebuild once-in-a-while, not after every file.
444 // At that point we should use Dex, too.
445 vlog("Rebuilding automatic index");
Eric Liuad588af2018-11-06 10:55:21 +0000446 reset(IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge,
447 URISchemes));
448
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000449 return Error::success();
450}
451
Kadir Cetinkaya2bed2cf2018-11-15 10:31:23 +0000452BackgroundIndexStorage *
453BackgroundIndex::getIndexStorage(llvm::StringRef CDBDirectory) {
454 if (!IndexStorageCreator)
455 return nullptr;
456 auto IndexStorageIt = IndexStorageMap.find(CDBDirectory);
457 if (IndexStorageIt == IndexStorageMap.end())
458 IndexStorageIt =
459 IndexStorageMap
460 .insert({CDBDirectory, IndexStorageCreator(CDBDirectory)})
461 .first;
462 return IndexStorageIt->second.get();
463}
Kadir Cetinkaya3e5a4752018-11-15 10:31:10 +0000464
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000465} // namespace clangd
466} // namespace clang