blob: e72dc3b523ab8f276376eb21803616282083694e [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>
Ilya Biryukov940901e2017-12-13 12:51:22 +0000230ParsedAST::Build(const Context &Ctx,
231 std::unique_ptr<clang::CompilerInvocation> CI,
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000232 std::shared_ptr<const PreambleData> Preamble,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000233 std::unique_ptr<llvm::MemoryBuffer> Buffer,
234 std::shared_ptr<PCHContainerOperations> PCHs,
Ilya Biryukov940901e2017-12-13 12:51:22 +0000235 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
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)) {
Ilya Biryukov940901e2017-12-13 12:51:22 +0000253 log(Ctx, "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())
Ilya Biryukov940901e2017-12-13 12:51:22 +0000258 log(Ctx, "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 Biryukov940901e2017-12-13 12:51:22 +0000460std::vector<Location> clangd::findDefinitions(const Context &Ctx,
461 ParsedAST &AST, Position Pos) {
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>
Ilya Biryukov940901e2017-12-13 12:51:22 +0000502clangd::findDocumentHighlights(const Context &Ctx, ParsedAST &AST,
503 Position Pos) {
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000504 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 Biryukov940901e2017-12-13 12:51:22 +0000615 std::shared_ptr<PCHContainerOperations> PCHs) {
616 return std::shared_ptr<CppFile>(new CppFile(
617 FileName, std::move(Command), StorePreamblesInMemory, std::move(PCHs)));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000618}
619
620CppFile::CppFile(PathRef FileName, tooling::CompileCommand Command,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000621 bool StorePreamblesInMemory,
Ilya Biryukov940901e2017-12-13 12:51:22 +0000622 std::shared_ptr<PCHContainerOperations> PCHs)
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000623 : FileName(FileName), Command(std::move(Command)),
624 StorePreamblesInMemory(StorePreamblesInMemory), RebuildCounter(0),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000625 RebuildInProgress(false), PCHs(std::move(PCHs)) {
626 // FIXME(ibiryukov): we should pass a proper Context here.
627 log(Context::empty(), "Opened file " + FileName + " with command [" +
628 this->Command.Directory + "] " +
629 llvm::join(this->Command.CommandLine, " "));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000630
631 std::lock_guard<std::mutex> Lock(Mutex);
632 LatestAvailablePreamble = nullptr;
633 PreamblePromise.set_value(nullptr);
634 PreambleFuture = PreamblePromise.get_future();
635
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000636 ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000637 ASTFuture = ASTPromise.get_future();
638}
639
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000640void CppFile::cancelRebuild() { deferCancelRebuild()(); }
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000641
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000642UniqueFunction<void()> CppFile::deferCancelRebuild() {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000643 std::unique_lock<std::mutex> Lock(Mutex);
644 // Cancel an ongoing rebuild, if any, and wait for it to finish.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000645 unsigned RequestRebuildCounter = ++this->RebuildCounter;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000646 // Rebuild asserts that futures aren't ready if rebuild is cancelled.
647 // We want to keep this invariant.
648 if (futureIsReady(PreambleFuture)) {
649 PreamblePromise = std::promise<std::shared_ptr<const PreambleData>>();
650 PreambleFuture = PreamblePromise.get_future();
651 }
652 if (futureIsReady(ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000653 ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000654 ASTFuture = ASTPromise.get_future();
655 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000656
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000657 Lock.unlock();
658 // Notify about changes to RebuildCounter.
659 RebuildCond.notify_all();
660
661 std::shared_ptr<CppFile> That = shared_from_this();
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000662 return [That, RequestRebuildCounter]() {
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000663 std::unique_lock<std::mutex> Lock(That->Mutex);
664 CppFile *This = &*That;
665 This->RebuildCond.wait(Lock, [This, RequestRebuildCounter]() {
666 return !This->RebuildInProgress ||
667 This->RebuildCounter != RequestRebuildCounter;
668 });
669
670 // This computation got cancelled itself, do nothing.
671 if (This->RebuildCounter != RequestRebuildCounter)
672 return;
673
674 // Set empty results for Promises.
675 That->PreamblePromise.set_value(nullptr);
676 That->ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000677 };
Ilya Biryukov02d58702017-08-01 15:51:38 +0000678}
679
680llvm::Optional<std::vector<DiagWithFixIts>>
Ilya Biryukov940901e2017-12-13 12:51:22 +0000681CppFile::rebuild(const Context &Ctx, StringRef NewContents,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000682 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
Ilya Biryukov940901e2017-12-13 12:51:22 +0000683 return deferRebuild(NewContents, std::move(VFS))(Ctx);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000684}
685
Ilya Biryukov940901e2017-12-13 12:51:22 +0000686UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(const Context &)>
Ilya Biryukov02d58702017-08-01 15:51:38 +0000687CppFile::deferRebuild(StringRef NewContents,
688 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
689 std::shared_ptr<const PreambleData> OldPreamble;
690 std::shared_ptr<PCHContainerOperations> PCHs;
691 unsigned RequestRebuildCounter;
692 {
693 std::unique_lock<std::mutex> Lock(Mutex);
694 // Increase RebuildCounter to cancel all ongoing FinishRebuild operations.
695 // They will try to exit as early as possible and won't call set_value on
696 // our promises.
697 RequestRebuildCounter = ++this->RebuildCounter;
698 PCHs = this->PCHs;
699
700 // Remember the preamble to be used during rebuild.
701 OldPreamble = this->LatestAvailablePreamble;
702 // Setup std::promises and std::futures for Preamble and AST. Corresponding
703 // futures will wait until the rebuild process is finished.
704 if (futureIsReady(this->PreambleFuture)) {
705 this->PreamblePromise =
706 std::promise<std::shared_ptr<const PreambleData>>();
707 this->PreambleFuture = this->PreamblePromise.get_future();
708 }
709 if (futureIsReady(this->ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000710 this->ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000711 this->ASTFuture = this->ASTPromise.get_future();
712 }
713 } // unlock Mutex.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000714 // Notify about changes to RebuildCounter.
715 RebuildCond.notify_all();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000716
717 // A helper to function to finish the rebuild. May be run on a different
718 // thread.
719
720 // Don't let this CppFile die before rebuild is finished.
721 std::shared_ptr<CppFile> That = shared_from_this();
Ilya Biryukov940901e2017-12-13 12:51:22 +0000722 auto FinishRebuild =
723 [OldPreamble, VFS, RequestRebuildCounter, PCHs,
724 That](std::string NewContents,
725 const Context &Ctx) mutable /* to allow changing OldPreamble. */
Ilya Biryukov02d58702017-08-01 15:51:38 +0000726 -> llvm::Optional<std::vector<DiagWithFixIts>> {
727 // Only one execution of this method is possible at a time.
728 // RebuildGuard will wait for any ongoing rebuilds to finish and will put us
729 // into a state for doing a rebuild.
730 RebuildGuard Rebuild(*That, RequestRebuildCounter);
731 if (Rebuild.wasCancelledBeforeConstruction())
732 return llvm::None;
733
734 std::vector<const char *> ArgStrs;
735 for (const auto &S : That->Command.CommandLine)
736 ArgStrs.push_back(S.c_str());
737
738 VFS->setCurrentWorkingDirectory(That->Command.Directory);
739
740 std::unique_ptr<CompilerInvocation> CI;
741 {
742 // FIXME(ibiryukov): store diagnostics from CommandLine when we start
743 // reporting them.
Sam McCall98775c52017-12-04 13:49:59 +0000744 IgnoreDiagnostics IgnoreDiagnostics;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000745 IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
746 CompilerInstance::createDiagnostics(new DiagnosticOptions,
Sam McCall98775c52017-12-04 13:49:59 +0000747 &IgnoreDiagnostics, false);
748 CI =
749 createInvocationFromCommandLine(ArgStrs, CommandLineDiagsEngine, VFS);
750 // createInvocationFromCommandLine sets DisableFree.
751 CI->getFrontendOpts().DisableFree = false;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000752 }
753 assert(CI && "Couldn't create CompilerInvocation");
754
755 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
756 llvm::MemoryBuffer::getMemBufferCopy(NewContents, That->FileName);
757
758 // A helper function to rebuild the preamble or reuse the existing one. Does
Ilya Biryukov11a02522017-11-17 19:05:56 +0000759 // not mutate any fields of CppFile, only does the actual computation.
760 // Lamdba is marked mutable to call reset() on OldPreamble.
761 auto DoRebuildPreamble =
762 [&]() mutable -> std::shared_ptr<const PreambleData> {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000763 auto Bounds =
764 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
765 if (OldPreamble && OldPreamble->Preamble.CanReuse(
766 *CI, ContentsBuffer.get(), Bounds, VFS.get())) {
767 return OldPreamble;
768 }
Ilya Biryukov11a02522017-11-17 19:05:56 +0000769 // We won't need the OldPreamble anymore, release it so it can be deleted
770 // (if there are no other references to it).
771 OldPreamble.reset();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000772
Sam McCall9cfd9c92017-11-23 17:12:04 +0000773 trace::Span Tracer("Preamble");
774 SPAN_ATTACH(Tracer, "File", That->FileName);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000775 std::vector<DiagWithFixIts> PreambleDiags;
776 StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
777 IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
778 CompilerInstance::createDiagnostics(
779 &CI->getDiagnosticOpts(), &PreambleDiagnosticsConsumer, false);
780 CppFilePreambleCallbacks SerializedDeclsCollector;
781 auto BuiltPreamble = PrecompiledPreamble::Build(
782 *CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, VFS, PCHs,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000783 /*StoreInMemory=*/That->StorePreamblesInMemory,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000784 SerializedDeclsCollector);
785
786 if (BuiltPreamble) {
787 return std::make_shared<PreambleData>(
788 std::move(*BuiltPreamble),
789 SerializedDeclsCollector.takeTopLevelDeclIDs(),
790 std::move(PreambleDiags));
791 } else {
792 return nullptr;
793 }
794 };
795
796 // Compute updated Preamble.
797 std::shared_ptr<const PreambleData> NewPreamble = DoRebuildPreamble();
798 // Publish the new Preamble.
799 {
800 std::lock_guard<std::mutex> Lock(That->Mutex);
801 // We always set LatestAvailablePreamble to the new value, hoping that it
802 // will still be usable in the further requests.
803 That->LatestAvailablePreamble = NewPreamble;
804 if (RequestRebuildCounter != That->RebuildCounter)
805 return llvm::None; // Our rebuild request was cancelled, do nothing.
806 That->PreamblePromise.set_value(NewPreamble);
807 } // unlock Mutex
808
809 // Prepare the Preamble and supplementary data for rebuilding AST.
Ilya Biryukov02d58702017-08-01 15:51:38 +0000810 std::vector<DiagWithFixIts> Diagnostics;
811 if (NewPreamble) {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000812 Diagnostics.insert(Diagnostics.begin(), NewPreamble->Diags.begin(),
813 NewPreamble->Diags.end());
814 }
815
816 // Compute updated AST.
Sam McCall8567cb32017-11-02 09:21:51 +0000817 llvm::Optional<ParsedAST> NewAST;
818 {
Sam McCall9cfd9c92017-11-23 17:12:04 +0000819 trace::Span Tracer("Build");
820 SPAN_ATTACH(Tracer, "File", That->FileName);
Ilya Biryukov940901e2017-12-13 12:51:22 +0000821 NewAST = ParsedAST::Build(Ctx, std::move(CI), std::move(NewPreamble),
822 std::move(ContentsBuffer), PCHs, VFS);
Sam McCall8567cb32017-11-02 09:21:51 +0000823 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000824
825 if (NewAST) {
826 Diagnostics.insert(Diagnostics.end(), NewAST->getDiagnostics().begin(),
827 NewAST->getDiagnostics().end());
828 } else {
829 // Don't report even Preamble diagnostics if we coulnd't build AST.
830 Diagnostics.clear();
831 }
832
833 // Publish the new AST.
834 {
835 std::lock_guard<std::mutex> Lock(That->Mutex);
836 if (RequestRebuildCounter != That->RebuildCounter)
837 return Diagnostics; // Our rebuild request was cancelled, don't set
838 // ASTPromise.
839
Ilya Biryukov574b7532017-08-02 09:08:39 +0000840 That->ASTPromise.set_value(
841 std::make_shared<ParsedASTWrapper>(std::move(NewAST)));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000842 } // unlock Mutex
843
844 return Diagnostics;
845 };
846
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000847 return BindWithForward(FinishRebuild, NewContents.str());
Ilya Biryukov02d58702017-08-01 15:51:38 +0000848}
849
850std::shared_future<std::shared_ptr<const PreambleData>>
851CppFile::getPreamble() const {
852 std::lock_guard<std::mutex> Lock(Mutex);
853 return PreambleFuture;
854}
855
856std::shared_ptr<const PreambleData> CppFile::getPossiblyStalePreamble() const {
857 std::lock_guard<std::mutex> Lock(Mutex);
858 return LatestAvailablePreamble;
859}
860
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000861std::shared_future<std::shared_ptr<ParsedASTWrapper>> CppFile::getAST() const {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000862 std::lock_guard<std::mutex> Lock(Mutex);
863 return ASTFuture;
864}
865
866tooling::CompileCommand const &CppFile::getCompileCommand() const {
867 return Command;
868}
869
870CppFile::RebuildGuard::RebuildGuard(CppFile &File,
871 unsigned RequestRebuildCounter)
872 : File(File), RequestRebuildCounter(RequestRebuildCounter) {
873 std::unique_lock<std::mutex> Lock(File.Mutex);
874 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
875 if (WasCancelledBeforeConstruction)
876 return;
877
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000878 File.RebuildCond.wait(Lock, [&File, RequestRebuildCounter]() {
879 return !File.RebuildInProgress ||
880 File.RebuildCounter != RequestRebuildCounter;
881 });
Ilya Biryukov02d58702017-08-01 15:51:38 +0000882
883 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
884 if (WasCancelledBeforeConstruction)
885 return;
886
887 File.RebuildInProgress = true;
888}
889
890bool CppFile::RebuildGuard::wasCancelledBeforeConstruction() const {
891 return WasCancelledBeforeConstruction;
892}
893
894CppFile::RebuildGuard::~RebuildGuard() {
895 if (WasCancelledBeforeConstruction)
896 return;
897
898 std::unique_lock<std::mutex> Lock(File.Mutex);
899 assert(File.RebuildInProgress);
900 File.RebuildInProgress = false;
901
902 if (File.RebuildCounter == RequestRebuildCounter) {
903 // Our rebuild request was successful.
904 assert(futureIsReady(File.ASTFuture));
905 assert(futureIsReady(File.PreambleFuture));
906 } else {
907 // Our rebuild request was cancelled, because further reparse was requested.
908 assert(!futureIsReady(File.ASTFuture));
909 assert(!futureIsReady(File.PreambleFuture));
910 }
911
912 Lock.unlock();
913 File.RebuildCond.notify_all();
914}
Haojian Wu345099c2017-11-09 11:30:04 +0000915
916SourceLocation clangd::getBeginningOfIdentifier(ParsedAST &Unit,
917 const Position &Pos,
918 const FileEntry *FE) {
919 // The language server protocol uses zero-based line and column numbers.
920 // Clang uses one-based numbers.
921
922 const ASTContext &AST = Unit.getASTContext();
923 const SourceManager &SourceMgr = AST.getSourceManager();
924
925 SourceLocation InputLocation =
926 getMacroArgExpandedLocation(SourceMgr, FE, Pos);
927 if (Pos.character == 0) {
928 return InputLocation;
929 }
930
931 // This handle cases where the position is in the middle of a token or right
932 // after the end of a token. In theory we could just use GetBeginningOfToken
933 // to find the start of the token at the input position, but this doesn't
934 // work when right after the end, i.e. foo|.
935 // So try to go back by one and see if we're still inside the an identifier
936 // token. If so, Take the beginning of this token.
937 // (It should be the same identifier because you can't have two adjacent
938 // identifiers without another token in between.)
939 SourceLocation PeekBeforeLocation = getMacroArgExpandedLocation(
940 SourceMgr, FE, Position{Pos.line, Pos.character - 1});
941 Token Result;
942 if (Lexer::getRawToken(PeekBeforeLocation, Result, SourceMgr,
943 AST.getLangOpts(), false)) {
944 // getRawToken failed, just use InputLocation.
945 return InputLocation;
946 }
947
948 if (Result.is(tok::raw_identifier)) {
949 return Lexer::GetBeginningOfToken(PeekBeforeLocation, SourceMgr,
950 AST.getLangOpts());
951 }
952
953 return InputLocation;
954}