blob: 6a3eace664e95675497cb6f99c326f7c8396fa31 [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
Sam McCall8dc9dbb2018-10-15 13:34:10 +000038namespace clang {
39namespace clangd {
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +000040namespace {
41// Resolves URI to file paths with cache.
42class URIToFileCache {
43public:
44 URIToFileCache(llvm::StringRef HintPath) : HintPath(HintPath) {}
45
46 llvm::StringRef resolve(llvm::StringRef FileURI) {
47 auto I = URIToPathCache.try_emplace(FileURI);
48 if (I.second) {
49 auto U = URI::parse(FileURI);
50 if (!U) {
51 elog("Failed to parse URI {0}: {1}", FileURI, U.takeError());
52 assert(false && "Failed to parse URI");
53 return "";
54 }
55 auto Path = URI::resolve(*U, HintPath);
56 if (!Path) {
57 elog("Failed to resolve URI {0}: {1}", FileURI, Path.takeError());
58 assert(false && "Failed to resolve URI");
59 return "";
60 }
61 I.first->second = *Path;
62 }
63 return I.first->second;
64 }
65
66private:
67 std::string HintPath;
68 llvm::StringMap<std::string> URIToPathCache;
69};
70
71// We keep only the node "U" and its edges. Any node other than "U" will be
72// empty in the resultant graph.
73IncludeGraph getSubGraph(const URI &U, const IncludeGraph &FullGraph) {
74 IncludeGraph IG;
75
76 std::string FileURI = U.toString();
77 auto Entry = IG.try_emplace(FileURI).first;
78 auto &Node = Entry->getValue();
79 Node = FullGraph.lookup(Entry->getKey());
80 Node.URI = Entry->getKey();
81
82 // URIs inside nodes must point into the keys of the same IncludeGraph.
83 for (auto &Include : Node.DirectIncludes) {
84 auto I = IG.try_emplace(Include).first;
85 I->getValue().URI = I->getKey();
86 Include = I->getKey();
87 }
88
89 return IG;
90}
Haojian Wu9d0d9f82018-12-13 13:07:29 +000091
92// Creates a filter to not collect index results from files with unchanged
93// digests.
94// \p FileDigests contains file digests for the current indexed files, and all
95// changed files will be added to \p FilesToUpdate.
96decltype(SymbolCollector::Options::FileFilter)
97createFileFilter(const llvm::StringMap<FileDigest> &FileDigests,
98 llvm::StringMap<FileDigest> &FilesToUpdate) {
99 return [&FileDigests, &FilesToUpdate](const SourceManager &SM, FileID FID) {
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000100 const auto *F = SM.getFileEntryForID(FID);
101 if (!F)
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000102 return false; // Skip invalid files.
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000103 auto AbsPath = getCanonicalPath(F, SM);
104 if (!AbsPath)
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000105 return false; // Skip files without absolute path.
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000106 auto Digest = digestFile(SM, FID);
107 if (!Digest)
108 return false;
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000109 auto D = FileDigests.find(*AbsPath);
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000110 if (D != FileDigests.end() && D->second == Digest)
111 return false; // Skip files that haven't changed.
112
Kadir Cetinkayadd677932018-12-19 10:46:21 +0000113 FilesToUpdate[*AbsPath] = *Digest;
Haojian Wu9d0d9f82018-12-13 13:07:29 +0000114 return true;
115 };
116}
117
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000118} // namespace
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000119
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000120BackgroundIndex::BackgroundIndex(
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000121 Context BackgroundContext, llvm::StringRef ResourceDir,
Sam McCall6e2d2a32018-11-26 09:51:50 +0000122 const FileSystemProvider &FSProvider, const GlobalCompilationDatabase &CDB,
Eric Liu667e8ef2018-12-18 15:39:33 +0000123 BackgroundIndexStorage::Factory IndexStorageFactory,
124 size_t BuildIndexPeriodMs, size_t ThreadPoolSize)
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000125 : SwapIndex(llvm::make_unique<MemIndex>()), ResourceDir(ResourceDir),
Sam McCall6e2d2a32018-11-26 09:51:50 +0000126 FSProvider(FSProvider), CDB(CDB),
127 BackgroundContext(std::move(BackgroundContext)),
Eric Liu667e8ef2018-12-18 15:39:33 +0000128 BuildIndexPeriodMs(BuildIndexPeriodMs),
129 SymbolsUpdatedSinceLastIndex(false),
Sam McCall6e2d2a32018-11-26 09:51:50 +0000130 IndexStorageFactory(std::move(IndexStorageFactory)),
131 CommandsChanged(
132 CDB.watch([&](const std::vector<std::string> &ChangedFiles) {
133 enqueue(ChangedFiles);
134 })) {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000135 assert(ThreadPoolSize > 0 && "Thread pool size can't be zero.");
Haojian Wu1bf52c52018-11-16 09:41:14 +0000136 assert(this->IndexStorageFactory && "Storage factory can not be null!");
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000137 while (ThreadPoolSize--)
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000138 ThreadPool.emplace_back([this] { run(); });
Eric Liu667e8ef2018-12-18 15:39:33 +0000139 if (BuildIndexPeriodMs > 0) {
140 log("BackgroundIndex: build symbol index periodically every {0} ms.",
141 BuildIndexPeriodMs);
142 ThreadPool.emplace_back([this] { buildIndex(); });
143 }
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000144}
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000145
146BackgroundIndex::~BackgroundIndex() {
147 stop();
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000148 for (auto &Thread : ThreadPool)
149 Thread.join();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000150}
151
152void BackgroundIndex::stop() {
153 {
Eric Liu667e8ef2018-12-18 15:39:33 +0000154 std::lock_guard<std::mutex> QueueLock(QueueMu);
155 std::lock_guard<std::mutex> IndexLock(IndexMu);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000156 ShouldStop = true;
157 }
158 QueueCV.notify_all();
Eric Liu667e8ef2018-12-18 15:39:33 +0000159 IndexCV.notify_all();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000160}
161
162void BackgroundIndex::run() {
Kadir Cetinkaya6675be82018-10-30 12:13:27 +0000163 WithContext Background(BackgroundContext.clone());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000164 while (true) {
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000165 llvm::Optional<Task> Task;
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000166 ThreadPriority Priority;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000167 {
168 std::unique_lock<std::mutex> Lock(QueueMu);
169 QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); });
170 if (ShouldStop) {
171 Queue.clear();
172 QueueCV.notify_all();
173 return;
174 }
175 ++NumActiveTasks;
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000176 std::tie(Task, Priority) = std::move(Queue.front());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000177 Queue.pop_front();
178 }
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000179
180 if (Priority != ThreadPriority::Normal)
181 setCurrentThreadPriority(Priority);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000182 (*Task)();
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000183 if (Priority != ThreadPriority::Normal)
184 setCurrentThreadPriority(ThreadPriority::Normal);
185
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000186 {
187 std::unique_lock<std::mutex> Lock(QueueMu);
188 assert(NumActiveTasks > 0 && "before decrementing");
189 --NumActiveTasks;
190 }
191 QueueCV.notify_all();
192 }
193}
194
Sam McCall422c8282018-11-26 16:00:11 +0000195bool BackgroundIndex::blockUntilIdleForTest(
196 llvm::Optional<double> TimeoutSeconds) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000197 std::unique_lock<std::mutex> Lock(QueueMu);
Sam McCall422c8282018-11-26 16:00:11 +0000198 return wait(Lock, QueueCV, timeoutSeconds(TimeoutSeconds),
199 [&] { return Queue.empty() && NumActiveTasks == 0; });
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000200}
201
Sam McCall6e2d2a32018-11-26 09:51:50 +0000202void BackgroundIndex::enqueue(const std::vector<std::string> &ChangedFiles) {
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000203 enqueueTask(
204 [this, ChangedFiles] {
205 trace::Span Tracer("BackgroundIndexEnqueue");
206 // We're doing this asynchronously, because we'll read shards here too.
207 // FIXME: read shards here too.
Sam McCall6e2d2a32018-11-26 09:51:50 +0000208
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000209 log("Enqueueing {0} commands for indexing", ChangedFiles.size());
210 SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size()));
Sam McCall6e2d2a32018-11-26 09:51:50 +0000211
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000212 // We shuffle the files because processing them in a random order should
213 // quickly give us good coverage of headers in the project.
214 std::vector<unsigned> Permutation(ChangedFiles.size());
215 std::iota(Permutation.begin(), Permutation.end(), 0);
216 std::mt19937 Generator(std::random_device{}());
217 std::shuffle(Permutation.begin(), Permutation.end(), Generator);
Sam McCall6e2d2a32018-11-26 09:51:50 +0000218
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000219 for (const unsigned I : Permutation)
220 enqueue(ChangedFiles[I]);
221 },
222 ThreadPriority::Normal);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000223}
224
Sam McCall6e2d2a32018-11-26 09:51:50 +0000225void BackgroundIndex::enqueue(const std::string &File) {
226 ProjectInfo Project;
227 if (auto Cmd = CDB.getCompileCommand(File, &Project)) {
228 auto *Storage = IndexStorageFactory(Project.SourceRoot);
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000229 // Set priority to low, since background indexing is a long running
230 // task we do not want to eat up cpu when there are any other high
231 // priority threads.
Sam McCall6e2d2a32018-11-26 09:51:50 +0000232 enqueueTask(Bind(
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000233 [this, File, Storage](tooling::CompileCommand Cmd) {
234 Cmd.CommandLine.push_back("-resource-dir=" + ResourceDir);
235 if (auto Error = index(std::move(Cmd), Storage))
236 log("Indexing {0} failed: {1}", File, std::move(Error));
237 },
238 std::move(*Cmd)),
239 ThreadPriority::Low);
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000240 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000241}
242
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000243void BackgroundIndex::enqueueTask(Task T, ThreadPriority Priority) {
Sam McCall6e2d2a32018-11-26 09:51:50 +0000244 {
245 std::lock_guard<std::mutex> Lock(QueueMu);
Kadir Cetinkaya375c54f2018-12-17 12:30:27 +0000246 auto I = Queue.end();
247 // We first store the tasks with Normal priority in the front of the queue.
248 // Then we store low priority tasks. Normal priority tasks are pretty rare,
249 // they should not grow beyond single-digit numbers, so it is OK to do
250 // linear search and insert after that.
251 if (Priority == ThreadPriority::Normal) {
252 I = llvm::find_if(Queue, [](const std::pair<Task, ThreadPriority> &Elem) {
253 return Elem.second == ThreadPriority::Low;
254 });
255 }
256 Queue.insert(I, {std::move(T), Priority});
Sam McCall6e2d2a32018-11-26 09:51:50 +0000257 }
258 QueueCV.notify_all();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000259}
260
Eric Liuad588af2018-11-06 10:55:21 +0000261/// Given index results from a TU, only update files in \p FilesToUpdate.
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000262void BackgroundIndex::update(llvm::StringRef MainFile, IndexFileIn Index,
263 const llvm::StringMap<FileDigest> &FilesToUpdate,
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000264 BackgroundIndexStorage *IndexStorage) {
Eric Liuad588af2018-11-06 10:55:21 +0000265 // Partition symbols/references into files.
266 struct File {
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000267 llvm::DenseSet<const Symbol *> Symbols;
268 llvm::DenseSet<const Ref *> Refs;
Eric Liuad588af2018-11-06 10:55:21 +0000269 };
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000270 llvm::StringMap<File> Files;
Eric Liuad588af2018-11-06 10:55:21 +0000271 URIToFileCache URICache(MainFile);
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000272 for (const auto &Sym : *Index.Symbols) {
Eric Liuad588af2018-11-06 10:55:21 +0000273 if (Sym.CanonicalDeclaration) {
274 auto DeclPath = URICache.resolve(Sym.CanonicalDeclaration.FileURI);
275 if (FilesToUpdate.count(DeclPath) != 0)
276 Files[DeclPath].Symbols.insert(&Sym);
277 }
278 // For symbols with different declaration and definition locations, we store
279 // the full symbol in both the header file and the implementation file, so
280 // that merging can tell the preferred symbols (from canonical headers) from
281 // other symbols (e.g. forward declarations).
282 if (Sym.Definition &&
283 Sym.Definition.FileURI != Sym.CanonicalDeclaration.FileURI) {
284 auto DefPath = URICache.resolve(Sym.Definition.FileURI);
285 if (FilesToUpdate.count(DefPath) != 0)
286 Files[DefPath].Symbols.insert(&Sym);
287 }
288 }
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000289 llvm::DenseMap<const Ref *, SymbolID> RefToIDs;
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000290 for (const auto &SymRefs : *Index.Refs) {
Eric Liuad588af2018-11-06 10:55:21 +0000291 for (const auto &R : SymRefs.second) {
292 auto Path = URICache.resolve(R.Location.FileURI);
293 if (FilesToUpdate.count(Path) != 0) {
294 auto &F = Files[Path];
295 RefToIDs[&R] = SymRefs.first;
296 F.Refs.insert(&R);
297 }
298 }
299 }
300
301 // Build and store new slabs for each updated file.
302 for (const auto &F : Files) {
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000303 llvm::StringRef Path = F.first();
Eric Liuad588af2018-11-06 10:55:21 +0000304 vlog("Update symbols in {0}", Path);
305 SymbolSlab::Builder Syms;
306 RefSlab::Builder Refs;
307 for (const auto *S : F.second.Symbols)
308 Syms.insert(*S);
309 for (const auto *R : F.second.Refs)
310 Refs.insert(RefToIDs[R], *R);
311
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000312 auto SS = llvm::make_unique<SymbolSlab>(std::move(Syms).build());
313 auto RS = llvm::make_unique<RefSlab>(std::move(Refs).build());
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000314 auto IG = llvm::make_unique<IncludeGraph>(
315 getSubGraph(URI::create(Path), Index.Sources.getValue()));
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000316
317 auto Hash = FilesToUpdate.lookup(Path);
318 // We need to store shards before updating the index, since the latter
319 // consumes slabs.
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000320 if (IndexStorage) {
321 IndexFileOut Shard;
322 Shard.Symbols = SS.get();
323 Shard.Refs = RS.get();
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000324 Shard.Sources = IG.get();
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000325
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000326 if (auto Error = IndexStorage->storeShard(Path, Shard))
327 elog("Failed to write background-index shard for file {0}: {1}", Path,
328 std::move(Error));
329 }
330
Eric Liuad588af2018-11-06 10:55:21 +0000331 std::lock_guard<std::mutex> Lock(DigestsMu);
332 // This can override a newer version that is added in another thread,
333 // if this thread sees the older version but finishes later. This should be
334 // rare in practice.
Kadir Cetinkaya06553bf2018-11-16 09:03:56 +0000335 IndexedFileDigests[Path] = Hash;
336 IndexedSymbols.update(Path, std::move(SS), std::move(RS));
Eric Liuad588af2018-11-06 10:55:21 +0000337 }
338}
339
Eric Liu667e8ef2018-12-18 15:39:33 +0000340void BackgroundIndex::buildIndex() {
341 assert(BuildIndexPeriodMs > 0);
342 while (true) {
343 {
344 std::unique_lock<std::mutex> Lock(IndexMu);
345 if (ShouldStop) // Avoid waiting if stopped.
346 break;
347 // Wait until this is notified to stop or `BuildIndexPeriodMs` has past.
348 IndexCV.wait_for(Lock, std::chrono::milliseconds(BuildIndexPeriodMs));
349 if (ShouldStop) // Avoid rebuilding index if stopped.
350 break;
351 }
352 if (!SymbolsUpdatedSinceLastIndex.exchange(false))
353 continue;
354 // There can be symbol update right after the flag is reset above and before
355 // index is rebuilt below. The new index would contain the updated symbols
356 // but the flag would still be true. This is fine as we would simply run an
357 // extra index build.
358 reset(
359 IndexedSymbols.buildIndex(IndexType::Heavy, DuplicateHandling::Merge));
360 log("BackgroundIndex: rebuilt symbol index.");
361 }
362}
363
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000364llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd,
365 BackgroundIndexStorage *IndexStorage) {
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000366 trace::Span Tracer("BackgroundIndex");
367 SPAN_ATTACH(Tracer, "file", Cmd.Filename);
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000368 llvm::SmallString<128> AbsolutePath;
369 if (llvm::sys::path::is_absolute(Cmd.Filename)) {
Kadir Cetinkayaed18e782018-11-15 10:34:39 +0000370 AbsolutePath = Cmd.Filename;
371 } else {
372 AbsolutePath = Cmd.Directory;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000373 llvm::sys::path::append(AbsolutePath, Cmd.Filename);
Kadir Cetinkayaed18e782018-11-15 10:34:39 +0000374 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000375
376 auto FS = FSProvider.getFileSystem();
377 auto Buf = FS->getBufferForFile(AbsolutePath);
378 if (!Buf)
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000379 return llvm::errorCodeToError(Buf.getError());
Eric Liuad588af2018-11-06 10:55:21 +0000380 auto Hash = digest(Buf->get()->getBuffer());
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000381
Eric Liuad588af2018-11-06 10:55:21 +0000382 // Take a snapshot of the digests to avoid locking for each file in the TU.
383 llvm::StringMap<FileDigest> DigestsSnapshot;
384 {
385 std::lock_guard<std::mutex> Lock(DigestsMu);
386 if (IndexedFileDigests.lookup(AbsolutePath) == Hash) {
387 vlog("No need to index {0}, already up to date", AbsolutePath);
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000388 return llvm::Error::success();
Eric Liuad588af2018-11-06 10:55:21 +0000389 }
390
391 DigestsSnapshot = IndexedFileDigests;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000392 }
393
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000394 log("Indexing {0} (digest:={1})", Cmd.Filename, llvm::toHex(Hash));
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000395 ParseInputs Inputs;
396 Inputs.FS = std::move(FS);
397 Inputs.FS->setCurrentWorkingDirectory(Cmd.Directory);
398 Inputs.CompileCommand = std::move(Cmd);
399 auto CI = buildCompilerInvocation(Inputs);
400 if (!CI)
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000401 return llvm::createStringError(llvm::inconvertibleErrorCode(),
402 "Couldn't build compiler invocation");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000403 IgnoreDiagnostics IgnoreDiags;
404 auto Clang = prepareCompilerInstance(
405 std::move(CI), /*Preamble=*/nullptr, std::move(*Buf),
406 std::make_shared<PCHContainerOperations>(), Inputs.FS, IgnoreDiags);
407 if (!Clang)
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000408 return llvm::createStringError(llvm::inconvertibleErrorCode(),
409 "Couldn't build compiler instance");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000410
411 SymbolCollector::Options IndexOpts;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000412 llvm::StringMap<FileDigest> FilesToUpdate;
Eric Liuad588af2018-11-06 10:55:21 +0000413 IndexOpts.FileFilter = createFileFilter(DigestsSnapshot, FilesToUpdate);
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000414 IndexFileIn Index;
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000415 auto Action = createStaticIndexingAction(
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000416 IndexOpts, [&](SymbolSlab S) { Index.Symbols = std::move(S); },
417 [&](RefSlab R) { Index.Refs = std::move(R); },
418 [&](IncludeGraph IG) { Index.Sources = std::move(IG); });
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000419
420 // We're going to run clang here, and it could potentially crash.
421 // We could use CrashRecoveryContext to try to make indexing crashes nonfatal,
422 // but the leaky "recovery" is pretty scary too in a long-running process.
423 // If crashes are a real problem, maybe we should fork a child process.
424
425 const FrontendInputFile &Input = Clang->getFrontendOpts().Inputs.front();
426 if (!Action->BeginSourceFile(*Clang, Input))
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000427 return llvm::createStringError(llvm::inconvertibleErrorCode(),
428 "BeginSourceFile() failed");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000429 if (!Action->Execute())
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000430 return llvm::createStringError(llvm::inconvertibleErrorCode(),
431 "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()) {
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000435 return llvm::createStringError(
436 llvm::inconvertibleErrorCode(),
437 "IndexingAction failed: has uncompilable errors");
Haojian Wud5a78e62018-12-14 12:39:08 +0000438 }
439
440 assert(Index.Symbols && Index.Refs && Index.Sources
441 && "Symbols, Refs and Sources must be set.");
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000442
Kadir Cetinkaya219c0fa2018-12-04 11:31:57 +0000443 log("Indexed {0} ({1} symbols, {2} refs, {3} files)",
444 Inputs.CompileCommand.Filename, Index.Symbols->size(),
445 Index.Refs->numRefs(), Index.Sources->size());
446 SPAN_ATTACH(Tracer, "symbols", int(Index.Symbols->size()));
447 SPAN_ATTACH(Tracer, "refs", int(Index.Refs->numRefs()));
448 SPAN_ATTACH(Tracer, "sources", int(Index.Sources->size()));
Kadir Cetinkayad08eab42018-11-27 16:08:53 +0000449
450 update(AbsolutePath, std::move(Index), FilesToUpdate, IndexStorage);
Eric Liuad588af2018-11-06 10:55:21 +0000451 {
452 // Make sure hash for the main file is always updated even if there is no
453 // index data in it.
454 std::lock_guard<std::mutex> Lock(DigestsMu);
455 IndexedFileDigests[AbsolutePath] = Hash;
456 }
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000457
Eric Liu667e8ef2018-12-18 15:39:33 +0000458 if (BuildIndexPeriodMs > 0)
459 SymbolsUpdatedSinceLastIndex = true;
460 else
461 reset(
462 IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge));
Eric Liuad588af2018-11-06 10:55:21 +0000463
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000464 return llvm::Error::success();
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000465}
466
Sam McCall8dc9dbb2018-10-15 13:34:10 +0000467} // namespace clangd
468} // namespace clang