blob: 5db2d39f631a531eb27cb4300ca6d0be47e55313 [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 Cetinkayad08eab42018-11-27 16:08:53 +000014#include "SourceCode.h"
Kadir Cetinkaya6675be82018-10-30 12:13:27 +000015#include "Threading.h"
Sam McCall8dc9dbb2018-10-15 13:34:10 +000016#include "Trace.h"
Eric Liuad588af2018-11-06 10:55:21 +000017#include "URI.h"
Sam McCall8dc9dbb2018-10-15 13:34:10 +000018#include "index/IndexAction.h"
19#include "index/MemIndex.h"
20#include "index/Serialization.h"
Eric Liuad588af2018-11-06 10:55:21 +000021#include "index/SymbolCollector.h"
22#include "clang/Basic/SourceLocation.h"
23#include "clang/Basic/SourceManager.h"
24#include "llvm/ADT/STLExtras.h"
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +000025#include "llvm/ADT/ScopeExit.h"
Eric Liuad588af2018-11-06 10:55:21 +000026#include "llvm/ADT/StringMap.h"
27#include "llvm/ADT/StringRef.h"
Sam McCall8dc9dbb2018-10-15 13:34:10 +000028#include "llvm/Support/SHA1.h"
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +000029
Eric Liu667e8ef2018-12-18 15:39:33 +000030#include <chrono>
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +000031#include <memory>
Sam McCall7d0e4842018-11-26 13:35:02 +000032#include <numeric>
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +000033#include <queue>
Sam McCall8dc9dbb2018-10-15 13:34:10 +000034#include <random>
Eric Liuad588af2018-11-06 10:55:21 +000035#include <string>
Eric Liu667e8ef2018-12-18 15:39:33 +000036#include <thread>
Sam McCall8dc9dbb2018-10-15 13:34:10 +000037
38using namespace llvm;
39namespace clang {
40namespace clangd {
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +000041namespace {
42// Resolves URI to file paths with cache.
43class URIToFileCache {
44public:
45 URIToFileCache(llvm::StringRef HintPath) : HintPath(HintPath) {}
46
47 llvm::StringRef resolve(llvm::StringRef FileURI) {
48 auto I = URIToPathCache.try_emplace(FileURI);
49 if (I.second) {
50 auto U = URI::parse(FileURI);
51 if (!U) {
52 elog("Failed to parse URI {0}: {1}", FileURI, U.takeError());
53 assert(false && "Failed to parse URI");
54 return "";
55 }
56 auto Path = URI::resolve(*U, HintPath);
57 if (!Path) {
58 elog("Failed to resolve URI {0}: {1}", FileURI, Path.takeError());
59 assert(false && "Failed to resolve URI");
60 return "";
61 }
62 I.first->second = *Path;
63 }
64 return I.first->second;
65 }
66
67private:
68 std::string HintPath;
69 llvm::StringMap<std::string> URIToPathCache;
70};
71
72// We keep only the node "U" and its edges. Any node other than "U" will be
73// empty in the resultant graph.
74IncludeGraph getSubGraph(const URI &U, const IncludeGraph &FullGraph) {
75 IncludeGraph IG;
76
77 std::string FileURI = U.toString();
78 auto Entry = IG.try_emplace(FileURI).first;
79 auto &Node = Entry->getValue();
80 Node = FullGraph.lookup(Entry->getKey());
81 Node.URI = Entry->getKey();
82
83 // URIs inside nodes must point into the keys of the same IncludeGraph.
84 for (auto &Include : Node.DirectIncludes) {
85 auto I = IG.try_emplace(Include).first;
86 I->getValue().URI = I->getKey();
87 Include = I->getKey();
88 }
89
90 return IG;
91}
Haojian Wu9d0d9f82018-12-13 13:07:29 +000092
93// Creates a filter to not collect index results from files with unchanged
94// digests.
95// \p FileDigests contains file digests for the current indexed files, and all
96// changed files will be added to \p FilesToUpdate.
97decltype(SymbolCollector::Options::FileFilter)
98createFileFilter(const llvm::StringMap<FileDigest> &FileDigests,
99 llvm::StringMap<FileDigest> &FilesToUpdate) {
100 return [&FileDigests, &FilesToUpdate](const SourceManager &SM, FileID FID) {
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000101 const auto *F = SM.getFileEntryForID(FID);
102 if (!F)
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000103 return false; // Skip invalid files.
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000104 auto AbsPath = getCanonicalPath(F, SM);
105 if (!AbsPath)
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000106 return false; // Skip files without absolute path.
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000107 auto Digest = digestFile(SM, FID);
108 if (!Digest)
109 return false;
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000110 auto D = FileDigests.find(*AbsPath);
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000111 if (D != FileDigests.end() && D->second == Digest)
112 return false; // Skip files that haven't changed.
113
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000114 FilesToUpdate[*AbsPath] = *Digest;
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000115 return true;
116 };
117}
118
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000119} // namespace
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000120
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000121BackgroundIndex::BackgroundIndex(
122 Context BackgroundContext, StringRef ResourceDir,
Sam McCall6e2d2a32018-11-26 09:51:50 +0000123 const FileSystemProvider &FSProvider, const GlobalCompilationDatabase &CDB,
Eric Liu667e8ef2018-12-18 15:39:33 +0000124 BackgroundIndexStorage::Factory IndexStorageFactory,
125 size_t BuildIndexPeriodMs, size_t ThreadPoolSize)
Sam McCallc008af62018-10-20 15:30:37 +0000126 : SwapIndex(make_unique<MemIndex>()), ResourceDir(ResourceDir),
Sam McCall6e2d2a32018-11-26 09:51:50 +0000127 FSProvider(FSProvider), CDB(CDB),
128 BackgroundContext(std::move(BackgroundContext)),
Eric Liu667e8ef2018-12-18 15:39:33 +0000129 BuildIndexPeriodMs(BuildIndexPeriodMs),
130 SymbolsUpdatedSinceLastIndex(false),
Sam McCall6e2d2a32018-11-26 09:51:50 +0000131 IndexStorageFactory(std::move(IndexStorageFactory)),
132 CommandsChanged(
133 CDB.watch([&](const std::vector<std::string> &ChangedFiles) {
134 enqueue(ChangedFiles);
135 })) {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000136 assert(ThreadPoolSize > 0 && "Thread pool size can't be zero.");
Haojian Wu1bf52c52018-11-16 09:41:14 +0000137 assert(this->IndexStorageFactory && "Storage factory can not be null!");
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000138 while (ThreadPoolSize--)
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000139 ThreadPool.emplace_back([this] { run(); });
Eric Liu667e8ef2018-12-18 15:39:33 +0000140 if (BuildIndexPeriodMs > 0) {
141 log("BackgroundIndex: build symbol index periodically every {0} ms.",
142 BuildIndexPeriodMs);
143 ThreadPool.emplace_back([this] { buildIndex(); });
144 }
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000145}
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000146
147BackgroundIndex::~BackgroundIndex() {
148 stop();
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000149 for (auto &Thread : ThreadPool)
150 Thread.join();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000151}
152
153void BackgroundIndex::stop() {
154 {
Eric Liu667e8ef2018-12-18 15:39:33 +0000155 std::lock_guard<std::mutex> QueueLock(QueueMu);
156 std::lock_guard<std::mutex> IndexLock(IndexMu);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000157 ShouldStop = true;
158 }
159 QueueCV.notify_all();
Eric Liu667e8ef2018-12-18 15:39:33 +0000160 IndexCV.notify_all();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000161}
162
163void BackgroundIndex::run() {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000164 WithContext Background(BackgroundContext.clone());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000165 while (true) {
Sam McCallc008af62018-10-20 15:30:37 +0000166 Optional<Task> Task;
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000167 ThreadPriority Priority;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000168 {
169 std::unique_lock<std::mutex> Lock(QueueMu);
170 QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); });
171 if (ShouldStop) {
172 Queue.clear();
173 QueueCV.notify_all();
174 return;
175 }
176 ++NumActiveTasks;
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000177 std::tie(Task, Priority) = std::move(Queue.front());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000178 Queue.pop_front();
179 }
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000180
181 if (Priority != ThreadPriority::Normal)
182 setCurrentThreadPriority(Priority);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000183 (*Task)();
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000184 if (Priority != ThreadPriority::Normal)
185 setCurrentThreadPriority(ThreadPriority::Normal);
186
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000187 {
188 std::unique_lock<std::mutex> Lock(QueueMu);
189 assert(NumActiveTasks > 0 && "before decrementing");
190 --NumActiveTasks;
191 }
192 QueueCV.notify_all();
193 }
194}
195
Sam McCall422c8282018-11-26 16:00:11 +0000196bool BackgroundIndex::blockUntilIdleForTest(
197 llvm::Optional<double> TimeoutSeconds) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000198 std::unique_lock<std::mutex> Lock(QueueMu);
Sam McCall422c8282018-11-26 16:00:11 +0000199 return wait(Lock, QueueCV, timeoutSeconds(TimeoutSeconds),
200 [&] { return Queue.empty() && NumActiveTasks == 0; });
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000201}
202
Sam McCall6e2d2a32018-11-26 09:51:50 +0000203void BackgroundIndex::enqueue(const std::vector<std::string> &ChangedFiles) {
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000204 enqueueTask(
205 [this, ChangedFiles] {
206 trace::Span Tracer("BackgroundIndexEnqueue");
207 // We're doing this asynchronously, because we'll read shards here too.
208 // FIXME: read shards here too.
Sam McCall6e2d2a32018-11-26 09:51:50 +0000209
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000210 log("Enqueueing {0} commands for indexing", ChangedFiles.size());
211 SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size()));
Sam McCall6e2d2a32018-11-26 09:51:50 +0000212
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000213 // We shuffle the files because processing them in a random order should
214 // quickly give us good coverage of headers in the project.
215 std::vector<unsigned> Permutation(ChangedFiles.size());
216 std::iota(Permutation.begin(), Permutation.end(), 0);
217 std::mt19937 Generator(std::random_device{}());
218 std::shuffle(Permutation.begin(), Permutation.end(), Generator);
Sam McCall6e2d2a32018-11-26 09:51:50 +0000219
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000220 for (const unsigned I : Permutation)
221 enqueue(ChangedFiles[I]);
222 },
223 ThreadPriority::Normal);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000224}
225
Sam McCall6e2d2a32018-11-26 09:51:50 +0000226void BackgroundIndex::enqueue(const std::string &File) {
227 ProjectInfo Project;
228 if (auto Cmd = CDB.getCompileCommand(File, &Project)) {
229 auto *Storage = IndexStorageFactory(Project.SourceRoot);
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000230 // Set priority to low, since background indexing is a long running
231 // task we do not want to eat up cpu when there are any other high
232 // priority threads.
Sam McCall6e2d2a32018-11-26 09:51:50 +0000233 enqueueTask(Bind(
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000234 [this, File, Storage](tooling::CompileCommand Cmd) {
235 Cmd.CommandLine.push_back("-resource-dir=" + ResourceDir);
236 if (auto Error = index(std::move(Cmd), Storage))
237 log("Indexing {0} failed: {1}", File, std::move(Error));
238 },
239 std::move(*Cmd)),
240 ThreadPriority::Low);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000241 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000242}
243
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000244void BackgroundIndex::enqueueTask(Task T, ThreadPriority Priority) {
Sam McCall6e2d2a32018-11-26 09:51:50 +0000245 {
246 std::lock_guard<std::mutex> Lock(QueueMu);
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000247 auto I = Queue.end();
248 // We first store the tasks with Normal priority in the front of the queue.
249 // Then we store low priority tasks. Normal priority tasks are pretty rare,
250 // they should not grow beyond single-digit numbers, so it is OK to do
251 // linear search and insert after that.
252 if (Priority == ThreadPriority::Normal) {
253 I = llvm::find_if(Queue, [](const std::pair<Task, ThreadPriority> &Elem) {
254 return Elem.second == ThreadPriority::Low;
255 });
256 }
257 Queue.insert(I, {std::move(T), Priority});
Sam McCall6e2d2a32018-11-26 09:51:50 +0000258 }
259 QueueCV.notify_all();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000260}
261
Eric Liuad588af2018-11-06 10:55:21 +0000262/// Given index results from a TU, only update files in \p FilesToUpdate.
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000263void BackgroundIndex::update(StringRef MainFile, IndexFileIn Index,
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000264 const StringMap<FileDigest> &FilesToUpdate,
265 BackgroundIndexStorage *IndexStorage) {
Eric Liuad588af2018-11-06 10:55:21 +0000266 // Partition symbols/references into files.
267 struct File {
268 DenseSet<const Symbol *> Symbols;
269 DenseSet<const Ref *> Refs;
270 };
271 StringMap<File> Files;
272 URIToFileCache URICache(MainFile);
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000273 for (const auto &Sym : *Index.Symbols) {
Eric Liuad588af2018-11-06 10:55:21 +0000274 if (Sym.CanonicalDeclaration) {
275 auto DeclPath = URICache.resolve(Sym.CanonicalDeclaration.FileURI);
276 if (FilesToUpdate.count(DeclPath) != 0)
277 Files[DeclPath].Symbols.insert(&Sym);
278 }
279 // For symbols with different declaration and definition locations, we store
280 // the full symbol in both the header file and the implementation file, so
281 // that merging can tell the preferred symbols (from canonical headers) from
282 // other symbols (e.g. forward declarations).
283 if (Sym.Definition &&
284 Sym.Definition.FileURI != Sym.CanonicalDeclaration.FileURI) {
285 auto DefPath = URICache.resolve(Sym.Definition.FileURI);
286 if (FilesToUpdate.count(DefPath) != 0)
287 Files[DefPath].Symbols.insert(&Sym);
288 }
289 }
290 DenseMap<const Ref *, SymbolID> RefToIDs;
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000291 for (const auto &SymRefs : *Index.Refs) {
Eric Liuad588af2018-11-06 10:55:21 +0000292 for (const auto &R : SymRefs.second) {
293 auto Path = URICache.resolve(R.Location.FileURI);
294 if (FilesToUpdate.count(Path) != 0) {
295 auto &F = Files[Path];
296 RefToIDs[&R] = SymRefs.first;
297 F.Refs.insert(&R);
298 }
299 }
300 }
301
302 // Build and store new slabs for each updated file.
303 for (const auto &F : Files) {
304 StringRef Path = F.first();
305 vlog("Update symbols in {0}", Path);
306 SymbolSlab::Builder Syms;
307 RefSlab::Builder Refs;
308 for (const auto *S : F.second.Symbols)
309 Syms.insert(*S);
310 for (const auto *R : F.second.Refs)
311 Refs.insert(RefToIDs[R], *R);
312
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000313 auto SS = llvm::make_unique<SymbolSlab>(std::move(Syms).build());
314 auto RS = llvm::make_unique<RefSlab>(std::move(Refs).build());
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000315 auto IG = llvm::make_unique<IncludeGraph>(
316 getSubGraph(URI::create(Path), Index.Sources.getValue()));
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000317
318 auto Hash = FilesToUpdate.lookup(Path);
319 // We need to store shards before updating the index, since the latter
320 // consumes slabs.
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000321 if (IndexStorage) {
322 IndexFileOut Shard;
323 Shard.Symbols = SS.get();
324 Shard.Refs = RS.get();
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000325 Shard.Sources = IG.get();
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000326
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000327 if (auto Error = IndexStorage->storeShard(Path, Shard))
328 elog("Failed to write background-index shard for file {0}: {1}", Path,
329 std::move(Error));
330 }
331
Eric Liuad588af2018-11-06 10:55:21 +0000332 std::lock_guard<std::mutex> Lock(DigestsMu);
333 // This can override a newer version that is added in another thread,
334 // if this thread sees the older version but finishes later. This should be
335 // rare in practice.
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000336 IndexedFileDigests[Path] = Hash;
337 IndexedSymbols.update(Path, std::move(SS), std::move(RS));
Eric Liuad588af2018-11-06 10:55:21 +0000338 }
339}
340
Eric Liu667e8ef2018-12-18 15:39:33 +0000341void BackgroundIndex::buildIndex() {
342 assert(BuildIndexPeriodMs > 0);
343 while (true) {
344 {
345 std::unique_lock<std::mutex> Lock(IndexMu);
346 if (ShouldStop) // Avoid waiting if stopped.
347 break;
348 // Wait until this is notified to stop or `BuildIndexPeriodMs` has past.
349 IndexCV.wait_for(Lock, std::chrono::milliseconds(BuildIndexPeriodMs));
350 if (ShouldStop) // Avoid rebuilding index if stopped.
351 break;
352 }
353 if (!SymbolsUpdatedSinceLastIndex.exchange(false))
354 continue;
355 // There can be symbol update right after the flag is reset above and before
356 // index is rebuilt below. The new index would contain the updated symbols
357 // but the flag would still be true. This is fine as we would simply run an
358 // extra index build.
359 reset(
360 IndexedSymbols.buildIndex(IndexType::Heavy, DuplicateHandling::Merge));
361 log("BackgroundIndex: rebuilt symbol index.");
362 }
363}
364
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000365Error BackgroundIndex::index(tooling::CompileCommand Cmd,
366 BackgroundIndexStorage *IndexStorage) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000367 trace::Span Tracer("BackgroundIndex");
368 SPAN_ATTACH(Tracer, "file", Cmd.Filename);
Kadir Cetinkayaed18e782018-11-15 10:34:39 +0000369 SmallString<128> AbsolutePath;
370 if (sys::path::is_absolute(Cmd.Filename)) {
371 AbsolutePath = Cmd.Filename;
372 } else {
373 AbsolutePath = Cmd.Directory;
374 sys::path::append(AbsolutePath, Cmd.Filename);
375 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000376
377 auto FS = FSProvider.getFileSystem();
378 auto Buf = FS->getBufferForFile(AbsolutePath);
379 if (!Buf)
380 return errorCodeToError(Buf.getError());
Eric Liuad588af2018-11-06 10:55:21 +0000381 auto Hash = digest(Buf->get()->getBuffer());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000382
Eric Liuad588af2018-11-06 10:55:21 +0000383 // Take a snapshot of the digests to avoid locking for each file in the TU.
384 llvm::StringMap<FileDigest> DigestsSnapshot;
385 {
386 std::lock_guard<std::mutex> Lock(DigestsMu);
387 if (IndexedFileDigests.lookup(AbsolutePath) == Hash) {
388 vlog("No need to index {0}, already up to date", AbsolutePath);
389 return Error::success();
390 }
391
392 DigestsSnapshot = IndexedFileDigests;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000393 }
394
Eric Liu667e8ef2018-12-18 15:39:33 +0000395 log("Indexing {0} (digest:={1})", Cmd.Filename, toHex(Hash));
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000396 ParseInputs Inputs;
397 Inputs.FS = std::move(FS);
398 Inputs.FS->setCurrentWorkingDirectory(Cmd.Directory);
399 Inputs.CompileCommand = std::move(Cmd);
400 auto CI = buildCompilerInvocation(Inputs);
401 if (!CI)
Sam McCallc008af62018-10-20 15:30:37 +0000402 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000403 "Couldn't build compiler invocation");
404 IgnoreDiagnostics IgnoreDiags;
405 auto Clang = prepareCompilerInstance(
406 std::move(CI), /*Preamble=*/nullptr, std::move(*Buf),
407 std::make_shared<PCHContainerOperations>(), Inputs.FS, IgnoreDiags);
408 if (!Clang)
Sam McCallc008af62018-10-20 15:30:37 +0000409 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000410 "Couldn't build compiler instance");
411
412 SymbolCollector::Options IndexOpts;
Eric Liuad588af2018-11-06 10:55:21 +0000413 StringMap<FileDigest> FilesToUpdate;
414 IndexOpts.FileFilter = createFileFilter(DigestsSnapshot, FilesToUpdate);
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000415 IndexFileIn Index;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000416 auto Action = createStaticIndexingAction(
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000417 IndexOpts, [&](SymbolSlab S) { Index.Symbols = std::move(S); },
418 [&](RefSlab R) { Index.Refs = std::move(R); },
419 [&](IncludeGraph IG) { Index.Sources = std::move(IG); });
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000420
421 // We're going to run clang here, and it could potentially crash.
422 // We could use CrashRecoveryContext to try to make indexing crashes nonfatal,
423 // but the leaky "recovery" is pretty scary too in a long-running process.
424 // If crashes are a real problem, maybe we should fork a child process.
425
426 const FrontendInputFile &Input = Clang->getFrontendOpts().Inputs.front();
427 if (!Action->BeginSourceFile(*Clang, Input))
Sam McCallc008af62018-10-20 15:30:37 +0000428 return createStringError(inconvertibleErrorCode(),
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000429 "BeginSourceFile() failed");
430 if (!Action->Execute())
Sam McCallc008af62018-10-20 15:30:37 +0000431 return createStringError(inconvertibleErrorCode(), "Execute() failed");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000432 Action->EndSourceFile();
Haojian Wud5a78e62018-12-14 12:39:08 +0000433 if (Clang->hasDiagnostics() &&
434 Clang->getDiagnostics().hasUncompilableErrorOccurred()) {
435 return createStringError(inconvertibleErrorCode(),
436 "IndexingAction failed: has uncompilable errors");
437 }
438
439 assert(Index.Symbols && Index.Refs && Index.Sources
440 && "Symbols, Refs and Sources must be set.");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000441
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000442 log("Indexed {0} ({1} symbols, {2} refs, {3} files)",
443 Inputs.CompileCommand.Filename, Index.Symbols->size(),
444 Index.Refs->numRefs(), Index.Sources->size());
445 SPAN_ATTACH(Tracer, "symbols", int(Index.Symbols->size()));
446 SPAN_ATTACH(Tracer, "refs", int(Index.Refs->numRefs()));
447 SPAN_ATTACH(Tracer, "sources", int(Index.Sources->size()));
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000448
449 update(AbsolutePath, std::move(Index), FilesToUpdate, IndexStorage);
Eric Liuad588af2018-11-06 10:55:21 +0000450 {
451 // Make sure hash for the main file is always updated even if there is no
452 // index data in it.
453 std::lock_guard<std::mutex> Lock(DigestsMu);
454 IndexedFileDigests[AbsolutePath] = Hash;
455 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000456
Eric Liu667e8ef2018-12-18 15:39:33 +0000457 if (BuildIndexPeriodMs > 0)
458 SymbolsUpdatedSinceLastIndex = true;
459 else
460 reset(
461 IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge));
Eric Liuad588af2018-11-06 10:55:21 +0000462
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000463 return Error::success();
464}
465
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000466} // namespace clangd
467} // namespace clang