blob: 1da2e8f282d16ca1cd61678dff578315f8fd0aa3 [file] [log] [blame]
Ilya Biryukov38d79772017-05-16 09:38:59 +00001//===--- ClangdUnit.cpp -----------------------------------------*- C++-*-===//
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 "ClangdUnit.h"
Sam McCall98775c52017-12-04 13:49:59 +000011#include "Compiler.h"
Ilya Biryukov83ca8a22017-09-20 10:46:58 +000012#include "Logger.h"
Sam McCall8567cb32017-11-02 09:21:51 +000013#include "Trace.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000014#include "clang/Frontend/CompilerInstance.h"
15#include "clang/Frontend/CompilerInvocation.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000016#include "clang/Frontend/FrontendActions.h"
Ilya Biryukov0f62ed22017-05-26 12:26:51 +000017#include "clang/Frontend/Utils.h"
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000018#include "clang/Index/IndexDataConsumer.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000019#include "clang/Index/IndexingAction.h"
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000020#include "clang/Lex/Lexer.h"
21#include "clang/Lex/MacroInfo.h"
22#include "clang/Lex/Preprocessor.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000023#include "clang/Sema/Sema.h"
24#include "clang/Serialization/ASTWriter.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000025#include "clang/Tooling/CompilationDatabase.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000026#include "llvm/ADT/ArrayRef.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/Support/CrashRecoveryContext.h"
Krasimir Georgieva1de3c92017-06-15 09:11:57 +000029#include "llvm/Support/Format.h"
Ilya Biryukovd14dc492018-02-01 19:06:45 +000030#include "llvm/Support/raw_ostream.h"
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000031#include <algorithm>
Ilya Biryukov02d58702017-08-01 15:51:38 +000032#include <chrono>
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000033
Ilya Biryukov38d79772017-05-16 09:38:59 +000034using namespace clang::clangd;
35using namespace clang;
36
Ilya Biryukov04db3682017-07-21 13:29:29 +000037namespace {
38
Ilya Biryukovdf842342018-01-25 14:32:21 +000039template <class T> std::size_t getUsedBytes(const std::vector<T> &Vec) {
40 return Vec.capacity() * sizeof(T);
41}
42
Ilya Biryukov04db3682017-07-21 13:29:29 +000043class DeclTrackingASTConsumer : public ASTConsumer {
44public:
45 DeclTrackingASTConsumer(std::vector<const Decl *> &TopLevelDecls)
46 : TopLevelDecls(TopLevelDecls) {}
47
48 bool HandleTopLevelDecl(DeclGroupRef DG) override {
49 for (const Decl *D : DG) {
50 // ObjCMethodDecl are not actually top-level decls.
51 if (isa<ObjCMethodDecl>(D))
52 continue;
53
54 TopLevelDecls.push_back(D);
55 }
56 return true;
57 }
58
59private:
60 std::vector<const Decl *> &TopLevelDecls;
61};
62
63class ClangdFrontendAction : public SyntaxOnlyAction {
64public:
65 std::vector<const Decl *> takeTopLevelDecls() {
66 return std::move(TopLevelDecls);
67 }
68
69protected:
70 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
71 StringRef InFile) override {
72 return llvm::make_unique<DeclTrackingASTConsumer>(/*ref*/ TopLevelDecls);
73 }
74
75private:
76 std::vector<const Decl *> TopLevelDecls;
77};
78
Ilya Biryukov02d58702017-08-01 15:51:38 +000079class CppFilePreambleCallbacks : public PreambleCallbacks {
Ilya Biryukov04db3682017-07-21 13:29:29 +000080public:
81 std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
82 return std::move(TopLevelDeclIDs);
83 }
84
85 void AfterPCHEmitted(ASTWriter &Writer) override {
86 TopLevelDeclIDs.reserve(TopLevelDecls.size());
87 for (Decl *D : TopLevelDecls) {
88 // Invalid top-level decls may not have been serialized.
89 if (D->isInvalidDecl())
90 continue;
91 TopLevelDeclIDs.push_back(Writer.getDeclID(D));
92 }
93 }
94
95 void HandleTopLevelDecl(DeclGroupRef DG) override {
96 for (Decl *D : DG) {
97 if (isa<ObjCMethodDecl>(D))
98 continue;
99 TopLevelDecls.push_back(D);
100 }
101 }
102
103private:
104 std::vector<Decl *> TopLevelDecls;
105 std::vector<serialization::DeclID> TopLevelDeclIDs;
106};
107
108/// Convert from clang diagnostic level to LSP severity.
109static int getSeverity(DiagnosticsEngine::Level L) {
110 switch (L) {
111 case DiagnosticsEngine::Remark:
112 return 4;
113 case DiagnosticsEngine::Note:
114 return 3;
115 case DiagnosticsEngine::Warning:
116 return 2;
117 case DiagnosticsEngine::Fatal:
118 case DiagnosticsEngine::Error:
119 return 1;
120 case DiagnosticsEngine::Ignored:
121 return 0;
122 }
123 llvm_unreachable("Unknown diagnostic level!");
124}
125
Sam McCall8111d3b2017-12-13 08:48:42 +0000126// Checks whether a location is within a half-open range.
127// Note that clang also uses closed source ranges, which this can't handle!
128bool locationInRange(SourceLocation L, CharSourceRange R,
129 const SourceManager &M) {
130 assert(R.isCharRange());
131 if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
132 M.getFileID(R.getBegin()) != M.getFileID(L))
133 return false;
134 return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
135}
136
137// Converts a half-open clang source range to an LSP range.
138// Note that clang also uses closed source ranges, which this can't handle!
139Range toRange(CharSourceRange R, const SourceManager &M) {
140 // Clang is 1-based, LSP uses 0-based indexes.
141 return {{static_cast<int>(M.getSpellingLineNumber(R.getBegin())) - 1,
142 static_cast<int>(M.getSpellingColumnNumber(R.getBegin())) - 1},
143 {static_cast<int>(M.getSpellingLineNumber(R.getEnd())) - 1,
144 static_cast<int>(M.getSpellingColumnNumber(R.getEnd())) - 1}};
145}
146
147// Clang diags have a location (shown as ^) and 0 or more ranges (~~~~).
148// LSP needs a single range.
149Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
150 auto &M = D.getSourceManager();
151 auto Loc = M.getFileLoc(D.getLocation());
152 // Accept the first range that contains the location.
153 for (const auto &CR : D.getRanges()) {
154 auto R = Lexer::makeFileCharRange(CR, M, L);
155 if (locationInRange(Loc, R, M))
156 return toRange(R, M);
157 }
158 // The range may be given as a fixit hint instead.
159 for (const auto &F : D.getFixItHints()) {
160 auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
161 if (locationInRange(Loc, R, M))
162 return toRange(R, M);
163 }
164 // If no suitable range is found, just use the token at the location.
165 auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L);
166 if (!R.isValid()) // Fall back to location only, let the editor deal with it.
167 R = CharSourceRange::getCharRange(Loc);
168 return toRange(R, M);
169}
170
171TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M,
172 const LangOptions &L) {
173 TextEdit Result;
174 Result.range = toRange(Lexer::makeFileCharRange(FixIt.RemoveRange, M, L), M);
175 Result.newText = FixIt.CodeToInsert;
176 return Result;
177}
178
179llvm::Optional<DiagWithFixIts> toClangdDiag(const clang::Diagnostic &D,
180 DiagnosticsEngine::Level Level,
181 const LangOptions &LangOpts) {
Ilya Biryukovd14dc492018-02-01 19:06:45 +0000182 SmallString<64> Message;
183 D.FormatDiagnostic(Message);
184
Sam McCall8111d3b2017-12-13 08:48:42 +0000185 if (!D.hasSourceManager() || !D.getLocation().isValid() ||
Ilya Biryukovd14dc492018-02-01 19:06:45 +0000186 !D.getSourceManager().isInMainFile(D.getLocation())) {
187
188 SmallString<64> Location;
189 if (D.hasSourceManager() && D.getLocation().isValid()) {
190 auto &SourceMgr = D.getSourceManager();
191 auto Loc = SourceMgr.getFileLoc(D.getLocation());
192 llvm::raw_svector_ostream OS(Location);
193 Loc.print(OS, SourceMgr);
194 } else {
195 Location = "<no-loc>";
196 }
197
198 log(llvm::formatv("Ignored diagnostic outside main file. {0}: {1}",
199 Location, Message));
Ilya Biryukov04db3682017-07-21 13:29:29 +0000200 return llvm::None;
Ilya Biryukovd14dc492018-02-01 19:06:45 +0000201 }
Ilya Biryukov04db3682017-07-21 13:29:29 +0000202
Sam McCall8111d3b2017-12-13 08:48:42 +0000203 DiagWithFixIts Result;
204 Result.Diag.range = diagnosticRange(D, LangOpts);
205 Result.Diag.severity = getSeverity(Level);
Sam McCall8111d3b2017-12-13 08:48:42 +0000206 Result.Diag.message = Message.str();
207 for (const FixItHint &Fix : D.getFixItHints())
208 Result.FixIts.push_back(toTextEdit(Fix, D.getSourceManager(), LangOpts));
209 return std::move(Result);
Ilya Biryukov04db3682017-07-21 13:29:29 +0000210}
211
212class StoreDiagsConsumer : public DiagnosticConsumer {
213public:
214 StoreDiagsConsumer(std::vector<DiagWithFixIts> &Output) : Output(Output) {}
215
Sam McCall8111d3b2017-12-13 08:48:42 +0000216 // Track language options in case we need to expand token ranges.
217 void BeginSourceFile(const LangOptions &Opts, const Preprocessor *) override {
218 LangOpts = Opts;
219 }
220
221 void EndSourceFile() override { LangOpts = llvm::None; }
222
Ilya Biryukov04db3682017-07-21 13:29:29 +0000223 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
224 const clang::Diagnostic &Info) override {
225 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
226
Sam McCall8111d3b2017-12-13 08:48:42 +0000227 if (LangOpts)
228 if (auto D = toClangdDiag(Info, DiagLevel, *LangOpts))
229 Output.push_back(std::move(*D));
Ilya Biryukov04db3682017-07-21 13:29:29 +0000230 }
231
232private:
233 std::vector<DiagWithFixIts> &Output;
Sam McCall8111d3b2017-12-13 08:48:42 +0000234 llvm::Optional<LangOptions> LangOpts;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000235};
236
Ilya Biryukov02d58702017-08-01 15:51:38 +0000237template <class T> bool futureIsReady(std::shared_future<T> const &Future) {
238 return Future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
239}
240
Ilya Biryukov04db3682017-07-21 13:29:29 +0000241} // namespace
242
Ilya Biryukov02d58702017-08-01 15:51:38 +0000243void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
244 AST.getASTContext().getTranslationUnitDecl()->dump(OS, true);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000245}
Ilya Biryukovf01af682017-05-23 13:42:59 +0000246
Ilya Biryukov02d58702017-08-01 15:51:38 +0000247llvm::Optional<ParsedAST>
Sam McCalld1a7a372018-01-31 13:40:48 +0000248ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI,
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000249 std::shared_ptr<const PreambleData> Preamble,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000250 std::unique_ptr<llvm::MemoryBuffer> Buffer,
251 std::shared_ptr<PCHContainerOperations> PCHs,
Ilya Biryukov940901e2017-12-13 12:51:22 +0000252 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000253
254 std::vector<DiagWithFixIts> ASTDiags;
255 StoreDiagsConsumer UnitDiagsConsumer(/*ref*/ ASTDiags);
256
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000257 const PrecompiledPreamble *PreamblePCH =
258 Preamble ? &Preamble->Preamble : nullptr;
Benjamin Kramer5349eed2017-10-28 17:32:56 +0000259 auto Clang = prepareCompilerInstance(
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000260 std::move(CI), PreamblePCH, std::move(Buffer), std::move(PCHs),
Benjamin Kramer5349eed2017-10-28 17:32:56 +0000261 std::move(VFS), /*ref*/ UnitDiagsConsumer);
Ilya Biryukovcec63352018-01-29 14:30:28 +0000262 if (!Clang)
263 return llvm::None;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000264
265 // Recover resources if we crash before exiting this method.
266 llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
267 Clang.get());
268
269 auto Action = llvm::make_unique<ClangdFrontendAction>();
Ilya Biryukove5128f72017-09-20 07:24:15 +0000270 const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
271 if (!Action->BeginSourceFile(*Clang, MainInput)) {
Sam McCalld1a7a372018-01-31 13:40:48 +0000272 log("BeginSourceFile() failed when building AST for " +
273 MainInput.getFile());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000274 return llvm::None;
275 }
Ilya Biryukove5128f72017-09-20 07:24:15 +0000276 if (!Action->Execute())
Sam McCalld1a7a372018-01-31 13:40:48 +0000277 log("Execute() failed when building AST for " + MainInput.getFile());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000278
279 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
280 // has a longer lifetime.
Sam McCall98775c52017-12-04 13:49:59 +0000281 Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
Ilya Biryukov04db3682017-07-21 13:29:29 +0000282
283 std::vector<const Decl *> ParsedDecls = Action->takeTopLevelDecls();
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000284 return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action),
285 std::move(ParsedDecls), std::move(ASTDiags));
Ilya Biryukov04db3682017-07-21 13:29:29 +0000286}
287
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000288namespace {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000289
290SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
Ilya Biryukov04db3682017-07-21 13:29:29 +0000291 const FileEntry *FE, Position Pos) {
292 SourceLocation InputLoc =
293 Mgr.translateFileLineCol(FE, Pos.line + 1, Pos.character + 1);
294 return Mgr.getMacroArgExpandedLocation(InputLoc);
295}
296
Ilya Biryukov02d58702017-08-01 15:51:38 +0000297} // namespace
Ilya Biryukov04db3682017-07-21 13:29:29 +0000298
Ilya Biryukov02d58702017-08-01 15:51:38 +0000299void ParsedAST::ensurePreambleDeclsDeserialized() {
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000300 if (PreambleDeclsDeserialized || !Preamble)
Ilya Biryukov04db3682017-07-21 13:29:29 +0000301 return;
302
303 std::vector<const Decl *> Resolved;
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000304 Resolved.reserve(Preamble->TopLevelDeclIDs.size());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000305
306 ExternalASTSource &Source = *getASTContext().getExternalSource();
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000307 for (serialization::DeclID TopLevelDecl : Preamble->TopLevelDeclIDs) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000308 // Resolve the declaration ID to an actual declaration, possibly
309 // deserializing the declaration in the process.
310 if (Decl *D = Source.GetExternalDecl(TopLevelDecl))
311 Resolved.push_back(D);
312 }
313
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000314 TopLevelDecls.reserve(TopLevelDecls.size() +
315 Preamble->TopLevelDeclIDs.size());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000316 TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
317
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000318 PreambleDeclsDeserialized = true;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000319}
320
Ilya Biryukov02d58702017-08-01 15:51:38 +0000321ParsedAST::ParsedAST(ParsedAST &&Other) = default;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000322
Ilya Biryukov02d58702017-08-01 15:51:38 +0000323ParsedAST &ParsedAST::operator=(ParsedAST &&Other) = default;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000324
Ilya Biryukov02d58702017-08-01 15:51:38 +0000325ParsedAST::~ParsedAST() {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000326 if (Action) {
327 Action->EndSourceFile();
328 }
329}
330
Ilya Biryukov02d58702017-08-01 15:51:38 +0000331ASTContext &ParsedAST::getASTContext() { return Clang->getASTContext(); }
332
333const ASTContext &ParsedAST::getASTContext() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000334 return Clang->getASTContext();
335}
336
Ilya Biryukov02d58702017-08-01 15:51:38 +0000337Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
Ilya Biryukov04db3682017-07-21 13:29:29 +0000338
Eric Liu76f6b442018-01-09 17:32:00 +0000339std::shared_ptr<Preprocessor> ParsedAST::getPreprocessorPtr() {
340 return Clang->getPreprocessorPtr();
341}
342
Ilya Biryukov02d58702017-08-01 15:51:38 +0000343const Preprocessor &ParsedAST::getPreprocessor() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000344 return Clang->getPreprocessor();
345}
346
Ilya Biryukov02d58702017-08-01 15:51:38 +0000347ArrayRef<const Decl *> ParsedAST::getTopLevelDecls() {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000348 ensurePreambleDeclsDeserialized();
349 return TopLevelDecls;
350}
351
Ilya Biryukov02d58702017-08-01 15:51:38 +0000352const std::vector<DiagWithFixIts> &ParsedAST::getDiagnostics() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000353 return Diags;
354}
355
Ilya Biryukovdf842342018-01-25 14:32:21 +0000356std::size_t ParsedAST::getUsedBytes() const {
357 auto &AST = getASTContext();
358 // FIXME(ibiryukov): we do not account for the dynamically allocated part of
359 // SmallVector<FixIt> inside each Diag.
360 return AST.getASTAllocatedMemory() + AST.getSideTableAllocatedMemory() +
361 ::getUsedBytes(TopLevelDecls) + ::getUsedBytes(Diags);
362}
363
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000364PreambleData::PreambleData(PrecompiledPreamble Preamble,
365 std::vector<serialization::DeclID> TopLevelDeclIDs,
366 std::vector<DiagWithFixIts> Diags)
367 : Preamble(std::move(Preamble)),
368 TopLevelDeclIDs(std::move(TopLevelDeclIDs)), Diags(std::move(Diags)) {}
369
370ParsedAST::ParsedAST(std::shared_ptr<const PreambleData> Preamble,
371 std::unique_ptr<CompilerInstance> Clang,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000372 std::unique_ptr<FrontendAction> Action,
373 std::vector<const Decl *> TopLevelDecls,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000374 std::vector<DiagWithFixIts> Diags)
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000375 : Preamble(std::move(Preamble)), Clang(std::move(Clang)),
376 Action(std::move(Action)), Diags(std::move(Diags)),
377 TopLevelDecls(std::move(TopLevelDecls)),
378 PreambleDeclsDeserialized(false) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000379 assert(this->Clang);
380 assert(this->Action);
381}
382
Ilya Biryukov02d58702017-08-01 15:51:38 +0000383ParsedASTWrapper::ParsedASTWrapper(ParsedASTWrapper &&Wrapper)
384 : AST(std::move(Wrapper.AST)) {}
385
386ParsedASTWrapper::ParsedASTWrapper(llvm::Optional<ParsedAST> AST)
387 : AST(std::move(AST)) {}
388
Ilya Biryukov02d58702017-08-01 15:51:38 +0000389std::shared_ptr<CppFile>
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000390CppFile::Create(PathRef FileName, bool StorePreamblesInMemory,
Eric Liubfac8f72017-12-19 18:00:37 +0000391 std::shared_ptr<PCHContainerOperations> PCHs,
392 ASTParsedCallback ASTCallback) {
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000393 return std::shared_ptr<CppFile>(new CppFile(FileName, StorePreamblesInMemory,
394 std::move(PCHs),
395 std::move(ASTCallback)));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000396}
397
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000398CppFile::CppFile(PathRef FileName, bool StorePreamblesInMemory,
Eric Liubfac8f72017-12-19 18:00:37 +0000399 std::shared_ptr<PCHContainerOperations> PCHs,
400 ASTParsedCallback ASTCallback)
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000401 : FileName(FileName), StorePreamblesInMemory(StorePreamblesInMemory),
Ilya Biryukovdf842342018-01-25 14:32:21 +0000402 RebuildCounter(0), RebuildInProgress(false), ASTMemUsage(0),
403 PreambleMemUsage(0), PCHs(std::move(PCHs)),
Eric Liubfac8f72017-12-19 18:00:37 +0000404 ASTCallback(std::move(ASTCallback)) {
Sam McCalld1a7a372018-01-31 13:40:48 +0000405 log("Created CppFile for " + FileName);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000406
407 std::lock_guard<std::mutex> Lock(Mutex);
408 LatestAvailablePreamble = nullptr;
409 PreamblePromise.set_value(nullptr);
410 PreambleFuture = PreamblePromise.get_future();
411
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000412 ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000413 ASTFuture = ASTPromise.get_future();
414}
415
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000416void CppFile::cancelRebuild() { deferCancelRebuild()(); }
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000417
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000418UniqueFunction<void()> CppFile::deferCancelRebuild() {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000419 std::unique_lock<std::mutex> Lock(Mutex);
420 // Cancel an ongoing rebuild, if any, and wait for it to finish.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000421 unsigned RequestRebuildCounter = ++this->RebuildCounter;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000422 // Rebuild asserts that futures aren't ready if rebuild is cancelled.
423 // We want to keep this invariant.
424 if (futureIsReady(PreambleFuture)) {
425 PreamblePromise = std::promise<std::shared_ptr<const PreambleData>>();
426 PreambleFuture = PreamblePromise.get_future();
427 }
428 if (futureIsReady(ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000429 ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000430 ASTFuture = ASTPromise.get_future();
431 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000432
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000433 Lock.unlock();
434 // Notify about changes to RebuildCounter.
435 RebuildCond.notify_all();
436
437 std::shared_ptr<CppFile> That = shared_from_this();
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000438 return [That, RequestRebuildCounter]() {
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000439 std::unique_lock<std::mutex> Lock(That->Mutex);
440 CppFile *This = &*That;
441 This->RebuildCond.wait(Lock, [This, RequestRebuildCounter]() {
442 return !This->RebuildInProgress ||
443 This->RebuildCounter != RequestRebuildCounter;
444 });
445
446 // This computation got cancelled itself, do nothing.
447 if (This->RebuildCounter != RequestRebuildCounter)
448 return;
449
450 // Set empty results for Promises.
Ilya Biryukovdf842342018-01-25 14:32:21 +0000451 That->PreambleMemUsage = 0;
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000452 That->PreamblePromise.set_value(nullptr);
Ilya Biryukovdf842342018-01-25 14:32:21 +0000453 That->ASTMemUsage = 0;
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000454 That->ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000455 };
Ilya Biryukov02d58702017-08-01 15:51:38 +0000456}
457
458llvm::Optional<std::vector<DiagWithFixIts>>
Sam McCalld1a7a372018-01-31 13:40:48 +0000459CppFile::rebuild(ParseInputs &&Inputs) {
460 return deferRebuild(std::move(Inputs))();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000461}
462
Sam McCalld1a7a372018-01-31 13:40:48 +0000463UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>()>
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000464CppFile::deferRebuild(ParseInputs &&Inputs) {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000465 std::shared_ptr<const PreambleData> OldPreamble;
466 std::shared_ptr<PCHContainerOperations> PCHs;
467 unsigned RequestRebuildCounter;
468 {
469 std::unique_lock<std::mutex> Lock(Mutex);
470 // Increase RebuildCounter to cancel all ongoing FinishRebuild operations.
471 // They will try to exit as early as possible and won't call set_value on
472 // our promises.
473 RequestRebuildCounter = ++this->RebuildCounter;
474 PCHs = this->PCHs;
475
476 // Remember the preamble to be used during rebuild.
477 OldPreamble = this->LatestAvailablePreamble;
478 // Setup std::promises and std::futures for Preamble and AST. Corresponding
479 // futures will wait until the rebuild process is finished.
480 if (futureIsReady(this->PreambleFuture)) {
481 this->PreamblePromise =
482 std::promise<std::shared_ptr<const PreambleData>>();
483 this->PreambleFuture = this->PreamblePromise.get_future();
484 }
485 if (futureIsReady(this->ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000486 this->ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000487 this->ASTFuture = this->ASTPromise.get_future();
488 }
489 } // unlock Mutex.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000490 // Notify about changes to RebuildCounter.
491 RebuildCond.notify_all();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000492
493 // A helper to function to finish the rebuild. May be run on a different
494 // thread.
495
496 // Don't let this CppFile die before rebuild is finished.
497 std::shared_ptr<CppFile> That = shared_from_this();
Ilya Biryukov940901e2017-12-13 12:51:22 +0000498 auto FinishRebuild =
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000499 [OldPreamble, RequestRebuildCounter, PCHs,
Sam McCalld1a7a372018-01-31 13:40:48 +0000500 That](ParseInputs Inputs) mutable /* to allow changing OldPreamble. */
Ilya Biryukov02d58702017-08-01 15:51:38 +0000501 -> llvm::Optional<std::vector<DiagWithFixIts>> {
Sam McCalld1a7a372018-01-31 13:40:48 +0000502 log("Rebuilding file " + That->FileName + " with command [" +
503 Inputs.CompileCommand.Directory + "] " +
504 llvm::join(Inputs.CompileCommand.CommandLine, " "));
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000505
Ilya Biryukov02d58702017-08-01 15:51:38 +0000506 // Only one execution of this method is possible at a time.
507 // RebuildGuard will wait for any ongoing rebuilds to finish and will put us
508 // into a state for doing a rebuild.
509 RebuildGuard Rebuild(*That, RequestRebuildCounter);
510 if (Rebuild.wasCancelledBeforeConstruction())
511 return llvm::None;
512
513 std::vector<const char *> ArgStrs;
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000514 for (const auto &S : Inputs.CompileCommand.CommandLine)
Ilya Biryukov02d58702017-08-01 15:51:38 +0000515 ArgStrs.push_back(S.c_str());
516
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000517 Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000518
519 std::unique_ptr<CompilerInvocation> CI;
520 {
521 // FIXME(ibiryukov): store diagnostics from CommandLine when we start
522 // reporting them.
Sam McCall98775c52017-12-04 13:49:59 +0000523 IgnoreDiagnostics IgnoreDiagnostics;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000524 IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
525 CompilerInstance::createDiagnostics(new DiagnosticOptions,
Sam McCall98775c52017-12-04 13:49:59 +0000526 &IgnoreDiagnostics, false);
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000527 CI = createInvocationFromCommandLine(ArgStrs, CommandLineDiagsEngine,
528 Inputs.FS);
Sam McCall98775c52017-12-04 13:49:59 +0000529 // createInvocationFromCommandLine sets DisableFree.
530 CI->getFrontendOpts().DisableFree = false;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000531 }
532 assert(CI && "Couldn't create CompilerInvocation");
533
534 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000535 llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, That->FileName);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000536
537 // A helper function to rebuild the preamble or reuse the existing one. Does
Ilya Biryukov11a02522017-11-17 19:05:56 +0000538 // not mutate any fields of CppFile, only does the actual computation.
539 // Lamdba is marked mutable to call reset() on OldPreamble.
540 auto DoRebuildPreamble =
541 [&]() mutable -> std::shared_ptr<const PreambleData> {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000542 auto Bounds =
543 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000544 if (OldPreamble &&
545 OldPreamble->Preamble.CanReuse(*CI, ContentsBuffer.get(), Bounds,
546 Inputs.FS.get())) {
Sam McCalld1a7a372018-01-31 13:40:48 +0000547 log("Reusing preamble for file " + Twine(That->FileName));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000548 return OldPreamble;
549 }
Benjamin Kramer5eb6a282018-02-06 20:08:23 +0000550 log("Preamble for file " + Twine(That->FileName) +
Sam McCalld1a7a372018-01-31 13:40:48 +0000551 " cannot be reused. Attempting to rebuild it.");
Ilya Biryukoveaeea042017-12-21 14:05:28 +0000552 // We won't need the OldPreamble anymore, release it so it can be
553 // deleted (if there are no other references to it).
Ilya Biryukov11a02522017-11-17 19:05:56 +0000554 OldPreamble.reset();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000555
Sam McCalld1a7a372018-01-31 13:40:48 +0000556 trace::Span Tracer("Preamble");
Sam McCall9cfd9c92017-11-23 17:12:04 +0000557 SPAN_ATTACH(Tracer, "File", That->FileName);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000558 std::vector<DiagWithFixIts> PreambleDiags;
559 StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
560 IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
561 CompilerInstance::createDiagnostics(
562 &CI->getDiagnosticOpts(), &PreambleDiagnosticsConsumer, false);
Ilya Biryukovda8daa32017-12-28 13:10:15 +0000563
564 // Skip function bodies when building the preamble to speed up building
565 // the preamble and make it smaller.
566 assert(!CI->getFrontendOpts().SkipFunctionBodies);
567 CI->getFrontendOpts().SkipFunctionBodies = true;
568
Ilya Biryukov02d58702017-08-01 15:51:38 +0000569 CppFilePreambleCallbacks SerializedDeclsCollector;
570 auto BuiltPreamble = PrecompiledPreamble::Build(
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000571 *CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, Inputs.FS,
572 PCHs,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000573 /*StoreInMemory=*/That->StorePreamblesInMemory,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000574 SerializedDeclsCollector);
575
Ilya Biryukovda8daa32017-12-28 13:10:15 +0000576 // When building the AST for the main file, we do want the function
577 // bodies.
578 CI->getFrontendOpts().SkipFunctionBodies = false;
579
Ilya Biryukov02d58702017-08-01 15:51:38 +0000580 if (BuiltPreamble) {
Sam McCalld1a7a372018-01-31 13:40:48 +0000581 log("Built preamble of size " + Twine(BuiltPreamble->getSize()) +
582 " for file " + Twine(That->FileName));
Ilya Biryukoveaeea042017-12-21 14:05:28 +0000583
Ilya Biryukov02d58702017-08-01 15:51:38 +0000584 return std::make_shared<PreambleData>(
585 std::move(*BuiltPreamble),
586 SerializedDeclsCollector.takeTopLevelDeclIDs(),
587 std::move(PreambleDiags));
588 } else {
Sam McCalld1a7a372018-01-31 13:40:48 +0000589 log("Could not build a preamble for file " + Twine(That->FileName));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000590 return nullptr;
591 }
592 };
593
594 // Compute updated Preamble.
595 std::shared_ptr<const PreambleData> NewPreamble = DoRebuildPreamble();
596 // Publish the new Preamble.
597 {
598 std::lock_guard<std::mutex> Lock(That->Mutex);
599 // We always set LatestAvailablePreamble to the new value, hoping that it
600 // will still be usable in the further requests.
601 That->LatestAvailablePreamble = NewPreamble;
602 if (RequestRebuildCounter != That->RebuildCounter)
603 return llvm::None; // Our rebuild request was cancelled, do nothing.
Ilya Biryukovdf842342018-01-25 14:32:21 +0000604 That->PreambleMemUsage =
605 NewPreamble ? NewPreamble->Preamble.getSize() : 0;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000606 That->PreamblePromise.set_value(NewPreamble);
607 } // unlock Mutex
608
609 // Prepare the Preamble and supplementary data for rebuilding AST.
Ilya Biryukov02d58702017-08-01 15:51:38 +0000610 std::vector<DiagWithFixIts> Diagnostics;
611 if (NewPreamble) {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000612 Diagnostics.insert(Diagnostics.begin(), NewPreamble->Diags.begin(),
613 NewPreamble->Diags.end());
614 }
615
616 // Compute updated AST.
Sam McCall8567cb32017-11-02 09:21:51 +0000617 llvm::Optional<ParsedAST> NewAST;
618 {
Sam McCalld1a7a372018-01-31 13:40:48 +0000619 trace::Span Tracer("Build");
Sam McCall9cfd9c92017-11-23 17:12:04 +0000620 SPAN_ATTACH(Tracer, "File", That->FileName);
Sam McCalld1a7a372018-01-31 13:40:48 +0000621 NewAST = ParsedAST::Build(std::move(CI), std::move(NewPreamble),
622 std::move(ContentsBuffer), PCHs, Inputs.FS);
Sam McCall8567cb32017-11-02 09:21:51 +0000623 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000624
625 if (NewAST) {
626 Diagnostics.insert(Diagnostics.end(), NewAST->getDiagnostics().begin(),
627 NewAST->getDiagnostics().end());
Eric Liubfac8f72017-12-19 18:00:37 +0000628 if (That->ASTCallback)
Sam McCalld1a7a372018-01-31 13:40:48 +0000629 That->ASTCallback(That->FileName, NewAST.getPointer());
Ilya Biryukov02d58702017-08-01 15:51:38 +0000630 } else {
Benjamin Kramer5eb6a282018-02-06 20:08:23 +0000631 // Don't report even Preamble diagnostics if we couldn't build AST.
Ilya Biryukov02d58702017-08-01 15:51:38 +0000632 Diagnostics.clear();
633 }
634
635 // Publish the new AST.
636 {
637 std::lock_guard<std::mutex> Lock(That->Mutex);
638 if (RequestRebuildCounter != That->RebuildCounter)
639 return Diagnostics; // Our rebuild request was cancelled, don't set
640 // ASTPromise.
641
Ilya Biryukovdf842342018-01-25 14:32:21 +0000642 That->ASTMemUsage = NewAST ? NewAST->getUsedBytes() : 0;
Ilya Biryukov574b7532017-08-02 09:08:39 +0000643 That->ASTPromise.set_value(
644 std::make_shared<ParsedASTWrapper>(std::move(NewAST)));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000645 } // unlock Mutex
646
647 return Diagnostics;
648 };
649
Ilya Biryukov82b59ae2018-01-23 15:07:52 +0000650 return BindWithForward(FinishRebuild, std::move(Inputs));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000651}
652
653std::shared_future<std::shared_ptr<const PreambleData>>
654CppFile::getPreamble() const {
655 std::lock_guard<std::mutex> Lock(Mutex);
656 return PreambleFuture;
657}
658
659std::shared_ptr<const PreambleData> CppFile::getPossiblyStalePreamble() const {
660 std::lock_guard<std::mutex> Lock(Mutex);
661 return LatestAvailablePreamble;
662}
663
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000664std::shared_future<std::shared_ptr<ParsedASTWrapper>> CppFile::getAST() const {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000665 std::lock_guard<std::mutex> Lock(Mutex);
666 return ASTFuture;
667}
668
Ilya Biryukovdf842342018-01-25 14:32:21 +0000669std::size_t CppFile::getUsedBytes() const {
670 std::lock_guard<std::mutex> Lock(Mutex);
671 // FIXME: We should not store extra size fields. When we store AST and
672 // Preamble directly, not inside futures, we could compute the sizes from the
673 // stored AST and the preamble in this function directly.
674 return ASTMemUsage + PreambleMemUsage;
675}
676
Ilya Biryukov02d58702017-08-01 15:51:38 +0000677CppFile::RebuildGuard::RebuildGuard(CppFile &File,
678 unsigned RequestRebuildCounter)
679 : File(File), RequestRebuildCounter(RequestRebuildCounter) {
680 std::unique_lock<std::mutex> Lock(File.Mutex);
681 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
682 if (WasCancelledBeforeConstruction)
683 return;
684
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000685 File.RebuildCond.wait(Lock, [&File, RequestRebuildCounter]() {
686 return !File.RebuildInProgress ||
687 File.RebuildCounter != RequestRebuildCounter;
688 });
Ilya Biryukov02d58702017-08-01 15:51:38 +0000689
690 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
691 if (WasCancelledBeforeConstruction)
692 return;
693
694 File.RebuildInProgress = true;
695}
696
697bool CppFile::RebuildGuard::wasCancelledBeforeConstruction() const {
698 return WasCancelledBeforeConstruction;
699}
700
701CppFile::RebuildGuard::~RebuildGuard() {
702 if (WasCancelledBeforeConstruction)
703 return;
704
705 std::unique_lock<std::mutex> Lock(File.Mutex);
706 assert(File.RebuildInProgress);
707 File.RebuildInProgress = false;
708
709 if (File.RebuildCounter == RequestRebuildCounter) {
710 // Our rebuild request was successful.
711 assert(futureIsReady(File.ASTFuture));
712 assert(futureIsReady(File.PreambleFuture));
713 } else {
714 // Our rebuild request was cancelled, because further reparse was requested.
715 assert(!futureIsReady(File.ASTFuture));
716 assert(!futureIsReady(File.PreambleFuture));
717 }
718
719 Lock.unlock();
720 File.RebuildCond.notify_all();
721}
Haojian Wu345099c2017-11-09 11:30:04 +0000722
723SourceLocation clangd::getBeginningOfIdentifier(ParsedAST &Unit,
724 const Position &Pos,
725 const FileEntry *FE) {
726 // The language server protocol uses zero-based line and column numbers.
727 // Clang uses one-based numbers.
728
729 const ASTContext &AST = Unit.getASTContext();
730 const SourceManager &SourceMgr = AST.getSourceManager();
731
732 SourceLocation InputLocation =
733 getMacroArgExpandedLocation(SourceMgr, FE, Pos);
734 if (Pos.character == 0) {
735 return InputLocation;
736 }
737
738 // This handle cases where the position is in the middle of a token or right
739 // after the end of a token. In theory we could just use GetBeginningOfToken
740 // to find the start of the token at the input position, but this doesn't
741 // work when right after the end, i.e. foo|.
Benjamin Kramer5eb6a282018-02-06 20:08:23 +0000742 // So try to go back by one and see if we're still inside an identifier
Haojian Wu345099c2017-11-09 11:30:04 +0000743 // token. If so, Take the beginning of this token.
744 // (It should be the same identifier because you can't have two adjacent
745 // identifiers without another token in between.)
746 SourceLocation PeekBeforeLocation = getMacroArgExpandedLocation(
747 SourceMgr, FE, Position{Pos.line, Pos.character - 1});
748 Token Result;
749 if (Lexer::getRawToken(PeekBeforeLocation, Result, SourceMgr,
750 AST.getLangOpts(), false)) {
751 // getRawToken failed, just use InputLocation.
752 return InputLocation;
753 }
754
755 if (Result.is(tok::raw_identifier)) {
756 return Lexer::GetBeginningOfToken(PeekBeforeLocation, SourceMgr,
757 AST.getLangOpts());
758 }
759
760 return InputLocation;
761}