blob: c699c2f0a4090ce531cafb58a18b5b43594b19c6 [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"
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000011
Sam McCall98775c52017-12-04 13:49:59 +000012#include "Compiler.h"
Ilya Biryukov83ca8a22017-09-20 10:46:58 +000013#include "Logger.h"
Sam McCall8567cb32017-11-02 09:21:51 +000014#include "Trace.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000015#include "clang/Frontend/CompilerInstance.h"
16#include "clang/Frontend/CompilerInvocation.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000017#include "clang/Frontend/FrontendActions.h"
Ilya Biryukov0f62ed22017-05-26 12:26:51 +000018#include "clang/Frontend/Utils.h"
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000019#include "clang/Index/IndexDataConsumer.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000020#include "clang/Index/IndexingAction.h"
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000021#include "clang/Lex/Lexer.h"
22#include "clang/Lex/MacroInfo.h"
23#include "clang/Lex/Preprocessor.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000024#include "clang/Sema/Sema.h"
25#include "clang/Serialization/ASTWriter.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000026#include "clang/Tooling/CompilationDatabase.h"
Ilya Biryukov04db3682017-07-21 13:29:29 +000027#include "llvm/ADT/ArrayRef.h"
28#include "llvm/ADT/SmallVector.h"
29#include "llvm/Support/CrashRecoveryContext.h"
Krasimir Georgieva1de3c92017-06-15 09:11:57 +000030#include "llvm/Support/Format.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000031
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000032#include <algorithm>
Ilya Biryukov02d58702017-08-01 15:51:38 +000033#include <chrono>
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000034
Ilya Biryukov38d79772017-05-16 09:38:59 +000035using namespace clang::clangd;
36using namespace clang;
37
Ilya Biryukov04db3682017-07-21 13:29:29 +000038namespace {
39
40class DeclTrackingASTConsumer : public ASTConsumer {
41public:
42 DeclTrackingASTConsumer(std::vector<const Decl *> &TopLevelDecls)
43 : TopLevelDecls(TopLevelDecls) {}
44
45 bool HandleTopLevelDecl(DeclGroupRef DG) override {
46 for (const Decl *D : DG) {
47 // ObjCMethodDecl are not actually top-level decls.
48 if (isa<ObjCMethodDecl>(D))
49 continue;
50
51 TopLevelDecls.push_back(D);
52 }
53 return true;
54 }
55
56private:
57 std::vector<const Decl *> &TopLevelDecls;
58};
59
60class ClangdFrontendAction : public SyntaxOnlyAction {
61public:
62 std::vector<const Decl *> takeTopLevelDecls() {
63 return std::move(TopLevelDecls);
64 }
65
66protected:
67 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
68 StringRef InFile) override {
69 return llvm::make_unique<DeclTrackingASTConsumer>(/*ref*/ TopLevelDecls);
70 }
71
72private:
73 std::vector<const Decl *> TopLevelDecls;
74};
75
Ilya Biryukov02d58702017-08-01 15:51:38 +000076class CppFilePreambleCallbacks : public PreambleCallbacks {
Ilya Biryukov04db3682017-07-21 13:29:29 +000077public:
78 std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
79 return std::move(TopLevelDeclIDs);
80 }
81
82 void AfterPCHEmitted(ASTWriter &Writer) override {
83 TopLevelDeclIDs.reserve(TopLevelDecls.size());
84 for (Decl *D : TopLevelDecls) {
85 // Invalid top-level decls may not have been serialized.
86 if (D->isInvalidDecl())
87 continue;
88 TopLevelDeclIDs.push_back(Writer.getDeclID(D));
89 }
90 }
91
92 void HandleTopLevelDecl(DeclGroupRef DG) override {
93 for (Decl *D : DG) {
94 if (isa<ObjCMethodDecl>(D))
95 continue;
96 TopLevelDecls.push_back(D);
97 }
98 }
99
100private:
101 std::vector<Decl *> TopLevelDecls;
102 std::vector<serialization::DeclID> TopLevelDeclIDs;
103};
104
105/// Convert from clang diagnostic level to LSP severity.
106static int getSeverity(DiagnosticsEngine::Level L) {
107 switch (L) {
108 case DiagnosticsEngine::Remark:
109 return 4;
110 case DiagnosticsEngine::Note:
111 return 3;
112 case DiagnosticsEngine::Warning:
113 return 2;
114 case DiagnosticsEngine::Fatal:
115 case DiagnosticsEngine::Error:
116 return 1;
117 case DiagnosticsEngine::Ignored:
118 return 0;
119 }
120 llvm_unreachable("Unknown diagnostic level!");
121}
122
Sam McCall8111d3b2017-12-13 08:48:42 +0000123// Checks whether a location is within a half-open range.
124// Note that clang also uses closed source ranges, which this can't handle!
125bool locationInRange(SourceLocation L, CharSourceRange R,
126 const SourceManager &M) {
127 assert(R.isCharRange());
128 if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
129 M.getFileID(R.getBegin()) != M.getFileID(L))
130 return false;
131 return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
132}
133
134// Converts a half-open clang source range to an LSP range.
135// Note that clang also uses closed source ranges, which this can't handle!
136Range toRange(CharSourceRange R, const SourceManager &M) {
137 // Clang is 1-based, LSP uses 0-based indexes.
138 return {{static_cast<int>(M.getSpellingLineNumber(R.getBegin())) - 1,
139 static_cast<int>(M.getSpellingColumnNumber(R.getBegin())) - 1},
140 {static_cast<int>(M.getSpellingLineNumber(R.getEnd())) - 1,
141 static_cast<int>(M.getSpellingColumnNumber(R.getEnd())) - 1}};
142}
143
144// Clang diags have a location (shown as ^) and 0 or more ranges (~~~~).
145// LSP needs a single range.
146Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
147 auto &M = D.getSourceManager();
148 auto Loc = M.getFileLoc(D.getLocation());
149 // Accept the first range that contains the location.
150 for (const auto &CR : D.getRanges()) {
151 auto R = Lexer::makeFileCharRange(CR, M, L);
152 if (locationInRange(Loc, R, M))
153 return toRange(R, M);
154 }
155 // The range may be given as a fixit hint instead.
156 for (const auto &F : D.getFixItHints()) {
157 auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
158 if (locationInRange(Loc, R, M))
159 return toRange(R, M);
160 }
161 // If no suitable range is found, just use the token at the location.
162 auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L);
163 if (!R.isValid()) // Fall back to location only, let the editor deal with it.
164 R = CharSourceRange::getCharRange(Loc);
165 return toRange(R, M);
166}
167
168TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M,
169 const LangOptions &L) {
170 TextEdit Result;
171 Result.range = toRange(Lexer::makeFileCharRange(FixIt.RemoveRange, M, L), M);
172 Result.newText = FixIt.CodeToInsert;
173 return Result;
174}
175
176llvm::Optional<DiagWithFixIts> toClangdDiag(const clang::Diagnostic &D,
177 DiagnosticsEngine::Level Level,
178 const LangOptions &LangOpts) {
179 if (!D.hasSourceManager() || !D.getLocation().isValid() ||
180 !D.getSourceManager().isInMainFile(D.getLocation()))
Ilya Biryukov04db3682017-07-21 13:29:29 +0000181 return llvm::None;
182
Sam McCall8111d3b2017-12-13 08:48:42 +0000183 DiagWithFixIts Result;
184 Result.Diag.range = diagnosticRange(D, LangOpts);
185 Result.Diag.severity = getSeverity(Level);
186 SmallString<64> Message;
187 D.FormatDiagnostic(Message);
188 Result.Diag.message = Message.str();
189 for (const FixItHint &Fix : D.getFixItHints())
190 Result.FixIts.push_back(toTextEdit(Fix, D.getSourceManager(), LangOpts));
191 return std::move(Result);
Ilya Biryukov04db3682017-07-21 13:29:29 +0000192}
193
194class StoreDiagsConsumer : public DiagnosticConsumer {
195public:
196 StoreDiagsConsumer(std::vector<DiagWithFixIts> &Output) : Output(Output) {}
197
Sam McCall8111d3b2017-12-13 08:48:42 +0000198 // Track language options in case we need to expand token ranges.
199 void BeginSourceFile(const LangOptions &Opts, const Preprocessor *) override {
200 LangOpts = Opts;
201 }
202
203 void EndSourceFile() override { LangOpts = llvm::None; }
204
Ilya Biryukov04db3682017-07-21 13:29:29 +0000205 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
206 const clang::Diagnostic &Info) override {
207 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
208
Sam McCall8111d3b2017-12-13 08:48:42 +0000209 if (LangOpts)
210 if (auto D = toClangdDiag(Info, DiagLevel, *LangOpts))
211 Output.push_back(std::move(*D));
Ilya Biryukov04db3682017-07-21 13:29:29 +0000212 }
213
214private:
215 std::vector<DiagWithFixIts> &Output;
Sam McCall8111d3b2017-12-13 08:48:42 +0000216 llvm::Optional<LangOptions> LangOpts;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000217};
218
Ilya Biryukov02d58702017-08-01 15:51:38 +0000219template <class T> bool futureIsReady(std::shared_future<T> const &Future) {
220 return Future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
221}
222
Ilya Biryukov04db3682017-07-21 13:29:29 +0000223} // namespace
224
Ilya Biryukov02d58702017-08-01 15:51:38 +0000225void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
226 AST.getASTContext().getTranslationUnitDecl()->dump(OS, true);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000227}
Ilya Biryukovf01af682017-05-23 13:42:59 +0000228
Ilya Biryukov02d58702017-08-01 15:51:38 +0000229llvm::Optional<ParsedAST>
230ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI,
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000231 std::shared_ptr<const PreambleData> Preamble,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000232 std::unique_ptr<llvm::MemoryBuffer> Buffer,
233 std::shared_ptr<PCHContainerOperations> PCHs,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000234 IntrusiveRefCntPtr<vfs::FileSystem> VFS,
235 clangd::Logger &Logger) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000236
237 std::vector<DiagWithFixIts> ASTDiags;
238 StoreDiagsConsumer UnitDiagsConsumer(/*ref*/ ASTDiags);
239
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000240 const PrecompiledPreamble *PreamblePCH =
241 Preamble ? &Preamble->Preamble : nullptr;
Benjamin Kramer5349eed2017-10-28 17:32:56 +0000242 auto Clang = prepareCompilerInstance(
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000243 std::move(CI), PreamblePCH, std::move(Buffer), std::move(PCHs),
Benjamin Kramer5349eed2017-10-28 17:32:56 +0000244 std::move(VFS), /*ref*/ UnitDiagsConsumer);
Ilya Biryukov04db3682017-07-21 13:29:29 +0000245
246 // Recover resources if we crash before exiting this method.
247 llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
248 Clang.get());
249
250 auto Action = llvm::make_unique<ClangdFrontendAction>();
Ilya Biryukove5128f72017-09-20 07:24:15 +0000251 const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
252 if (!Action->BeginSourceFile(*Clang, MainInput)) {
253 Logger.log("BeginSourceFile() failed when building AST for " +
254 MainInput.getFile());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000255 return llvm::None;
256 }
Ilya Biryukove5128f72017-09-20 07:24:15 +0000257 if (!Action->Execute())
258 Logger.log("Execute() failed when building AST for " + MainInput.getFile());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000259
260 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
261 // has a longer lifetime.
Sam McCall98775c52017-12-04 13:49:59 +0000262 Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
Ilya Biryukov04db3682017-07-21 13:29:29 +0000263
264 std::vector<const Decl *> ParsedDecls = Action->takeTopLevelDecls();
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000265 return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action),
266 std::move(ParsedDecls), std::move(ASTDiags));
Ilya Biryukov04db3682017-07-21 13:29:29 +0000267}
268
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000269namespace {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000270
271SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
272 const FileEntry *FE,
273 unsigned Offset) {
274 SourceLocation FileLoc = Mgr.translateFileLineCol(FE, 1, 1);
275 return Mgr.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset));
276}
277
278SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
279 const FileEntry *FE, Position Pos) {
280 SourceLocation InputLoc =
281 Mgr.translateFileLineCol(FE, Pos.line + 1, Pos.character + 1);
282 return Mgr.getMacroArgExpandedLocation(InputLoc);
283}
284
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000285/// Finds declarations locations that a given source location refers to.
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000286class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
287 std::vector<const Decl *> Decls;
288 std::vector<const MacroInfo *> MacroInfos;
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000289 const SourceLocation &SearchedLocation;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000290 const ASTContext &AST;
291 Preprocessor &PP;
292
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000293public:
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000294 DeclarationAndMacrosFinder(raw_ostream &OS,
Ilya Biryukov04db3682017-07-21 13:29:29 +0000295 const SourceLocation &SearchedLocation,
296 ASTContext &AST, Preprocessor &PP)
297 : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000298
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000299 std::vector<const Decl *> takeDecls() {
300 // Don't keep the same declaration multiple times.
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000301 // This can happen when nodes in the AST are visited twice.
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000302 std::sort(Decls.begin(), Decls.end());
303 auto Last = std::unique(Decls.begin(), Decls.end());
304 Decls.erase(Last, Decls.end());
305 return std::move(Decls);
306 }
307
308 std::vector<const MacroInfo *> takeMacroInfos() {
309 // Don't keep the same Macro info multiple times.
310 std::sort(MacroInfos.begin(), MacroInfos.end());
311 auto Last = std::unique(MacroInfos.begin(), MacroInfos.end());
312 MacroInfos.erase(Last, MacroInfos.end());
313 return std::move(MacroInfos);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000314 }
315
Ilya Biryukov02d58702017-08-01 15:51:38 +0000316 bool
317 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
318 ArrayRef<index::SymbolRelation> Relations, FileID FID,
319 unsigned Offset,
320 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000321 if (isSearchedLocation(FID, Offset))
322 Decls.push_back(D);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000323 return true;
324 }
325
326private:
327 bool isSearchedLocation(FileID FID, unsigned Offset) const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000328 const SourceManager &SourceMgr = AST.getSourceManager();
329 return SourceMgr.getFileOffset(SearchedLocation) == Offset &&
330 SourceMgr.getFileID(SearchedLocation) == FID;
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000331 }
332
Kirill Bobyrev46213872017-06-28 20:57:28 +0000333 void finish() override {
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000334 // Also handle possible macro at the searched location.
335 Token Result;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000336 if (!Lexer::getRawToken(SearchedLocation, Result, AST.getSourceManager(),
337 AST.getLangOpts(), false)) {
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000338 if (Result.is(tok::raw_identifier)) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000339 PP.LookUpIdentifierInfo(Result);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000340 }
Ilya Biryukov04db3682017-07-21 13:29:29 +0000341 IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000342 if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
343 std::pair<FileID, unsigned int> DecLoc =
Ilya Biryukov04db3682017-07-21 13:29:29 +0000344 AST.getSourceManager().getDecomposedExpansionLoc(SearchedLocation);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000345 // Get the definition just before the searched location so that a macro
346 // referenced in a '#undef MACRO' can still be found.
Ilya Biryukov04db3682017-07-21 13:29:29 +0000347 SourceLocation BeforeSearchedLocation = getMacroArgExpandedLocation(
348 AST.getSourceManager(),
349 AST.getSourceManager().getFileEntryForID(DecLoc.first),
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000350 DecLoc.second - 1);
351 MacroDefinition MacroDef =
Ilya Biryukov04db3682017-07-21 13:29:29 +0000352 PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
353 MacroInfo *MacroInf = MacroDef.getMacroInfo();
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000354 if (MacroInf) {
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000355 MacroInfos.push_back(MacroInf);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000356 }
357 }
358 }
359 }
360};
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000361
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000362/// Finds document highlights that a given list of declarations refers to.
363class DocumentHighlightsFinder : public index::IndexDataConsumer {
364 std::vector<const Decl *> &Decls;
365 std::vector<DocumentHighlight> DocumentHighlights;
366 const ASTContext &AST;
367
368public:
369 DocumentHighlightsFinder(raw_ostream &OS, ASTContext &AST, Preprocessor &PP,
370 std::vector<const Decl *> &Decls)
371 : Decls(Decls), AST(AST) {}
372 std::vector<DocumentHighlight> takeHighlights() {
373 // Don't keep the same highlight multiple times.
374 // This can happen when nodes in the AST are visited twice.
375 std::sort(DocumentHighlights.begin(), DocumentHighlights.end());
376 auto Last =
377 std::unique(DocumentHighlights.begin(), DocumentHighlights.end());
378 DocumentHighlights.erase(Last, DocumentHighlights.end());
379 return std::move(DocumentHighlights);
380 }
381
382 bool
383 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
384 ArrayRef<index::SymbolRelation> Relations, FileID FID,
385 unsigned Offset,
386 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
387 const SourceManager &SourceMgr = AST.getSourceManager();
388 if (SourceMgr.getMainFileID() != FID ||
389 std::find(Decls.begin(), Decls.end(), D) == Decls.end()) {
390 return true;
391 }
Ilya Biryukovef3191f2017-12-12 14:15:01 +0000392 SourceLocation End;
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000393 const LangOptions &LangOpts = AST.getLangOpts();
394 SourceLocation StartOfFileLoc = SourceMgr.getLocForStartOfFile(FID);
395 SourceLocation HightlightStartLoc = StartOfFileLoc.getLocWithOffset(Offset);
396 End =
397 Lexer::getLocForEndOfToken(HightlightStartLoc, 0, SourceMgr, LangOpts);
398 SourceRange SR(HightlightStartLoc, End);
399
400 DocumentHighlightKind Kind = DocumentHighlightKind::Text;
401 if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Write) & Roles)
402 Kind = DocumentHighlightKind::Write;
403 else if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Read) & Roles)
404 Kind = DocumentHighlightKind::Read;
405
406 DocumentHighlights.push_back(getDocumentHighlight(SR, Kind));
407 return true;
408 }
409
410private:
411 DocumentHighlight getDocumentHighlight(SourceRange SR,
412 DocumentHighlightKind Kind) {
413 const SourceManager &SourceMgr = AST.getSourceManager();
414 SourceLocation LocStart = SR.getBegin();
415 Position Begin;
416 Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
417 Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
418 Position End;
419 End.line = SourceMgr.getSpellingLineNumber(SR.getEnd()) - 1;
420 End.character = SourceMgr.getSpellingColumnNumber(SR.getEnd()) - 1;
421 Range R = {Begin, End};
422 DocumentHighlight DH;
423 DH.range = R;
424 DH.kind = Kind;
425 return DH;
426 }
427};
428
Ilya Biryukov02d58702017-08-01 15:51:38 +0000429} // namespace
Ilya Biryukov04db3682017-07-21 13:29:29 +0000430
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000431llvm::Optional<Location>
432getDeclarationLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
433 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
434 const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
435 SourceLocation LocStart = ValSourceRange.getBegin();
436
437 const FileEntry *F =
438 SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
439 if (!F)
440 return llvm::None;
441 SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(), 0,
442 SourceMgr, LangOpts);
443 Position Begin;
444 Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
445 Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
446 Position End;
447 End.line = SourceMgr.getSpellingLineNumber(LocEnd) - 1;
448 End.character = SourceMgr.getSpellingColumnNumber(LocEnd) - 1;
449 Range R = {Begin, End};
450 Location L;
451
452 StringRef FilePath = F->tryGetRealPathName();
453 if (FilePath.empty())
454 FilePath = F->getName();
455 L.uri = URI::fromFile(FilePath);
456 L.range = R;
457 return L;
458}
459
Ilya Biryukove5128f72017-09-20 07:24:15 +0000460std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
461 clangd::Logger &Logger) {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000462 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
463 const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
464 if (!FE)
465 return {};
466
467 SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
468
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000469 auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
Ilya Biryukov02d58702017-08-01 15:51:38 +0000470 llvm::errs(), SourceLocationBeg, AST.getASTContext(),
471 AST.getPreprocessor());
472 index::IndexingOptions IndexOpts;
473 IndexOpts.SystemSymbolFilter =
474 index::IndexingOptions::SystemSymbolFilterKind::All;
475 IndexOpts.IndexFunctionLocals = true;
476
477 indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000478 DeclMacrosFinder, IndexOpts);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000479
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000480 std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls();
481 std::vector<const MacroInfo *> MacroInfos =
482 DeclMacrosFinder->takeMacroInfos();
483 std::vector<Location> Result;
484
485 for (auto Item : Decls) {
486 auto L = getDeclarationLocation(AST, Item->getSourceRange());
487 if (L)
488 Result.push_back(*L);
489 }
490
491 for (auto Item : MacroInfos) {
492 SourceRange SR(Item->getDefinitionLoc(), Item->getDefinitionEndLoc());
493 auto L = getDeclarationLocation(AST, SR);
494 if (L)
495 Result.push_back(*L);
496 }
497
498 return Result;
499}
500
501std::vector<DocumentHighlight>
502clangd::findDocumentHighlights(ParsedAST &AST, Position Pos,
503 clangd::Logger &Logger) {
504 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
505 const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
506 if (!FE)
507 return {};
508
509 SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
510
511 auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
512 llvm::errs(), SourceLocationBeg, AST.getASTContext(),
513 AST.getPreprocessor());
514 index::IndexingOptions IndexOpts;
515 IndexOpts.SystemSymbolFilter =
516 index::IndexingOptions::SystemSymbolFilterKind::All;
517 IndexOpts.IndexFunctionLocals = true;
518
519 // Macro occurences are not currently handled.
520 indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
521 DeclMacrosFinder, IndexOpts);
522
523 std::vector<const Decl *> SelectedDecls = DeclMacrosFinder->takeDecls();
524
525 auto DocHighlightsFinder = std::make_shared<DocumentHighlightsFinder>(
526 llvm::errs(), AST.getASTContext(), AST.getPreprocessor(), SelectedDecls);
527
528 indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
529 DocHighlightsFinder, IndexOpts);
530
531 return DocHighlightsFinder->takeHighlights();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000532}
533
534void ParsedAST::ensurePreambleDeclsDeserialized() {
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000535 if (PreambleDeclsDeserialized || !Preamble)
Ilya Biryukov04db3682017-07-21 13:29:29 +0000536 return;
537
538 std::vector<const Decl *> Resolved;
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000539 Resolved.reserve(Preamble->TopLevelDeclIDs.size());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000540
541 ExternalASTSource &Source = *getASTContext().getExternalSource();
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000542 for (serialization::DeclID TopLevelDecl : Preamble->TopLevelDeclIDs) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000543 // Resolve the declaration ID to an actual declaration, possibly
544 // deserializing the declaration in the process.
545 if (Decl *D = Source.GetExternalDecl(TopLevelDecl))
546 Resolved.push_back(D);
547 }
548
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000549 TopLevelDecls.reserve(TopLevelDecls.size() +
550 Preamble->TopLevelDeclIDs.size());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000551 TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
552
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000553 PreambleDeclsDeserialized = true;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000554}
555
Ilya Biryukov02d58702017-08-01 15:51:38 +0000556ParsedAST::ParsedAST(ParsedAST &&Other) = default;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000557
Ilya Biryukov02d58702017-08-01 15:51:38 +0000558ParsedAST &ParsedAST::operator=(ParsedAST &&Other) = default;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000559
Ilya Biryukov02d58702017-08-01 15:51:38 +0000560ParsedAST::~ParsedAST() {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000561 if (Action) {
562 Action->EndSourceFile();
563 }
564}
565
Ilya Biryukov02d58702017-08-01 15:51:38 +0000566ASTContext &ParsedAST::getASTContext() { return Clang->getASTContext(); }
567
568const ASTContext &ParsedAST::getASTContext() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000569 return Clang->getASTContext();
570}
571
Ilya Biryukov02d58702017-08-01 15:51:38 +0000572Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
Ilya Biryukov04db3682017-07-21 13:29:29 +0000573
Ilya Biryukov02d58702017-08-01 15:51:38 +0000574const Preprocessor &ParsedAST::getPreprocessor() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000575 return Clang->getPreprocessor();
576}
577
Ilya Biryukov02d58702017-08-01 15:51:38 +0000578ArrayRef<const Decl *> ParsedAST::getTopLevelDecls() {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000579 ensurePreambleDeclsDeserialized();
580 return TopLevelDecls;
581}
582
Ilya Biryukov02d58702017-08-01 15:51:38 +0000583const std::vector<DiagWithFixIts> &ParsedAST::getDiagnostics() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000584 return Diags;
585}
586
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000587PreambleData::PreambleData(PrecompiledPreamble Preamble,
588 std::vector<serialization::DeclID> TopLevelDeclIDs,
589 std::vector<DiagWithFixIts> Diags)
590 : Preamble(std::move(Preamble)),
591 TopLevelDeclIDs(std::move(TopLevelDeclIDs)), Diags(std::move(Diags)) {}
592
593ParsedAST::ParsedAST(std::shared_ptr<const PreambleData> Preamble,
594 std::unique_ptr<CompilerInstance> Clang,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000595 std::unique_ptr<FrontendAction> Action,
596 std::vector<const Decl *> TopLevelDecls,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000597 std::vector<DiagWithFixIts> Diags)
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000598 : Preamble(std::move(Preamble)), Clang(std::move(Clang)),
599 Action(std::move(Action)), Diags(std::move(Diags)),
600 TopLevelDecls(std::move(TopLevelDecls)),
601 PreambleDeclsDeserialized(false) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000602 assert(this->Clang);
603 assert(this->Action);
604}
605
Ilya Biryukov02d58702017-08-01 15:51:38 +0000606ParsedASTWrapper::ParsedASTWrapper(ParsedASTWrapper &&Wrapper)
607 : AST(std::move(Wrapper.AST)) {}
608
609ParsedASTWrapper::ParsedASTWrapper(llvm::Optional<ParsedAST> AST)
610 : AST(std::move(AST)) {}
611
Ilya Biryukov02d58702017-08-01 15:51:38 +0000612std::shared_ptr<CppFile>
613CppFile::Create(PathRef FileName, tooling::CompileCommand Command,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000614 bool StorePreamblesInMemory,
Ilya Biryukov83ca8a22017-09-20 10:46:58 +0000615 std::shared_ptr<PCHContainerOperations> PCHs,
616 clangd::Logger &Logger) {
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000617 return std::shared_ptr<CppFile>(new CppFile(FileName, std::move(Command),
618 StorePreamblesInMemory,
619 std::move(PCHs), Logger));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000620}
621
622CppFile::CppFile(PathRef FileName, tooling::CompileCommand Command,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000623 bool StorePreamblesInMemory,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000624 std::shared_ptr<PCHContainerOperations> PCHs,
625 clangd::Logger &Logger)
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000626 : FileName(FileName), Command(std::move(Command)),
627 StorePreamblesInMemory(StorePreamblesInMemory), RebuildCounter(0),
Ilya Biryukove5128f72017-09-20 07:24:15 +0000628 RebuildInProgress(false), PCHs(std::move(PCHs)), Logger(Logger) {
Sam McCallfae3b022017-11-30 23:16:23 +0000629 Logger.log("Opened file " + FileName + " with command [" +
630 this->Command.Directory + "] " +
Sam McCall318fbeb2017-11-30 23:21:34 +0000631 llvm::join(this->Command.CommandLine, " "));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000632
633 std::lock_guard<std::mutex> Lock(Mutex);
634 LatestAvailablePreamble = nullptr;
635 PreamblePromise.set_value(nullptr);
636 PreambleFuture = PreamblePromise.get_future();
637
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000638 ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000639 ASTFuture = ASTPromise.get_future();
640}
641
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000642void CppFile::cancelRebuild() { deferCancelRebuild()(); }
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000643
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000644UniqueFunction<void()> CppFile::deferCancelRebuild() {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000645 std::unique_lock<std::mutex> Lock(Mutex);
646 // Cancel an ongoing rebuild, if any, and wait for it to finish.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000647 unsigned RequestRebuildCounter = ++this->RebuildCounter;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000648 // Rebuild asserts that futures aren't ready if rebuild is cancelled.
649 // We want to keep this invariant.
650 if (futureIsReady(PreambleFuture)) {
651 PreamblePromise = std::promise<std::shared_ptr<const PreambleData>>();
652 PreambleFuture = PreamblePromise.get_future();
653 }
654 if (futureIsReady(ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000655 ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000656 ASTFuture = ASTPromise.get_future();
657 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000658
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000659 Lock.unlock();
660 // Notify about changes to RebuildCounter.
661 RebuildCond.notify_all();
662
663 std::shared_ptr<CppFile> That = shared_from_this();
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000664 return [That, RequestRebuildCounter]() {
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000665 std::unique_lock<std::mutex> Lock(That->Mutex);
666 CppFile *This = &*That;
667 This->RebuildCond.wait(Lock, [This, RequestRebuildCounter]() {
668 return !This->RebuildInProgress ||
669 This->RebuildCounter != RequestRebuildCounter;
670 });
671
672 // This computation got cancelled itself, do nothing.
673 if (This->RebuildCounter != RequestRebuildCounter)
674 return;
675
676 // Set empty results for Promises.
677 That->PreamblePromise.set_value(nullptr);
678 That->ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000679 };
Ilya Biryukov02d58702017-08-01 15:51:38 +0000680}
681
682llvm::Optional<std::vector<DiagWithFixIts>>
683CppFile::rebuild(StringRef NewContents,
684 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000685 return deferRebuild(NewContents, std::move(VFS))();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000686}
687
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000688UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>()>
Ilya Biryukov02d58702017-08-01 15:51:38 +0000689CppFile::deferRebuild(StringRef NewContents,
690 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
691 std::shared_ptr<const PreambleData> OldPreamble;
692 std::shared_ptr<PCHContainerOperations> PCHs;
693 unsigned RequestRebuildCounter;
694 {
695 std::unique_lock<std::mutex> Lock(Mutex);
696 // Increase RebuildCounter to cancel all ongoing FinishRebuild operations.
697 // They will try to exit as early as possible and won't call set_value on
698 // our promises.
699 RequestRebuildCounter = ++this->RebuildCounter;
700 PCHs = this->PCHs;
701
702 // Remember the preamble to be used during rebuild.
703 OldPreamble = this->LatestAvailablePreamble;
704 // Setup std::promises and std::futures for Preamble and AST. Corresponding
705 // futures will wait until the rebuild process is finished.
706 if (futureIsReady(this->PreambleFuture)) {
707 this->PreamblePromise =
708 std::promise<std::shared_ptr<const PreambleData>>();
709 this->PreambleFuture = this->PreamblePromise.get_future();
710 }
711 if (futureIsReady(this->ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000712 this->ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000713 this->ASTFuture = this->ASTPromise.get_future();
714 }
715 } // unlock Mutex.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000716 // Notify about changes to RebuildCounter.
717 RebuildCond.notify_all();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000718
719 // A helper to function to finish the rebuild. May be run on a different
720 // thread.
721
722 // Don't let this CppFile die before rebuild is finished.
723 std::shared_ptr<CppFile> That = shared_from_this();
724 auto FinishRebuild = [OldPreamble, VFS, RequestRebuildCounter, PCHs,
Ilya Biryukov11a02522017-11-17 19:05:56 +0000725 That](std::string NewContents) mutable // 'mutable' to
726 // allow changing
727 // OldPreamble.
Ilya Biryukov02d58702017-08-01 15:51:38 +0000728 -> llvm::Optional<std::vector<DiagWithFixIts>> {
729 // Only one execution of this method is possible at a time.
730 // RebuildGuard will wait for any ongoing rebuilds to finish and will put us
731 // into a state for doing a rebuild.
732 RebuildGuard Rebuild(*That, RequestRebuildCounter);
733 if (Rebuild.wasCancelledBeforeConstruction())
734 return llvm::None;
735
736 std::vector<const char *> ArgStrs;
737 for (const auto &S : That->Command.CommandLine)
738 ArgStrs.push_back(S.c_str());
739
740 VFS->setCurrentWorkingDirectory(That->Command.Directory);
741
742 std::unique_ptr<CompilerInvocation> CI;
743 {
744 // FIXME(ibiryukov): store diagnostics from CommandLine when we start
745 // reporting them.
Sam McCall98775c52017-12-04 13:49:59 +0000746 IgnoreDiagnostics IgnoreDiagnostics;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000747 IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
748 CompilerInstance::createDiagnostics(new DiagnosticOptions,
Sam McCall98775c52017-12-04 13:49:59 +0000749 &IgnoreDiagnostics, false);
750 CI =
751 createInvocationFromCommandLine(ArgStrs, CommandLineDiagsEngine, VFS);
752 // createInvocationFromCommandLine sets DisableFree.
753 CI->getFrontendOpts().DisableFree = false;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000754 }
755 assert(CI && "Couldn't create CompilerInvocation");
756
757 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
758 llvm::MemoryBuffer::getMemBufferCopy(NewContents, That->FileName);
759
760 // A helper function to rebuild the preamble or reuse the existing one. Does
Ilya Biryukov11a02522017-11-17 19:05:56 +0000761 // not mutate any fields of CppFile, only does the actual computation.
762 // Lamdba is marked mutable to call reset() on OldPreamble.
763 auto DoRebuildPreamble =
764 [&]() mutable -> std::shared_ptr<const PreambleData> {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000765 auto Bounds =
766 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
767 if (OldPreamble && OldPreamble->Preamble.CanReuse(
768 *CI, ContentsBuffer.get(), Bounds, VFS.get())) {
769 return OldPreamble;
770 }
Ilya Biryukov11a02522017-11-17 19:05:56 +0000771 // We won't need the OldPreamble anymore, release it so it can be deleted
772 // (if there are no other references to it).
773 OldPreamble.reset();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000774
Sam McCall9cfd9c92017-11-23 17:12:04 +0000775 trace::Span Tracer("Preamble");
776 SPAN_ATTACH(Tracer, "File", That->FileName);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000777 std::vector<DiagWithFixIts> PreambleDiags;
778 StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
779 IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
780 CompilerInstance::createDiagnostics(
781 &CI->getDiagnosticOpts(), &PreambleDiagnosticsConsumer, false);
782 CppFilePreambleCallbacks SerializedDeclsCollector;
783 auto BuiltPreamble = PrecompiledPreamble::Build(
784 *CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, VFS, PCHs,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000785 /*StoreInMemory=*/That->StorePreamblesInMemory,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000786 SerializedDeclsCollector);
787
788 if (BuiltPreamble) {
789 return std::make_shared<PreambleData>(
790 std::move(*BuiltPreamble),
791 SerializedDeclsCollector.takeTopLevelDeclIDs(),
792 std::move(PreambleDiags));
793 } else {
794 return nullptr;
795 }
796 };
797
798 // Compute updated Preamble.
799 std::shared_ptr<const PreambleData> NewPreamble = DoRebuildPreamble();
800 // Publish the new Preamble.
801 {
802 std::lock_guard<std::mutex> Lock(That->Mutex);
803 // We always set LatestAvailablePreamble to the new value, hoping that it
804 // will still be usable in the further requests.
805 That->LatestAvailablePreamble = NewPreamble;
806 if (RequestRebuildCounter != That->RebuildCounter)
807 return llvm::None; // Our rebuild request was cancelled, do nothing.
808 That->PreamblePromise.set_value(NewPreamble);
809 } // unlock Mutex
810
811 // Prepare the Preamble and supplementary data for rebuilding AST.
Ilya Biryukov02d58702017-08-01 15:51:38 +0000812 std::vector<DiagWithFixIts> Diagnostics;
813 if (NewPreamble) {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000814 Diagnostics.insert(Diagnostics.begin(), NewPreamble->Diags.begin(),
815 NewPreamble->Diags.end());
816 }
817
818 // Compute updated AST.
Sam McCall8567cb32017-11-02 09:21:51 +0000819 llvm::Optional<ParsedAST> NewAST;
820 {
Sam McCall9cfd9c92017-11-23 17:12:04 +0000821 trace::Span Tracer("Build");
822 SPAN_ATTACH(Tracer, "File", That->FileName);
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000823 NewAST =
824 ParsedAST::Build(std::move(CI), std::move(NewPreamble),
825 std::move(ContentsBuffer), PCHs, VFS, That->Logger);
Sam McCall8567cb32017-11-02 09:21:51 +0000826 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000827
828 if (NewAST) {
829 Diagnostics.insert(Diagnostics.end(), NewAST->getDiagnostics().begin(),
830 NewAST->getDiagnostics().end());
831 } else {
832 // Don't report even Preamble diagnostics if we coulnd't build AST.
833 Diagnostics.clear();
834 }
835
836 // Publish the new AST.
837 {
838 std::lock_guard<std::mutex> Lock(That->Mutex);
839 if (RequestRebuildCounter != That->RebuildCounter)
840 return Diagnostics; // Our rebuild request was cancelled, don't set
841 // ASTPromise.
842
Ilya Biryukov574b7532017-08-02 09:08:39 +0000843 That->ASTPromise.set_value(
844 std::make_shared<ParsedASTWrapper>(std::move(NewAST)));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000845 } // unlock Mutex
846
847 return Diagnostics;
848 };
849
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000850 return BindWithForward(FinishRebuild, NewContents.str());
Ilya Biryukov02d58702017-08-01 15:51:38 +0000851}
852
853std::shared_future<std::shared_ptr<const PreambleData>>
854CppFile::getPreamble() const {
855 std::lock_guard<std::mutex> Lock(Mutex);
856 return PreambleFuture;
857}
858
859std::shared_ptr<const PreambleData> CppFile::getPossiblyStalePreamble() const {
860 std::lock_guard<std::mutex> Lock(Mutex);
861 return LatestAvailablePreamble;
862}
863
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000864std::shared_future<std::shared_ptr<ParsedASTWrapper>> CppFile::getAST() const {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000865 std::lock_guard<std::mutex> Lock(Mutex);
866 return ASTFuture;
867}
868
869tooling::CompileCommand const &CppFile::getCompileCommand() const {
870 return Command;
871}
872
873CppFile::RebuildGuard::RebuildGuard(CppFile &File,
874 unsigned RequestRebuildCounter)
875 : File(File), RequestRebuildCounter(RequestRebuildCounter) {
876 std::unique_lock<std::mutex> Lock(File.Mutex);
877 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
878 if (WasCancelledBeforeConstruction)
879 return;
880
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000881 File.RebuildCond.wait(Lock, [&File, RequestRebuildCounter]() {
882 return !File.RebuildInProgress ||
883 File.RebuildCounter != RequestRebuildCounter;
884 });
Ilya Biryukov02d58702017-08-01 15:51:38 +0000885
886 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
887 if (WasCancelledBeforeConstruction)
888 return;
889
890 File.RebuildInProgress = true;
891}
892
893bool CppFile::RebuildGuard::wasCancelledBeforeConstruction() const {
894 return WasCancelledBeforeConstruction;
895}
896
897CppFile::RebuildGuard::~RebuildGuard() {
898 if (WasCancelledBeforeConstruction)
899 return;
900
901 std::unique_lock<std::mutex> Lock(File.Mutex);
902 assert(File.RebuildInProgress);
903 File.RebuildInProgress = false;
904
905 if (File.RebuildCounter == RequestRebuildCounter) {
906 // Our rebuild request was successful.
907 assert(futureIsReady(File.ASTFuture));
908 assert(futureIsReady(File.PreambleFuture));
909 } else {
910 // Our rebuild request was cancelled, because further reparse was requested.
911 assert(!futureIsReady(File.ASTFuture));
912 assert(!futureIsReady(File.PreambleFuture));
913 }
914
915 Lock.unlock();
916 File.RebuildCond.notify_all();
917}
Haojian Wu345099c2017-11-09 11:30:04 +0000918
919SourceLocation clangd::getBeginningOfIdentifier(ParsedAST &Unit,
920 const Position &Pos,
921 const FileEntry *FE) {
922 // The language server protocol uses zero-based line and column numbers.
923 // Clang uses one-based numbers.
924
925 const ASTContext &AST = Unit.getASTContext();
926 const SourceManager &SourceMgr = AST.getSourceManager();
927
928 SourceLocation InputLocation =
929 getMacroArgExpandedLocation(SourceMgr, FE, Pos);
930 if (Pos.character == 0) {
931 return InputLocation;
932 }
933
934 // This handle cases where the position is in the middle of a token or right
935 // after the end of a token. In theory we could just use GetBeginningOfToken
936 // to find the start of the token at the input position, but this doesn't
937 // work when right after the end, i.e. foo|.
938 // So try to go back by one and see if we're still inside the an identifier
939 // token. If so, Take the beginning of this token.
940 // (It should be the same identifier because you can't have two adjacent
941 // identifiers without another token in between.)
942 SourceLocation PeekBeforeLocation = getMacroArgExpandedLocation(
943 SourceMgr, FE, Position{Pos.line, Pos.character - 1});
944 Token Result;
945 if (Lexer::getRawToken(PeekBeforeLocation, Result, SourceMgr,
946 AST.getLangOpts(), false)) {
947 // getRawToken failed, just use InputLocation.
948 return InputLocation;
949 }
950
951 if (Result.is(tok::raw_identifier)) {
952 return Lexer::GetBeginningOfToken(PeekBeforeLocation, SourceMgr,
953 AST.getLangOpts());
954 }
955
956 return InputLocation;
957}