blob: 313c72edfce8b6977025854f2fdc1eacc10e9e5c [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
Benjamin Kramer5349eed2017-10-28 17:32:56 +0000123llvm::Optional<DiagWithFixIts> toClangdDiag(const StoredDiagnostic &D) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000124 auto Location = D.getLocation();
125 if (!Location.isValid() || !Location.getManager().isInMainFile(Location))
126 return llvm::None;
127
128 Position P;
129 P.line = Location.getSpellingLineNumber() - 1;
130 P.character = Location.getSpellingColumnNumber();
131 Range R = {P, P};
132 clangd::Diagnostic Diag = {R, getSeverity(D.getLevel()), D.getMessage()};
133
134 llvm::SmallVector<tooling::Replacement, 1> FixItsForDiagnostic;
135 for (const FixItHint &Fix : D.getFixIts()) {
136 FixItsForDiagnostic.push_back(clang::tooling::Replacement(
137 Location.getManager(), Fix.RemoveRange, Fix.CodeToInsert));
138 }
139 return DiagWithFixIts{Diag, std::move(FixItsForDiagnostic)};
140}
141
142class StoreDiagsConsumer : public DiagnosticConsumer {
143public:
144 StoreDiagsConsumer(std::vector<DiagWithFixIts> &Output) : Output(Output) {}
145
146 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
147 const clang::Diagnostic &Info) override {
148 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
149
150 if (auto convertedDiag = toClangdDiag(StoredDiagnostic(DiagLevel, Info)))
151 Output.push_back(std::move(*convertedDiag));
152 }
153
154private:
155 std::vector<DiagWithFixIts> &Output;
156};
157
Ilya Biryukov02d58702017-08-01 15:51:38 +0000158template <class T> bool futureIsReady(std::shared_future<T> const &Future) {
159 return Future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
160}
161
Ilya Biryukov04db3682017-07-21 13:29:29 +0000162} // namespace
163
Ilya Biryukov02d58702017-08-01 15:51:38 +0000164void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
165 AST.getASTContext().getTranslationUnitDecl()->dump(OS, true);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000166}
Ilya Biryukovf01af682017-05-23 13:42:59 +0000167
Ilya Biryukov02d58702017-08-01 15:51:38 +0000168llvm::Optional<ParsedAST>
169ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI,
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000170 std::shared_ptr<const PreambleData> Preamble,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000171 std::unique_ptr<llvm::MemoryBuffer> Buffer,
172 std::shared_ptr<PCHContainerOperations> PCHs,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000173 IntrusiveRefCntPtr<vfs::FileSystem> VFS,
174 clangd::Logger &Logger) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000175
176 std::vector<DiagWithFixIts> ASTDiags;
177 StoreDiagsConsumer UnitDiagsConsumer(/*ref*/ ASTDiags);
178
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000179 const PrecompiledPreamble *PreamblePCH =
180 Preamble ? &Preamble->Preamble : nullptr;
Benjamin Kramer5349eed2017-10-28 17:32:56 +0000181 auto Clang = prepareCompilerInstance(
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000182 std::move(CI), PreamblePCH, std::move(Buffer), std::move(PCHs),
Benjamin Kramer5349eed2017-10-28 17:32:56 +0000183 std::move(VFS), /*ref*/ UnitDiagsConsumer);
Ilya Biryukov04db3682017-07-21 13:29:29 +0000184
185 // Recover resources if we crash before exiting this method.
186 llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
187 Clang.get());
188
189 auto Action = llvm::make_unique<ClangdFrontendAction>();
Ilya Biryukove5128f72017-09-20 07:24:15 +0000190 const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
191 if (!Action->BeginSourceFile(*Clang, MainInput)) {
192 Logger.log("BeginSourceFile() failed when building AST for " +
193 MainInput.getFile());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000194 return llvm::None;
195 }
Ilya Biryukove5128f72017-09-20 07:24:15 +0000196 if (!Action->Execute())
197 Logger.log("Execute() failed when building AST for " + MainInput.getFile());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000198
199 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
200 // has a longer lifetime.
Sam McCall98775c52017-12-04 13:49:59 +0000201 Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
Ilya Biryukov04db3682017-07-21 13:29:29 +0000202
203 std::vector<const Decl *> ParsedDecls = Action->takeTopLevelDecls();
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000204 return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action),
205 std::move(ParsedDecls), std::move(ASTDiags));
Ilya Biryukov04db3682017-07-21 13:29:29 +0000206}
207
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000208namespace {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000209
210SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
211 const FileEntry *FE,
212 unsigned Offset) {
213 SourceLocation FileLoc = Mgr.translateFileLineCol(FE, 1, 1);
214 return Mgr.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset));
215}
216
217SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
218 const FileEntry *FE, Position Pos) {
219 SourceLocation InputLoc =
220 Mgr.translateFileLineCol(FE, Pos.line + 1, Pos.character + 1);
221 return Mgr.getMacroArgExpandedLocation(InputLoc);
222}
223
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000224/// Finds declarations locations that a given source location refers to.
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000225class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
226 std::vector<const Decl *> Decls;
227 std::vector<const MacroInfo *> MacroInfos;
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000228 const SourceLocation &SearchedLocation;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000229 const ASTContext &AST;
230 Preprocessor &PP;
231
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000232public:
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000233 DeclarationAndMacrosFinder(raw_ostream &OS,
Ilya Biryukov04db3682017-07-21 13:29:29 +0000234 const SourceLocation &SearchedLocation,
235 ASTContext &AST, Preprocessor &PP)
236 : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000237
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000238 std::vector<const Decl *> takeDecls() {
239 // Don't keep the same declaration multiple times.
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000240 // This can happen when nodes in the AST are visited twice.
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000241 std::sort(Decls.begin(), Decls.end());
242 auto Last = std::unique(Decls.begin(), Decls.end());
243 Decls.erase(Last, Decls.end());
244 return std::move(Decls);
245 }
246
247 std::vector<const MacroInfo *> takeMacroInfos() {
248 // Don't keep the same Macro info multiple times.
249 std::sort(MacroInfos.begin(), MacroInfos.end());
250 auto Last = std::unique(MacroInfos.begin(), MacroInfos.end());
251 MacroInfos.erase(Last, MacroInfos.end());
252 return std::move(MacroInfos);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000253 }
254
Ilya Biryukov02d58702017-08-01 15:51:38 +0000255 bool
256 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
257 ArrayRef<index::SymbolRelation> Relations, FileID FID,
258 unsigned Offset,
259 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000260 if (isSearchedLocation(FID, Offset))
261 Decls.push_back(D);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000262 return true;
263 }
264
265private:
266 bool isSearchedLocation(FileID FID, unsigned Offset) const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000267 const SourceManager &SourceMgr = AST.getSourceManager();
268 return SourceMgr.getFileOffset(SearchedLocation) == Offset &&
269 SourceMgr.getFileID(SearchedLocation) == FID;
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000270 }
271
Kirill Bobyrev46213872017-06-28 20:57:28 +0000272 void finish() override {
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000273 // Also handle possible macro at the searched location.
274 Token Result;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000275 if (!Lexer::getRawToken(SearchedLocation, Result, AST.getSourceManager(),
276 AST.getLangOpts(), false)) {
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000277 if (Result.is(tok::raw_identifier)) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000278 PP.LookUpIdentifierInfo(Result);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000279 }
Ilya Biryukov04db3682017-07-21 13:29:29 +0000280 IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000281 if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
282 std::pair<FileID, unsigned int> DecLoc =
Ilya Biryukov04db3682017-07-21 13:29:29 +0000283 AST.getSourceManager().getDecomposedExpansionLoc(SearchedLocation);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000284 // Get the definition just before the searched location so that a macro
285 // referenced in a '#undef MACRO' can still be found.
Ilya Biryukov04db3682017-07-21 13:29:29 +0000286 SourceLocation BeforeSearchedLocation = getMacroArgExpandedLocation(
287 AST.getSourceManager(),
288 AST.getSourceManager().getFileEntryForID(DecLoc.first),
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000289 DecLoc.second - 1);
290 MacroDefinition MacroDef =
Ilya Biryukov04db3682017-07-21 13:29:29 +0000291 PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
292 MacroInfo *MacroInf = MacroDef.getMacroInfo();
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000293 if (MacroInf) {
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000294 MacroInfos.push_back(MacroInf);
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000295 }
296 }
297 }
298 }
299};
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000300
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000301/// Finds document highlights that a given list of declarations refers to.
302class DocumentHighlightsFinder : public index::IndexDataConsumer {
303 std::vector<const Decl *> &Decls;
304 std::vector<DocumentHighlight> DocumentHighlights;
305 const ASTContext &AST;
306
307public:
308 DocumentHighlightsFinder(raw_ostream &OS, ASTContext &AST, Preprocessor &PP,
309 std::vector<const Decl *> &Decls)
310 : Decls(Decls), AST(AST) {}
311 std::vector<DocumentHighlight> takeHighlights() {
312 // Don't keep the same highlight multiple times.
313 // This can happen when nodes in the AST are visited twice.
314 std::sort(DocumentHighlights.begin(), DocumentHighlights.end());
315 auto Last =
316 std::unique(DocumentHighlights.begin(), DocumentHighlights.end());
317 DocumentHighlights.erase(Last, DocumentHighlights.end());
318 return std::move(DocumentHighlights);
319 }
320
321 bool
322 handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
323 ArrayRef<index::SymbolRelation> Relations, FileID FID,
324 unsigned Offset,
325 index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
326 const SourceManager &SourceMgr = AST.getSourceManager();
327 if (SourceMgr.getMainFileID() != FID ||
328 std::find(Decls.begin(), Decls.end(), D) == Decls.end()) {
329 return true;
330 }
Ilya Biryukovef3191f2017-12-12 14:15:01 +0000331 SourceLocation End;
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000332 const LangOptions &LangOpts = AST.getLangOpts();
333 SourceLocation StartOfFileLoc = SourceMgr.getLocForStartOfFile(FID);
334 SourceLocation HightlightStartLoc = StartOfFileLoc.getLocWithOffset(Offset);
335 End =
336 Lexer::getLocForEndOfToken(HightlightStartLoc, 0, SourceMgr, LangOpts);
337 SourceRange SR(HightlightStartLoc, End);
338
339 DocumentHighlightKind Kind = DocumentHighlightKind::Text;
340 if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Write) & Roles)
341 Kind = DocumentHighlightKind::Write;
342 else if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Read) & Roles)
343 Kind = DocumentHighlightKind::Read;
344
345 DocumentHighlights.push_back(getDocumentHighlight(SR, Kind));
346 return true;
347 }
348
349private:
350 DocumentHighlight getDocumentHighlight(SourceRange SR,
351 DocumentHighlightKind Kind) {
352 const SourceManager &SourceMgr = AST.getSourceManager();
353 SourceLocation LocStart = SR.getBegin();
354 Position Begin;
355 Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
356 Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
357 Position End;
358 End.line = SourceMgr.getSpellingLineNumber(SR.getEnd()) - 1;
359 End.character = SourceMgr.getSpellingColumnNumber(SR.getEnd()) - 1;
360 Range R = {Begin, End};
361 DocumentHighlight DH;
362 DH.range = R;
363 DH.kind = Kind;
364 return DH;
365 }
366};
367
Ilya Biryukov02d58702017-08-01 15:51:38 +0000368} // namespace
Ilya Biryukov04db3682017-07-21 13:29:29 +0000369
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000370llvm::Optional<Location>
371getDeclarationLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
372 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
373 const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
374 SourceLocation LocStart = ValSourceRange.getBegin();
375
376 const FileEntry *F =
377 SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
378 if (!F)
379 return llvm::None;
380 SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(), 0,
381 SourceMgr, LangOpts);
382 Position Begin;
383 Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
384 Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
385 Position End;
386 End.line = SourceMgr.getSpellingLineNumber(LocEnd) - 1;
387 End.character = SourceMgr.getSpellingColumnNumber(LocEnd) - 1;
388 Range R = {Begin, End};
389 Location L;
390
391 StringRef FilePath = F->tryGetRealPathName();
392 if (FilePath.empty())
393 FilePath = F->getName();
394 L.uri = URI::fromFile(FilePath);
395 L.range = R;
396 return L;
397}
398
Ilya Biryukove5128f72017-09-20 07:24:15 +0000399std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
400 clangd::Logger &Logger) {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000401 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
402 const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
403 if (!FE)
404 return {};
405
406 SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
407
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000408 auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
Ilya Biryukov02d58702017-08-01 15:51:38 +0000409 llvm::errs(), SourceLocationBeg, AST.getASTContext(),
410 AST.getPreprocessor());
411 index::IndexingOptions IndexOpts;
412 IndexOpts.SystemSymbolFilter =
413 index::IndexingOptions::SystemSymbolFilterKind::All;
414 IndexOpts.IndexFunctionLocals = true;
415
416 indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000417 DeclMacrosFinder, IndexOpts);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000418
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000419 std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls();
420 std::vector<const MacroInfo *> MacroInfos =
421 DeclMacrosFinder->takeMacroInfos();
422 std::vector<Location> Result;
423
424 for (auto Item : Decls) {
425 auto L = getDeclarationLocation(AST, Item->getSourceRange());
426 if (L)
427 Result.push_back(*L);
428 }
429
430 for (auto Item : MacroInfos) {
431 SourceRange SR(Item->getDefinitionLoc(), Item->getDefinitionEndLoc());
432 auto L = getDeclarationLocation(AST, SR);
433 if (L)
434 Result.push_back(*L);
435 }
436
437 return Result;
438}
439
440std::vector<DocumentHighlight>
441clangd::findDocumentHighlights(ParsedAST &AST, Position Pos,
442 clangd::Logger &Logger) {
443 const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
444 const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
445 if (!FE)
446 return {};
447
448 SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
449
450 auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
451 llvm::errs(), SourceLocationBeg, AST.getASTContext(),
452 AST.getPreprocessor());
453 index::IndexingOptions IndexOpts;
454 IndexOpts.SystemSymbolFilter =
455 index::IndexingOptions::SystemSymbolFilterKind::All;
456 IndexOpts.IndexFunctionLocals = true;
457
458 // Macro occurences are not currently handled.
459 indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
460 DeclMacrosFinder, IndexOpts);
461
462 std::vector<const Decl *> SelectedDecls = DeclMacrosFinder->takeDecls();
463
464 auto DocHighlightsFinder = std::make_shared<DocumentHighlightsFinder>(
465 llvm::errs(), AST.getASTContext(), AST.getPreprocessor(), SelectedDecls);
466
467 indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(),
468 DocHighlightsFinder, IndexOpts);
469
470 return DocHighlightsFinder->takeHighlights();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000471}
472
473void ParsedAST::ensurePreambleDeclsDeserialized() {
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000474 if (PreambleDeclsDeserialized || !Preamble)
Ilya Biryukov04db3682017-07-21 13:29:29 +0000475 return;
476
477 std::vector<const Decl *> Resolved;
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000478 Resolved.reserve(Preamble->TopLevelDeclIDs.size());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000479
480 ExternalASTSource &Source = *getASTContext().getExternalSource();
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000481 for (serialization::DeclID TopLevelDecl : Preamble->TopLevelDeclIDs) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000482 // Resolve the declaration ID to an actual declaration, possibly
483 // deserializing the declaration in the process.
484 if (Decl *D = Source.GetExternalDecl(TopLevelDecl))
485 Resolved.push_back(D);
486 }
487
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000488 TopLevelDecls.reserve(TopLevelDecls.size() +
489 Preamble->TopLevelDeclIDs.size());
Ilya Biryukov04db3682017-07-21 13:29:29 +0000490 TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
491
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000492 PreambleDeclsDeserialized = true;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000493}
494
Ilya Biryukov02d58702017-08-01 15:51:38 +0000495ParsedAST::ParsedAST(ParsedAST &&Other) = default;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000496
Ilya Biryukov02d58702017-08-01 15:51:38 +0000497ParsedAST &ParsedAST::operator=(ParsedAST &&Other) = default;
Ilya Biryukov04db3682017-07-21 13:29:29 +0000498
Ilya Biryukov02d58702017-08-01 15:51:38 +0000499ParsedAST::~ParsedAST() {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000500 if (Action) {
501 Action->EndSourceFile();
502 }
503}
504
Ilya Biryukov02d58702017-08-01 15:51:38 +0000505ASTContext &ParsedAST::getASTContext() { return Clang->getASTContext(); }
506
507const ASTContext &ParsedAST::getASTContext() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000508 return Clang->getASTContext();
509}
510
Ilya Biryukov02d58702017-08-01 15:51:38 +0000511Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
Ilya Biryukov04db3682017-07-21 13:29:29 +0000512
Ilya Biryukov02d58702017-08-01 15:51:38 +0000513const Preprocessor &ParsedAST::getPreprocessor() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000514 return Clang->getPreprocessor();
515}
516
Ilya Biryukov02d58702017-08-01 15:51:38 +0000517ArrayRef<const Decl *> ParsedAST::getTopLevelDecls() {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000518 ensurePreambleDeclsDeserialized();
519 return TopLevelDecls;
520}
521
Ilya Biryukov02d58702017-08-01 15:51:38 +0000522const std::vector<DiagWithFixIts> &ParsedAST::getDiagnostics() const {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000523 return Diags;
524}
525
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000526PreambleData::PreambleData(PrecompiledPreamble Preamble,
527 std::vector<serialization::DeclID> TopLevelDeclIDs,
528 std::vector<DiagWithFixIts> Diags)
529 : Preamble(std::move(Preamble)),
530 TopLevelDeclIDs(std::move(TopLevelDeclIDs)), Diags(std::move(Diags)) {}
531
532ParsedAST::ParsedAST(std::shared_ptr<const PreambleData> Preamble,
533 std::unique_ptr<CompilerInstance> Clang,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000534 std::unique_ptr<FrontendAction> Action,
535 std::vector<const Decl *> TopLevelDecls,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000536 std::vector<DiagWithFixIts> Diags)
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000537 : Preamble(std::move(Preamble)), Clang(std::move(Clang)),
538 Action(std::move(Action)), Diags(std::move(Diags)),
539 TopLevelDecls(std::move(TopLevelDecls)),
540 PreambleDeclsDeserialized(false) {
Ilya Biryukov04db3682017-07-21 13:29:29 +0000541 assert(this->Clang);
542 assert(this->Action);
543}
544
Ilya Biryukov02d58702017-08-01 15:51:38 +0000545ParsedASTWrapper::ParsedASTWrapper(ParsedASTWrapper &&Wrapper)
546 : AST(std::move(Wrapper.AST)) {}
547
548ParsedASTWrapper::ParsedASTWrapper(llvm::Optional<ParsedAST> AST)
549 : AST(std::move(AST)) {}
550
Ilya Biryukov02d58702017-08-01 15:51:38 +0000551std::shared_ptr<CppFile>
552CppFile::Create(PathRef FileName, tooling::CompileCommand Command,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000553 bool StorePreamblesInMemory,
Ilya Biryukov83ca8a22017-09-20 10:46:58 +0000554 std::shared_ptr<PCHContainerOperations> PCHs,
555 clangd::Logger &Logger) {
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000556 return std::shared_ptr<CppFile>(new CppFile(FileName, std::move(Command),
557 StorePreamblesInMemory,
558 std::move(PCHs), Logger));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000559}
560
561CppFile::CppFile(PathRef FileName, tooling::CompileCommand Command,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000562 bool StorePreamblesInMemory,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000563 std::shared_ptr<PCHContainerOperations> PCHs,
564 clangd::Logger &Logger)
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000565 : FileName(FileName), Command(std::move(Command)),
566 StorePreamblesInMemory(StorePreamblesInMemory), RebuildCounter(0),
Ilya Biryukove5128f72017-09-20 07:24:15 +0000567 RebuildInProgress(false), PCHs(std::move(PCHs)), Logger(Logger) {
Sam McCallfae3b022017-11-30 23:16:23 +0000568 Logger.log("Opened file " + FileName + " with command [" +
569 this->Command.Directory + "] " +
Sam McCall318fbeb2017-11-30 23:21:34 +0000570 llvm::join(this->Command.CommandLine, " "));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000571
572 std::lock_guard<std::mutex> Lock(Mutex);
573 LatestAvailablePreamble = nullptr;
574 PreamblePromise.set_value(nullptr);
575 PreambleFuture = PreamblePromise.get_future();
576
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000577 ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000578 ASTFuture = ASTPromise.get_future();
579}
580
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000581void CppFile::cancelRebuild() { deferCancelRebuild()(); }
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000582
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000583UniqueFunction<void()> CppFile::deferCancelRebuild() {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000584 std::unique_lock<std::mutex> Lock(Mutex);
585 // Cancel an ongoing rebuild, if any, and wait for it to finish.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000586 unsigned RequestRebuildCounter = ++this->RebuildCounter;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000587 // Rebuild asserts that futures aren't ready if rebuild is cancelled.
588 // We want to keep this invariant.
589 if (futureIsReady(PreambleFuture)) {
590 PreamblePromise = std::promise<std::shared_ptr<const PreambleData>>();
591 PreambleFuture = PreamblePromise.get_future();
592 }
593 if (futureIsReady(ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000594 ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000595 ASTFuture = ASTPromise.get_future();
596 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000597
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000598 Lock.unlock();
599 // Notify about changes to RebuildCounter.
600 RebuildCond.notify_all();
601
602 std::shared_ptr<CppFile> That = shared_from_this();
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000603 return [That, RequestRebuildCounter]() {
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000604 std::unique_lock<std::mutex> Lock(That->Mutex);
605 CppFile *This = &*That;
606 This->RebuildCond.wait(Lock, [This, RequestRebuildCounter]() {
607 return !This->RebuildInProgress ||
608 This->RebuildCounter != RequestRebuildCounter;
609 });
610
611 // This computation got cancelled itself, do nothing.
612 if (This->RebuildCounter != RequestRebuildCounter)
613 return;
614
615 // Set empty results for Promises.
616 That->PreamblePromise.set_value(nullptr);
617 That->ASTPromise.set_value(std::make_shared<ParsedASTWrapper>(llvm::None));
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000618 };
Ilya Biryukov02d58702017-08-01 15:51:38 +0000619}
620
621llvm::Optional<std::vector<DiagWithFixIts>>
622CppFile::rebuild(StringRef NewContents,
623 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000624 return deferRebuild(NewContents, std::move(VFS))();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000625}
626
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000627UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>()>
Ilya Biryukov02d58702017-08-01 15:51:38 +0000628CppFile::deferRebuild(StringRef NewContents,
629 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
630 std::shared_ptr<const PreambleData> OldPreamble;
631 std::shared_ptr<PCHContainerOperations> PCHs;
632 unsigned RequestRebuildCounter;
633 {
634 std::unique_lock<std::mutex> Lock(Mutex);
635 // Increase RebuildCounter to cancel all ongoing FinishRebuild operations.
636 // They will try to exit as early as possible and won't call set_value on
637 // our promises.
638 RequestRebuildCounter = ++this->RebuildCounter;
639 PCHs = this->PCHs;
640
641 // Remember the preamble to be used during rebuild.
642 OldPreamble = this->LatestAvailablePreamble;
643 // Setup std::promises and std::futures for Preamble and AST. Corresponding
644 // futures will wait until the rebuild process is finished.
645 if (futureIsReady(this->PreambleFuture)) {
646 this->PreamblePromise =
647 std::promise<std::shared_ptr<const PreambleData>>();
648 this->PreambleFuture = this->PreamblePromise.get_future();
649 }
650 if (futureIsReady(this->ASTFuture)) {
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000651 this->ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000652 this->ASTFuture = this->ASTPromise.get_future();
653 }
654 } // unlock Mutex.
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000655 // Notify about changes to RebuildCounter.
656 RebuildCond.notify_all();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000657
658 // A helper to function to finish the rebuild. May be run on a different
659 // thread.
660
661 // Don't let this CppFile die before rebuild is finished.
662 std::shared_ptr<CppFile> That = shared_from_this();
663 auto FinishRebuild = [OldPreamble, VFS, RequestRebuildCounter, PCHs,
Ilya Biryukov11a02522017-11-17 19:05:56 +0000664 That](std::string NewContents) mutable // 'mutable' to
665 // allow changing
666 // OldPreamble.
Ilya Biryukov02d58702017-08-01 15:51:38 +0000667 -> llvm::Optional<std::vector<DiagWithFixIts>> {
668 // Only one execution of this method is possible at a time.
669 // RebuildGuard will wait for any ongoing rebuilds to finish and will put us
670 // into a state for doing a rebuild.
671 RebuildGuard Rebuild(*That, RequestRebuildCounter);
672 if (Rebuild.wasCancelledBeforeConstruction())
673 return llvm::None;
674
675 std::vector<const char *> ArgStrs;
676 for (const auto &S : That->Command.CommandLine)
677 ArgStrs.push_back(S.c_str());
678
679 VFS->setCurrentWorkingDirectory(That->Command.Directory);
680
681 std::unique_ptr<CompilerInvocation> CI;
682 {
683 // FIXME(ibiryukov): store diagnostics from CommandLine when we start
684 // reporting them.
Sam McCall98775c52017-12-04 13:49:59 +0000685 IgnoreDiagnostics IgnoreDiagnostics;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000686 IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
687 CompilerInstance::createDiagnostics(new DiagnosticOptions,
Sam McCall98775c52017-12-04 13:49:59 +0000688 &IgnoreDiagnostics, false);
689 CI =
690 createInvocationFromCommandLine(ArgStrs, CommandLineDiagsEngine, VFS);
691 // createInvocationFromCommandLine sets DisableFree.
692 CI->getFrontendOpts().DisableFree = false;
Ilya Biryukov02d58702017-08-01 15:51:38 +0000693 }
694 assert(CI && "Couldn't create CompilerInvocation");
695
696 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
697 llvm::MemoryBuffer::getMemBufferCopy(NewContents, That->FileName);
698
699 // A helper function to rebuild the preamble or reuse the existing one. Does
Ilya Biryukov11a02522017-11-17 19:05:56 +0000700 // not mutate any fields of CppFile, only does the actual computation.
701 // Lamdba is marked mutable to call reset() on OldPreamble.
702 auto DoRebuildPreamble =
703 [&]() mutable -> std::shared_ptr<const PreambleData> {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000704 auto Bounds =
705 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
706 if (OldPreamble && OldPreamble->Preamble.CanReuse(
707 *CI, ContentsBuffer.get(), Bounds, VFS.get())) {
708 return OldPreamble;
709 }
Ilya Biryukov11a02522017-11-17 19:05:56 +0000710 // We won't need the OldPreamble anymore, release it so it can be deleted
711 // (if there are no other references to it).
712 OldPreamble.reset();
Ilya Biryukov02d58702017-08-01 15:51:38 +0000713
Sam McCall9cfd9c92017-11-23 17:12:04 +0000714 trace::Span Tracer("Preamble");
715 SPAN_ATTACH(Tracer, "File", That->FileName);
Ilya Biryukov02d58702017-08-01 15:51:38 +0000716 std::vector<DiagWithFixIts> PreambleDiags;
717 StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
718 IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
719 CompilerInstance::createDiagnostics(
720 &CI->getDiagnosticOpts(), &PreambleDiagnosticsConsumer, false);
721 CppFilePreambleCallbacks SerializedDeclsCollector;
722 auto BuiltPreamble = PrecompiledPreamble::Build(
723 *CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, VFS, PCHs,
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000724 /*StoreInMemory=*/That->StorePreamblesInMemory,
Ilya Biryukov02d58702017-08-01 15:51:38 +0000725 SerializedDeclsCollector);
726
727 if (BuiltPreamble) {
728 return std::make_shared<PreambleData>(
729 std::move(*BuiltPreamble),
730 SerializedDeclsCollector.takeTopLevelDeclIDs(),
731 std::move(PreambleDiags));
732 } else {
733 return nullptr;
734 }
735 };
736
737 // Compute updated Preamble.
738 std::shared_ptr<const PreambleData> NewPreamble = DoRebuildPreamble();
739 // Publish the new Preamble.
740 {
741 std::lock_guard<std::mutex> Lock(That->Mutex);
742 // We always set LatestAvailablePreamble to the new value, hoping that it
743 // will still be usable in the further requests.
744 That->LatestAvailablePreamble = NewPreamble;
745 if (RequestRebuildCounter != That->RebuildCounter)
746 return llvm::None; // Our rebuild request was cancelled, do nothing.
747 That->PreamblePromise.set_value(NewPreamble);
748 } // unlock Mutex
749
750 // Prepare the Preamble and supplementary data for rebuilding AST.
Ilya Biryukov02d58702017-08-01 15:51:38 +0000751 std::vector<DiagWithFixIts> Diagnostics;
752 if (NewPreamble) {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000753 Diagnostics.insert(Diagnostics.begin(), NewPreamble->Diags.begin(),
754 NewPreamble->Diags.end());
755 }
756
757 // Compute updated AST.
Sam McCall8567cb32017-11-02 09:21:51 +0000758 llvm::Optional<ParsedAST> NewAST;
759 {
Sam McCall9cfd9c92017-11-23 17:12:04 +0000760 trace::Span Tracer("Build");
761 SPAN_ATTACH(Tracer, "File", That->FileName);
Ilya Biryukov2660cc92017-11-24 13:04:21 +0000762 NewAST =
763 ParsedAST::Build(std::move(CI), std::move(NewPreamble),
764 std::move(ContentsBuffer), PCHs, VFS, That->Logger);
Sam McCall8567cb32017-11-02 09:21:51 +0000765 }
Ilya Biryukov02d58702017-08-01 15:51:38 +0000766
767 if (NewAST) {
768 Diagnostics.insert(Diagnostics.end(), NewAST->getDiagnostics().begin(),
769 NewAST->getDiagnostics().end());
770 } else {
771 // Don't report even Preamble diagnostics if we coulnd't build AST.
772 Diagnostics.clear();
773 }
774
775 // Publish the new AST.
776 {
777 std::lock_guard<std::mutex> Lock(That->Mutex);
778 if (RequestRebuildCounter != That->RebuildCounter)
779 return Diagnostics; // Our rebuild request was cancelled, don't set
780 // ASTPromise.
781
Ilya Biryukov574b7532017-08-02 09:08:39 +0000782 That->ASTPromise.set_value(
783 std::make_shared<ParsedASTWrapper>(std::move(NewAST)));
Ilya Biryukov02d58702017-08-01 15:51:38 +0000784 } // unlock Mutex
785
786 return Diagnostics;
787 };
788
Ilya Biryukov98a1fd72017-10-10 16:12:54 +0000789 return BindWithForward(FinishRebuild, NewContents.str());
Ilya Biryukov02d58702017-08-01 15:51:38 +0000790}
791
792std::shared_future<std::shared_ptr<const PreambleData>>
793CppFile::getPreamble() const {
794 std::lock_guard<std::mutex> Lock(Mutex);
795 return PreambleFuture;
796}
797
798std::shared_ptr<const PreambleData> CppFile::getPossiblyStalePreamble() const {
799 std::lock_guard<std::mutex> Lock(Mutex);
800 return LatestAvailablePreamble;
801}
802
Ilya Biryukov6e1f3b12017-08-01 18:27:58 +0000803std::shared_future<std::shared_ptr<ParsedASTWrapper>> CppFile::getAST() const {
Ilya Biryukov02d58702017-08-01 15:51:38 +0000804 std::lock_guard<std::mutex> Lock(Mutex);
805 return ASTFuture;
806}
807
808tooling::CompileCommand const &CppFile::getCompileCommand() const {
809 return Command;
810}
811
812CppFile::RebuildGuard::RebuildGuard(CppFile &File,
813 unsigned RequestRebuildCounter)
814 : File(File), RequestRebuildCounter(RequestRebuildCounter) {
815 std::unique_lock<std::mutex> Lock(File.Mutex);
816 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
817 if (WasCancelledBeforeConstruction)
818 return;
819
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000820 File.RebuildCond.wait(Lock, [&File, RequestRebuildCounter]() {
821 return !File.RebuildInProgress ||
822 File.RebuildCounter != RequestRebuildCounter;
823 });
Ilya Biryukov02d58702017-08-01 15:51:38 +0000824
825 WasCancelledBeforeConstruction = File.RebuildCounter != RequestRebuildCounter;
826 if (WasCancelledBeforeConstruction)
827 return;
828
829 File.RebuildInProgress = true;
830}
831
832bool CppFile::RebuildGuard::wasCancelledBeforeConstruction() const {
833 return WasCancelledBeforeConstruction;
834}
835
836CppFile::RebuildGuard::~RebuildGuard() {
837 if (WasCancelledBeforeConstruction)
838 return;
839
840 std::unique_lock<std::mutex> Lock(File.Mutex);
841 assert(File.RebuildInProgress);
842 File.RebuildInProgress = false;
843
844 if (File.RebuildCounter == RequestRebuildCounter) {
845 // Our rebuild request was successful.
846 assert(futureIsReady(File.ASTFuture));
847 assert(futureIsReady(File.PreambleFuture));
848 } else {
849 // Our rebuild request was cancelled, because further reparse was requested.
850 assert(!futureIsReady(File.ASTFuture));
851 assert(!futureIsReady(File.PreambleFuture));
852 }
853
854 Lock.unlock();
855 File.RebuildCond.notify_all();
856}
Haojian Wu345099c2017-11-09 11:30:04 +0000857
858SourceLocation clangd::getBeginningOfIdentifier(ParsedAST &Unit,
859 const Position &Pos,
860 const FileEntry *FE) {
861 // The language server protocol uses zero-based line and column numbers.
862 // Clang uses one-based numbers.
863
864 const ASTContext &AST = Unit.getASTContext();
865 const SourceManager &SourceMgr = AST.getSourceManager();
866
867 SourceLocation InputLocation =
868 getMacroArgExpandedLocation(SourceMgr, FE, Pos);
869 if (Pos.character == 0) {
870 return InputLocation;
871 }
872
873 // This handle cases where the position is in the middle of a token or right
874 // after the end of a token. In theory we could just use GetBeginningOfToken
875 // to find the start of the token at the input position, but this doesn't
876 // work when right after the end, i.e. foo|.
877 // So try to go back by one and see if we're still inside the an identifier
878 // token. If so, Take the beginning of this token.
879 // (It should be the same identifier because you can't have two adjacent
880 // identifiers without another token in between.)
881 SourceLocation PeekBeforeLocation = getMacroArgExpandedLocation(
882 SourceMgr, FE, Position{Pos.line, Pos.character - 1});
883 Token Result;
884 if (Lexer::getRawToken(PeekBeforeLocation, Result, SourceMgr,
885 AST.getLangOpts(), false)) {
886 // getRawToken failed, just use InputLocation.
887 return InputLocation;
888 }
889
890 if (Result.is(tok::raw_identifier)) {
891 return Lexer::GetBeginningOfToken(PeekBeforeLocation, SourceMgr,
892 AST.getLangOpts());
893 }
894
895 return InputLocation;
896}