comparison clang-tools-extra/clangd/ParsedAST.cpp @ 221:79ff65ed7e25

LLVM12 Original
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 15 Jun 2021 19:15:29 +0900
parents 0572611fdcc8
children 5f17cb93ff66
comparison
equal deleted inserted replaced
220:42394fc6a535 221:79ff65ed7e25
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 // 6 //
7 //===----------------------------------------------------------------------===// 7 //===----------------------------------------------------------------------===//
8 8
9 #include "ParsedAST.h" 9 #include "ParsedAST.h"
10 #include "../clang-tidy/ClangTidyCheck.h"
10 #include "../clang-tidy/ClangTidyDiagnosticConsumer.h" 11 #include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
11 #include "../clang-tidy/ClangTidyModuleRegistry.h" 12 #include "../clang-tidy/ClangTidyModuleRegistry.h"
12 #include "AST.h" 13 #include "AST.h"
13 #include "Compiler.h" 14 #include "Compiler.h"
15 #include "Config.h"
14 #include "Diagnostics.h" 16 #include "Diagnostics.h"
17 #include "FeatureModule.h"
15 #include "Headers.h" 18 #include "Headers.h"
19 #include "HeuristicResolver.h"
16 #include "IncludeFixer.h" 20 #include "IncludeFixer.h"
21 #include "Preamble.h"
17 #include "SourceCode.h" 22 #include "SourceCode.h"
23 #include "TidyProvider.h"
18 #include "index/CanonicalIncludes.h" 24 #include "index/CanonicalIncludes.h"
19 #include "index/Index.h" 25 #include "index/Index.h"
20 #include "support/Logger.h" 26 #include "support/Logger.h"
21 #include "support/Trace.h" 27 #include "support/Trace.h"
22 #include "clang/AST/ASTContext.h" 28 #include "clang/AST/ASTContext.h"
23 #include "clang/AST/Decl.h" 29 #include "clang/AST/Decl.h"
30 #include "clang/Basic/Diagnostic.h"
24 #include "clang/Basic/LangOptions.h" 31 #include "clang/Basic/LangOptions.h"
25 #include "clang/Basic/SourceLocation.h" 32 #include "clang/Basic/SourceLocation.h"
26 #include "clang/Basic/SourceManager.h" 33 #include "clang/Basic/SourceManager.h"
27 #include "clang/Basic/TokenKinds.h" 34 #include "clang/Basic/TokenKinds.h"
28 #include "clang/Frontend/CompilerInstance.h" 35 #include "clang/Frontend/CompilerInstance.h"
43 #include "clang/Tooling/Syntax/Tokens.h" 50 #include "clang/Tooling/Syntax/Tokens.h"
44 #include "llvm/ADT/ArrayRef.h" 51 #include "llvm/ADT/ArrayRef.h"
45 #include "llvm/ADT/STLExtras.h" 52 #include "llvm/ADT/STLExtras.h"
46 #include "llvm/ADT/SmallString.h" 53 #include "llvm/ADT/SmallString.h"
47 #include "llvm/ADT/SmallVector.h" 54 #include "llvm/ADT/SmallVector.h"
55 #include "llvm/ADT/StringRef.h"
48 #include "llvm/Support/raw_ostream.h" 56 #include "llvm/Support/raw_ostream.h"
49 #include <algorithm> 57 #include <algorithm>
50 #include <memory> 58 #include <memory>
59 #include <vector>
51 60
52 // Force the linker to link in Clang-tidy modules. 61 // Force the linker to link in Clang-tidy modules.
53 // clangd doesn't support the static analyzer. 62 // clangd doesn't support the static analyzer.
54 #define CLANG_TIDY_DISABLE_STATIC_ANALYZER_CHECKS 63 #define CLANG_TIDY_DISABLE_STATIC_ANALYZER_CHECKS
55 #include "../clang-tidy/ClangTidyForceLinker.h" 64 #include "../clang-tidy/ClangTidyForceLinker.h"
112 class ReplayPreamble : private PPCallbacks { 121 class ReplayPreamble : private PPCallbacks {
113 public: 122 public:
114 // Attach preprocessor hooks such that preamble events will be injected at 123 // Attach preprocessor hooks such that preamble events will be injected at
115 // the appropriate time. 124 // the appropriate time.
116 // Events will be delivered to the *currently registered* PP callbacks. 125 // Events will be delivered to the *currently registered* PP callbacks.
117 static void attach(const IncludeStructure &Includes, CompilerInstance &Clang, 126 static void attach(std::vector<Inclusion> Includes, CompilerInstance &Clang,
118 const PreambleBounds &PB) { 127 const PreambleBounds &PB) {
119 auto &PP = Clang.getPreprocessor(); 128 auto &PP = Clang.getPreprocessor();
120 auto *ExistingCallbacks = PP.getPPCallbacks(); 129 auto *ExistingCallbacks = PP.getPPCallbacks();
121 // No need to replay events if nobody is listening. 130 // No need to replay events if nobody is listening.
122 if (!ExistingCallbacks) 131 if (!ExistingCallbacks)
123 return; 132 return;
124 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new ReplayPreamble( 133 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new ReplayPreamble(
125 Includes, ExistingCallbacks, Clang.getSourceManager(), PP, 134 std::move(Includes), ExistingCallbacks, Clang.getSourceManager(), PP,
126 Clang.getLangOpts(), PB))); 135 Clang.getLangOpts(), PB)));
127 // We're relying on the fact that addPPCallbacks keeps the old PPCallbacks 136 // We're relying on the fact that addPPCallbacks keeps the old PPCallbacks
128 // around, creating a chaining wrapper. Guard against other implementations. 137 // around, creating a chaining wrapper. Guard against other implementations.
129 assert(PP.getPPCallbacks() != ExistingCallbacks && 138 assert(PP.getPPCallbacks() != ExistingCallbacks &&
130 "Expected chaining implementation"); 139 "Expected chaining implementation");
131 } 140 }
132 141
133 private: 142 private:
134 ReplayPreamble(const IncludeStructure &Includes, PPCallbacks *Delegate, 143 ReplayPreamble(std::vector<Inclusion> Includes, PPCallbacks *Delegate,
135 const SourceManager &SM, Preprocessor &PP, 144 const SourceManager &SM, Preprocessor &PP,
136 const LangOptions &LangOpts, const PreambleBounds &PB) 145 const LangOptions &LangOpts, const PreambleBounds &PB)
137 : Includes(Includes), Delegate(Delegate), SM(SM), PP(PP) { 146 : Includes(std::move(Includes)), Delegate(Delegate), SM(SM), PP(PP) {
138 // Only tokenize the preamble section of the main file, as we are not 147 // Only tokenize the preamble section of the main file, as we are not
139 // interested in the rest of the tokens. 148 // interested in the rest of the tokens.
140 MainFileTokens = syntax::tokenize( 149 MainFileTokens = syntax::tokenize(
141 syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts); 150 syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts);
142 } 151 }
158 // We insert them right after the built-in header, which still appears. 167 // We insert them right after the built-in header, which still appears.
159 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 168 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
160 SrcMgr::CharacteristicKind Kind, FileID PrevFID) override { 169 SrcMgr::CharacteristicKind Kind, FileID PrevFID) override {
161 // It'd be nice if there was a better way to identify built-in headers... 170 // It'd be nice if there was a better way to identify built-in headers...
162 if (Reason == FileChangeReason::ExitFile && 171 if (Reason == FileChangeReason::ExitFile &&
163 SM.getBuffer(PrevFID)->getBufferIdentifier() == "<built-in>") 172 SM.getBufferOrFake(PrevFID).getBufferIdentifier() == "<built-in>")
164 replay(); 173 replay();
165 } 174 }
166 175
167 void replay() { 176 void replay() {
168 for (const auto &Inc : Includes.MainFileIncludes) { 177 for (const auto &Inc : Includes) {
169 const FileEntry *File = nullptr; 178 llvm::Optional<FileEntryRef> File;
170 if (Inc.Resolved != "") 179 if (Inc.Resolved != "")
171 if (auto FE = SM.getFileManager().getFile(Inc.Resolved)) 180 File = expectedToOptional(SM.getFileManager().getFileRef(Inc.Resolved));
172 File = *FE;
173 181
174 // Re-lex the #include directive to find its interesting parts. 182 // Re-lex the #include directive to find its interesting parts.
175 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset); 183 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
176 auto HashTok = llvm::partition_point(MainFileTokens, 184 auto HashTok = llvm::partition_point(MainFileTokens,
177 [&HashLoc](const syntax::Token &T) { 185 [&HashLoc](const syntax::Token &T) {
205 // quotes/angles. 213 // quotes/angles.
206 SynthesizedFilenameTok.setLength(Inc.Written.length()); 214 SynthesizedFilenameTok.setLength(Inc.Written.length());
207 SynthesizedFilenameTok.setKind(tok::header_name); 215 SynthesizedFilenameTok.setKind(tok::header_name);
208 SynthesizedFilenameTok.setLiteralData(Inc.Written.data()); 216 SynthesizedFilenameTok.setLiteralData(Inc.Written.data());
209 217
218 const FileEntry *FE = File ? &File->getFileEntry() : nullptr;
210 llvm::StringRef WrittenFilename = 219 llvm::StringRef WrittenFilename =
211 llvm::StringRef(Inc.Written).drop_front().drop_back(); 220 llvm::StringRef(Inc.Written).drop_front().drop_back();
212 Delegate->InclusionDirective(HashTok->location(), SynthesizedIncludeTok, 221 Delegate->InclusionDirective(HashTok->location(), SynthesizedIncludeTok,
213 WrittenFilename, Inc.Written.front() == '<', 222 WrittenFilename, Inc.Written.front() == '<',
214 FileTok->range(SM).toCharRange(SM), File, 223 FileTok->range(SM).toCharRange(SM), FE,
215 "SearchPath", "RelPath", 224 "SearchPath", "RelPath",
216 /*Imported=*/nullptr, Inc.FileKind); 225 /*Imported=*/nullptr, Inc.FileKind);
217 if (File) 226 if (File)
218 // FIXME: Use correctly named FileEntryRef. 227 Delegate->FileSkipped(*File, SynthesizedFilenameTok, Inc.FileKind);
219 Delegate->FileSkipped(FileEntryRef(File->getName(), *File),
220 SynthesizedFilenameTok, Inc.FileKind);
221 else { 228 else {
222 llvm::SmallString<1> UnusedRecovery; 229 llvm::SmallString<1> UnusedRecovery;
223 Delegate->FileNotFound(WrittenFilename, UnusedRecovery); 230 Delegate->FileNotFound(WrittenFilename, UnusedRecovery);
224 } 231 }
225 } 232 }
226 } 233 }
227 234
228 const IncludeStructure &Includes; 235 const std::vector<Inclusion> Includes;
229 PPCallbacks *Delegate; 236 PPCallbacks *Delegate;
230 const SourceManager &SM; 237 const SourceManager &SM;
231 Preprocessor &PP; 238 Preprocessor &PP;
232 std::vector<syntax::Token> MainFileTokens; 239 std::vector<syntax::Token> MainFileTokens;
233 }; 240 };
234 241
235 } // namespace 242 } // namespace
236
237 void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
238 AST.getASTContext().getTranslationUnitDecl()->dump(OS, true);
239 }
240 243
241 llvm::Optional<ParsedAST> 244 llvm::Optional<ParsedAST>
242 ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, 245 ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
243 std::unique_ptr<clang::CompilerInvocation> CI, 246 std::unique_ptr<clang::CompilerInvocation> CI,
244 llvm::ArrayRef<Diag> CompilerInvocationDiags, 247 llvm::ArrayRef<Diag> CompilerInvocationDiags,
245 std::shared_ptr<const PreambleData> Preamble) { 248 std::shared_ptr<const PreambleData> Preamble) {
246 trace::Span Tracer("BuildAST"); 249 trace::Span Tracer("BuildAST");
247 SPAN_ATTACH(Tracer, "File", Filename); 250 SPAN_ATTACH(Tracer, "File", Filename);
248 251
249 auto VFS = Inputs.FS; 252 auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
250 if (Preamble && Preamble->StatCache) 253 if (Preamble && Preamble->StatCache)
251 VFS = Preamble->StatCache->getConsumingFS(std::move(VFS)); 254 VFS = Preamble->StatCache->getConsumingFS(std::move(VFS));
252 if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
253 log("Couldn't set working directory when building the preamble.");
254 // We proceed anyway, our lit-tests rely on results for non-existing working
255 // dirs.
256 }
257 255
258 assert(CI); 256 assert(CI);
259 // Command-line parsing sets DisableFree to true by default, but we don't want 257 // Command-line parsing sets DisableFree to true by default, but we don't want
260 // to leak memory in clangd. 258 // to leak memory in clangd.
261 CI->getFrontendOpts().DisableFree = false; 259 CI->getFrontendOpts().DisableFree = false;
264 262
265 // This is on-by-default in windows to allow parsing SDK headers, but it 263 // This is on-by-default in windows to allow parsing SDK headers, but it
266 // breaks many features. Disable it for the main-file (not preamble). 264 // breaks many features. Disable it for the main-file (not preamble).
267 CI->getLangOpts()->DelayedTemplateParsing = false; 265 CI->getLangOpts()->DelayedTemplateParsing = false;
268 266
267 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
268 if (Inputs.FeatureModules) {
269 for (auto &M : *Inputs.FeatureModules) {
270 if (auto Listener = M.astListeners())
271 ASTListeners.emplace_back(std::move(Listener));
272 }
273 }
269 StoreDiags ASTDiags; 274 StoreDiags ASTDiags;
270 275 ASTDiags.setDiagCallback(
276 [&ASTListeners](const clang::Diagnostic &D, clangd::Diag &Diag) {
277 llvm::for_each(ASTListeners,
278 [&](const auto &L) { L->sawDiagnostic(D, Diag); });
279 });
280
281 llvm::Optional<PreamblePatch> Patch;
282 bool PreserveDiags = true;
283 if (Preamble) {
284 Patch = PreamblePatch::create(Filename, Inputs, *Preamble);
285 Patch->apply(*CI);
286 PreserveDiags = Patch->preserveDiagnostics();
287 }
271 auto Clang = prepareCompilerInstance( 288 auto Clang = prepareCompilerInstance(
272 std::move(CI), PreamblePCH, 289 std::move(CI), PreamblePCH,
273 llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS, 290 llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS,
274 ASTDiags); 291 ASTDiags);
275 if (!Clang) 292 if (!Clang)
292 std::vector<std::unique_ptr<tidy::ClangTidyCheck>> CTChecks; 309 std::vector<std::unique_ptr<tidy::ClangTidyCheck>> CTChecks;
293 ast_matchers::MatchFinder CTFinder; 310 ast_matchers::MatchFinder CTFinder;
294 llvm::Optional<tidy::ClangTidyContext> CTContext; 311 llvm::Optional<tidy::ClangTidyContext> CTContext;
295 { 312 {
296 trace::Span Tracer("ClangTidyInit"); 313 trace::Span Tracer("ClangTidyInit");
314 tidy::ClangTidyOptions ClangTidyOpts =
315 getTidyOptionsForFile(Inputs.ClangTidyProvider, Filename);
297 dlog("ClangTidy configuration for file {0}: {1}", Filename, 316 dlog("ClangTidy configuration for file {0}: {1}", Filename,
298 tidy::configurationAsText(Inputs.Opts.ClangTidyOpts)); 317 tidy::configurationAsText(ClangTidyOpts));
299 tidy::ClangTidyCheckFactories CTFactories; 318 tidy::ClangTidyCheckFactories CTFactories;
300 for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) 319 for (const auto &E : tidy::ClangTidyModuleRegistry::entries())
301 E.instantiate()->addCheckFactories(CTFactories); 320 E.instantiate()->addCheckFactories(CTFactories);
302 CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>( 321 CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
303 tidy::ClangTidyGlobalOptions(), Inputs.Opts.ClangTidyOpts)); 322 tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
304 CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); 323 CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
305 CTContext->setASTContext(&Clang->getASTContext()); 324 CTContext->setASTContext(&Clang->getASTContext());
306 CTContext->setCurrentFile(Filename); 325 CTContext->setCurrentFile(Filename);
307 CTChecks = CTFactories.createChecks(CTContext.getPointer()); 326 CTChecks = CTFactories.createChecks(CTContext.getPointer());
308 ASTDiags.setLevelAdjuster([&CTContext](DiagnosticsEngine::Level DiagLevel, 327 llvm::erase_if(CTChecks, [&](const auto &Check) {
309 const clang::Diagnostic &Info) { 328 return !Check->isLanguageVersionSupported(CTContext->getLangOpts());
310 if (CTContext) { 329 });
330 Preprocessor *PP = &Clang->getPreprocessor();
331 for (const auto &Check : CTChecks) {
332 Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP);
333 Check->registerMatchers(&CTFinder);
334 }
335
336 const Config &Cfg = Config::current();
337 ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
338 const clang::Diagnostic &Info) {
339 if (Cfg.Diagnostics.SuppressAll ||
340 isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress))
341 return DiagnosticsEngine::Ignored;
342 if (!CTChecks.empty()) {
311 std::string CheckName = CTContext->getCheckName(Info.getID()); 343 std::string CheckName = CTContext->getCheckName(Info.getID());
312 bool IsClangTidyDiag = !CheckName.empty(); 344 bool IsClangTidyDiag = !CheckName.empty();
313 if (IsClangTidyDiag) { 345 if (IsClangTidyDiag) {
346 if (Cfg.Diagnostics.Suppress.contains(CheckName))
347 return DiagnosticsEngine::Ignored;
314 // Check for suppression comment. Skip the check for diagnostics not 348 // Check for suppression comment. Skip the check for diagnostics not
315 // in the main file, because we don't want that function to query the 349 // in the main file, because we don't want that function to query the
316 // source buffer for preamble files. For the same reason, we ask 350 // source buffer for preamble files. For the same reason, we ask
317 // shouldSuppressDiagnostic to avoid I/O. 351 // shouldSuppressDiagnostic to avoid I/O.
318 // We let suppression comments take precedence over warning-as-error 352 // We let suppression comments take precedence over warning-as-error
333 } 367 }
334 } 368 }
335 } 369 }
336 return DiagLevel; 370 return DiagLevel;
337 }); 371 });
338 Preprocessor *PP = &Clang->getPreprocessor();
339 for (const auto &Check : CTChecks) {
340 if (!Check->isLanguageVersionSupported(CTContext->getLangOpts()))
341 continue;
342 // FIXME: the PP callbacks skip the entire preamble.
343 // Checks that want to see #includes in the main file do not see them.
344 Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP);
345 Check->registerMatchers(&CTFinder);
346 }
347 } 372 }
348 373
349 // Add IncludeFixer which can recover diagnostics caused by missing includes 374 // Add IncludeFixer which can recover diagnostics caused by missing includes
350 // (e.g. incomplete type) and attach include insertion fixes to diagnostics. 375 // (e.g. incomplete type) and attach include insertion fixes to diagnostics.
351 llvm::Optional<IncludeFixer> FixIncludes; 376 llvm::Optional<IncludeFixer> FixIncludes;
352 auto BuildDir = VFS->getCurrentWorkingDirectory(); 377 auto BuildDir = VFS->getCurrentWorkingDirectory();
353 if (Inputs.Opts.SuggestMissingIncludes && Inputs.Index && 378 if (Inputs.Index && !BuildDir.getError()) {
354 !BuildDir.getError()) { 379 auto Style = getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS);
355 auto Style = getFormatStyleForFile(Filename, Inputs.Contents, VFS.get());
356 auto Inserter = std::make_shared<IncludeInserter>( 380 auto Inserter = std::make_shared<IncludeInserter>(
357 Filename, Inputs.Contents, Style, BuildDir.get(), 381 Filename, Inputs.Contents, Style, BuildDir.get(),
358 &Clang->getPreprocessor().getHeaderSearchInfo()); 382 &Clang->getPreprocessor().getHeaderSearchInfo());
359 if (Preamble) { 383 if (Preamble) {
360 for (const auto &Inc : Preamble->Includes.MainFileIncludes) 384 for (const auto &Inc : Preamble->Includes.MainFileIncludes)
367 return FixIncludes->fix(DiagLevl, Info); 391 return FixIncludes->fix(DiagLevl, Info);
368 }); 392 });
369 Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder()); 393 Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder());
370 } 394 }
371 395
372 // Copy over the includes from the preamble, then combine with the 396 IncludeStructure Includes;
373 // non-preamble includes below. 397 // If we are using a preamble, copy existing includes.
374 auto Includes = Preamble ? Preamble->Includes : IncludeStructure{}; 398 if (Preamble) {
375 // Replay the preamble includes so that clang-tidy checks can see them. 399 Includes = Preamble->Includes;
376 if (Preamble) 400 Includes.MainFileIncludes = Patch->preambleIncludes();
377 ReplayPreamble::attach(Includes, *Clang, Preamble->Preamble.getBounds()); 401 // Replay the preamble includes so that clang-tidy checks can see them.
402 ReplayPreamble::attach(Patch->preambleIncludes(), *Clang,
403 Patch->modifiedBounds());
404 }
378 // Important: collectIncludeStructure is registered *after* ReplayPreamble! 405 // Important: collectIncludeStructure is registered *after* ReplayPreamble!
379 // Otherwise we would collect the replayed includes again... 406 // Otherwise we would collect the replayed includes again...
380 // (We can't *just* use the replayed includes, they don't have Resolved path). 407 // (We can't *just* use the replayed includes, they don't have Resolved path).
381 Clang->getPreprocessor().addPPCallbacks( 408 Clang->getPreprocessor().addPPCallbacks(
382 collectIncludeStructureCallback(Clang->getSourceManager(), &Includes)); 409 collectIncludeStructureCallback(Clang->getSourceManager(), &Includes));
409 436
410 // We have to consume the tokens before running clang-tidy to avoid collecting 437 // We have to consume the tokens before running clang-tidy to avoid collecting
411 // tokens from running the preprocessor inside the checks (only 438 // tokens from running the preprocessor inside the checks (only
412 // modernize-use-trailing-return-type does that today). 439 // modernize-use-trailing-return-type does that today).
413 syntax::TokenBuffer Tokens = std::move(CollectTokens).consume(); 440 syntax::TokenBuffer Tokens = std::move(CollectTokens).consume();
441 // Makes SelectionTree build much faster.
442 Tokens.indexExpandedTokens();
414 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls(); 443 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();
415 // AST traversals should exclude the preamble, to avoid performance cliffs. 444 // AST traversals should exclude the preamble, to avoid performance cliffs.
416 Clang->getASTContext().setTraversalScope(ParsedDecls); 445 Clang->getASTContext().setTraversalScope(ParsedDecls);
417 { 446 if (!CTChecks.empty()) {
418 // Run the AST-dependent part of the clang-tidy checks. 447 // Run the AST-dependent part of the clang-tidy checks.
419 // (The preprocessor part ran already, via PPCallbacks). 448 // (The preprocessor part ran already, via PPCallbacks).
420 trace::Span Tracer("ClangTidyMatch"); 449 trace::Span Tracer("ClangTidyMatch");
421 CTFinder.matchAST(Clang->getASTContext()); 450 CTFinder.matchAST(Clang->getASTContext());
422 } 451 }
423 452
453 // XXX: This is messy: clang-tidy checks flush some diagnostics at EOF.
454 // However Action->EndSourceFile() would destroy the ASTContext!
455 // So just inform the preprocessor of EOF, while keeping everything alive.
456 Clang->getPreprocessor().EndSourceFile();
424 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that 457 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
425 // has a longer lifetime. 458 // has a longer lifetime.
426 Clang->getDiagnostics().setClient(new IgnoreDiagnostics); 459 Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
427 // CompilerInstance won't run this callback, do it directly. 460 // CompilerInstance won't run this callback, do it directly.
428 ASTDiags.EndSourceFile(); 461 ASTDiags.EndSourceFile();
429 // XXX: This is messy: clang-tidy checks flush some diagnostics at EOF. 462
430 // However Action->EndSourceFile() would destroy the ASTContext! 463 llvm::Optional<std::vector<Diag>> Diags;
431 // So just inform the preprocessor of EOF, while keeping everything alive. 464 // FIXME: Also skip generation of diagnostics alltogether to speed up ast
432 Clang->getPreprocessor().EndSourceFile(); 465 // builds when we are patching a stale preamble.
433 466 if (PreserveDiags) {
434 std::vector<Diag> Diags = CompilerInvocationDiags; 467 Diags = CompilerInvocationDiags;
435 // Add diagnostics from the preamble, if any. 468 // Add diagnostics from the preamble, if any.
436 if (Preamble) 469 if (Preamble)
437 Diags.insert(Diags.end(), Preamble->Diags.begin(), Preamble->Diags.end()); 470 Diags->insert(Diags->end(), Preamble->Diags.begin(),
438 // Finally, add diagnostics coming from the AST. 471 Preamble->Diags.end());
439 { 472 // Finally, add diagnostics coming from the AST.
440 std::vector<Diag> D = ASTDiags.take(CTContext.getPointer()); 473 {
441 Diags.insert(Diags.end(), D.begin(), D.end()); 474 std::vector<Diag> D = ASTDiags.take(CTContext.getPointer());
475 Diags->insert(Diags->end(), D.begin(), D.end());
476 }
442 } 477 }
443 return ParsedAST(Inputs.Version, std::move(Preamble), std::move(Clang), 478 return ParsedAST(Inputs.Version, std::move(Preamble), std::move(Clang),
444 std::move(Action), std::move(Tokens), std::move(Macros), 479 std::move(Action), std::move(Tokens), std::move(Macros),
445 std::move(ParsedDecls), std::move(Diags), 480 std::move(ParsedDecls), std::move(Diags),
446 std::move(Includes), std::move(CanonIncludes)); 481 std::move(Includes), std::move(CanonIncludes));
481 return LocalTopLevelDecls; 516 return LocalTopLevelDecls;
482 } 517 }
483 518
484 const MainFileMacros &ParsedAST::getMacros() const { return Macros; } 519 const MainFileMacros &ParsedAST::getMacros() const { return Macros; }
485 520
486 const std::vector<Diag> &ParsedAST::getDiagnostics() const { return Diags; }
487
488 std::size_t ParsedAST::getUsedBytes() const { 521 std::size_t ParsedAST::getUsedBytes() const {
489 auto &AST = getASTContext(); 522 auto &AST = getASTContext();
490 // FIXME(ibiryukov): we do not account for the dynamically allocated part of 523 // FIXME(ibiryukov): we do not account for the dynamically allocated part of
491 // Message and Fixes inside each diagnostic. 524 // Message and Fixes inside each diagnostic.
492 std::size_t Total = 525 std::size_t Total = clangd::getUsedBytes(LocalTopLevelDecls) +
493 clangd::getUsedBytes(LocalTopLevelDecls) + clangd::getUsedBytes(Diags); 526 (Diags ? clangd::getUsedBytes(*Diags) : 0);
494 527
495 // FIXME: the rest of the function is almost a direct copy-paste from 528 // FIXME: the rest of the function is almost a direct copy-paste from
496 // libclang's clang_getCXTUResourceUsage. We could share the implementation. 529 // libclang's clang_getCXTUResourceUsage. We could share the implementation.
497 530
498 // Sum up various allocators inside the ast context and the preprocessor. 531 // Sum up various allocators inside the ast context and the preprocessor.
529 std::shared_ptr<const PreambleData> Preamble, 562 std::shared_ptr<const PreambleData> Preamble,
530 std::unique_ptr<CompilerInstance> Clang, 563 std::unique_ptr<CompilerInstance> Clang,
531 std::unique_ptr<FrontendAction> Action, 564 std::unique_ptr<FrontendAction> Action,
532 syntax::TokenBuffer Tokens, MainFileMacros Macros, 565 syntax::TokenBuffer Tokens, MainFileMacros Macros,
533 std::vector<Decl *> LocalTopLevelDecls, 566 std::vector<Decl *> LocalTopLevelDecls,
534 std::vector<Diag> Diags, IncludeStructure Includes, 567 llvm::Optional<std::vector<Diag>> Diags,
535 CanonicalIncludes CanonIncludes) 568 IncludeStructure Includes, CanonicalIncludes CanonIncludes)
536 : Version(Version), Preamble(std::move(Preamble)), Clang(std::move(Clang)), 569 : Version(Version), Preamble(std::move(Preamble)), Clang(std::move(Clang)),
537 Action(std::move(Action)), Tokens(std::move(Tokens)), 570 Action(std::move(Action)), Tokens(std::move(Tokens)),
538 Macros(std::move(Macros)), Diags(std::move(Diags)), 571 Macros(std::move(Macros)), Diags(std::move(Diags)),
539 LocalTopLevelDecls(std::move(LocalTopLevelDecls)), 572 LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
540 Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) { 573 Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) {
574 Resolver = std::make_unique<HeuristicResolver>(getASTContext());
541 assert(this->Clang); 575 assert(this->Clang);
542 assert(this->Action); 576 assert(this->Action);
543 } 577 }
544 578
579 llvm::Optional<llvm::StringRef> ParsedAST::preambleVersion() const {
580 if (!Preamble)
581 return llvm::None;
582 return llvm::StringRef(Preamble->Version);
583 }
545 } // namespace clangd 584 } // namespace clangd
546 } // namespace clang 585 } // namespace clang