clang-tools 24.0.0git
ParsedAST.cpp
Go to the documentation of this file.
1//===--- ParsedAST.cpp -------------------------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ParsedAST.h"
10#include "AST.h"
11#include "CollectMacros.h"
12#include "Compiler.h"
13#include "Config.h"
14#include "Diagnostics.h"
15#include "FeatureModule.h"
16#include "Headers.h"
17#include "IncludeCleaner.h"
18#include "IncludeFixer.h"
19#include "Preamble.h"
20#include "SourceCode.h"
21#include "clang-include-cleaner/Record.h"
22#include "index/Symbol.h"
23#include "support/Logger.h"
24#include "support/Path.h"
25#include "support/Trace.h"
26#include "clang/AST/ASTContext.h"
27#include "clang/AST/Decl.h"
28#include "clang/AST/DeclGroup.h"
29#include "clang/AST/ExternalASTSource.h"
30#include "clang/Basic/Diagnostic.h"
31#include "clang/Basic/DiagnosticIDs.h"
32#include "clang/Basic/DiagnosticSema.h"
33#include "clang/Basic/FileEntry.h"
34#include "clang/Basic/LLVM.h"
35#include "clang/Basic/LangOptions.h"
36#include "clang/Basic/SourceLocation.h"
37#include "clang/Basic/SourceManager.h"
38#include "clang/Basic/TokenKinds.h"
39#include "clang/Frontend/CompilerInstance.h"
40#include "clang/Frontend/CompilerInvocation.h"
41#include "clang/Frontend/FrontendActions.h"
42#include "clang/Frontend/FrontendOptions.h"
43#include "clang/Frontend/PrecompiledPreamble.h"
44#include "clang/Lex/Lexer.h"
45#include "clang/Lex/PPCallbacks.h"
46#include "clang/Lex/PreprocessingRecord.h"
47#include "clang/Lex/Preprocessor.h"
48#include "clang/Sema/HeuristicResolver.h"
49#include "clang/Serialization/ASTWriter.h"
50#include "clang/Tooling/CompilationDatabase.h"
51#include "clang/Tooling/Syntax/Tokens.h"
52#include "llvm/ADT/ArrayRef.h"
53#include "llvm/ADT/DenseMap.h"
54#include "llvm/ADT/STLExtras.h"
55#include "llvm/ADT/STLFunctionalExtras.h"
56#include "llvm/ADT/SmallVector.h"
57#include "llvm/ADT/StringRef.h"
58#include "llvm/Support/Error.h"
59#include "llvm/Support/MemoryBuffer.h"
60#include <cassert>
61#include <cstddef>
62#include <iterator>
63#include <memory>
64#include <optional>
65#include <string>
66#include <utility>
67#include <vector>
68
69namespace clang {
70namespace clangd {
71namespace {
72
73template <class T> std::size_t getUsedBytes(const std::vector<T> &Vec) {
74 return Vec.capacity() * sizeof(T);
75}
76
77class DeclTrackingASTConsumer : public ASTConsumer {
78public:
79 DeclTrackingASTConsumer(std::vector<Decl *> &TopLevelDecls)
80 : TopLevelDecls(TopLevelDecls) {}
81
82 bool HandleTopLevelDecl(DeclGroupRef DG) override {
83 for (Decl *D : DG) {
84 auto &SM = D->getASTContext().getSourceManager();
85 if (!isInsideMainFile(D->getLocation(), SM))
86 continue;
87 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
89 continue;
90
91 // ObjCMethodDecl are not actually top-level decls.
92 if (isa<ObjCMethodDecl>(D))
93 continue;
94
95 TopLevelDecls.push_back(D);
96 }
97 return true;
98 }
99
100private:
101 std::vector<Decl *> &TopLevelDecls;
102};
103
104class ClangdFrontendAction : public SyntaxOnlyAction {
105public:
106 std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
107
108protected:
109 std::unique_ptr<ASTConsumer>
110 CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
111 return std::make_unique<DeclTrackingASTConsumer>(/*ref*/ TopLevelDecls);
112 }
113
114private:
115 std::vector<Decl *> TopLevelDecls;
116};
117
118// When using a preamble, only preprocessor events outside its bounds are seen.
119// This is almost what we want: replaying transitive preprocessing wastes time.
120// However this confuses clang-tidy checks: they don't see any #includes!
121// So we replay the *non-transitive* #includes that appear in the main-file.
122// It would be nice to replay other events (macro definitions, ifdefs etc) but
123// this addresses the most common cases fairly cheaply.
124class ReplayPreamble : private PPCallbacks {
125public:
126 // Attach preprocessor hooks such that preamble events will be injected at
127 // the appropriate time.
128 // Events will be delivered to the *currently registered* PP callbacks.
129 static void attach(std::vector<Inclusion> Includes,
130 const MainFileMacros Macros, CompilerInstance &Clang,
131 const PreambleBounds &PB) {
132 auto &PP = Clang.getPreprocessor();
133 auto *ExistingCallbacks = PP.getPPCallbacks();
134 // No need to replay events if nobody is listening.
135 if (!ExistingCallbacks)
136 return;
137 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new ReplayPreamble(
138 std::move(Includes), std::move(Macros), ExistingCallbacks,
139 Clang.getSourceManager(), PP, Clang.getLangOpts(), PB)));
140 // We're relying on the fact that addPPCallbacks keeps the old PPCallbacks
141 // around, creating a chaining wrapper. Guard against other implementations.
142 assert(PP.getPPCallbacks() != ExistingCallbacks &&
143 "Expected chaining implementation");
144 }
145
146private:
147 ReplayPreamble(std::vector<Inclusion> Includes, MainFileMacros Macros,
148 PPCallbacks *Delegate, const SourceManager &SM,
149 Preprocessor &PP, const LangOptions &LangOpts,
150 const PreambleBounds &PB)
151 : Includes(std::move(Includes)), Macros(std::move(Macros)),
152 Delegate(Delegate), SM(SM), PP(PP) {
153 // Only tokenize the preamble section of the main file, as we are not
154 // interested in the rest of the tokens.
155 MainFileTokens = syntax::tokenize(
156 syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts);
157 }
158
159 // In a normal compile, the preamble traverses the following structure:
160 //
161 // mainfile.cpp
162 // <built-in>
163 // ... macro definitions like __cplusplus ...
164 // <command-line>
165 // ... macro definitions for args like -Dfoo=bar ...
166 // "header1.h"
167 // ... header file contents ...
168 // "header2.h"
169 // ... header file contents ...
170 // ... main file contents ...
171 //
172 // When using a preamble, the "header1" and "header2" subtrees get skipped.
173 // We insert them right after the built-in header, which still appears.
174 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
175 SrcMgr::CharacteristicKind Kind, FileID PrevFID) override {
176 // It'd be nice if there was a better way to identify built-in headers...
177 if (Reason == FileChangeReason::ExitFile &&
178 SM.getBufferOrFake(PrevFID).getBufferIdentifier() == "<built-in>")
179 replay();
180 }
181
182 void replay() {
183 // Replay macro definitions from the preamble region of the main file,
184 // so that clang-tidy checks can observe them.
185 for (const auto &[SID, Refs] : Macros.MacroRefs) {
186 for (const auto &Ref : Refs) {
187 if (!Ref.IsDefinition)
188 continue;
189 auto Loc = SM.getComposedLoc(SM.getMainFileID(), Ref.StartOffset);
190 Token Tok;
191 if (Lexer::getRawToken(Loc, Tok, SM, PP.getLangOpts(), false))
192 continue;
193 if (auto *II = PP.getIdentifierInfo(Tok.getRawIdentifier())) {
194 Tok.setIdentifierInfo(II);
195 Tok.setKind(tok::identifier);
196 if (auto *MD = PP.getLocalMacroDirective(II))
197 Delegate->MacroDefined(Tok, MD);
198 }
199 }
200 }
201 for (const auto &Inc : Includes) {
202 OptionalFileEntryRef File;
203 if (Inc.Resolved != "")
204 File = expectedToOptional(SM.getFileManager().getFileRef(Inc.Resolved));
205
206 // Re-lex the #include directive to find its interesting parts.
207 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
208 auto HashTok = llvm::partition_point(MainFileTokens,
209 [&HashLoc](const syntax::Token &T) {
210 return T.location() < HashLoc;
211 });
212 assert(HashTok != MainFileTokens.end() && HashTok->kind() == tok::hash);
213
214 auto IncludeTok = std::next(HashTok);
215 assert(IncludeTok != MainFileTokens.end());
216
217 auto FileTok = std::next(IncludeTok);
218 assert(FileTok != MainFileTokens.end());
219
220 // Create a fake import/include token, none of the callers seem to care
221 // about clang::Token::Flags.
222 Token SynthesizedIncludeTok;
223 SynthesizedIncludeTok.startToken();
224 SynthesizedIncludeTok.setLocation(IncludeTok->location());
225 SynthesizedIncludeTok.setLength(IncludeTok->length());
226 SynthesizedIncludeTok.setKind(tok::raw_identifier);
227 SynthesizedIncludeTok.setRawIdentifierData(IncludeTok->text(SM).data());
228 PP.LookUpIdentifierInfo(SynthesizedIncludeTok);
229
230 // Same here, create a fake one for Filename, including angles or quotes.
231 Token SynthesizedFilenameTok;
232 SynthesizedFilenameTok.startToken();
233 SynthesizedFilenameTok.setLocation(FileTok->location());
234 // Note that we can't make use of FileTok->length/text in here as in the
235 // case of angled includes this will contain tok::less instead of
236 // filename. Whereas Inc.Written contains the full header name including
237 // quotes/angles.
238 SynthesizedFilenameTok.setLength(Inc.Written.length());
239 SynthesizedFilenameTok.setKind(tok::header_name);
240 SynthesizedFilenameTok.setLiteralData(Inc.Written.data());
241
242 llvm::StringRef WrittenFilename =
243 llvm::StringRef(Inc.Written).drop_front().drop_back();
244 Delegate->InclusionDirective(
245 HashTok->location(), SynthesizedIncludeTok, WrittenFilename,
246 Inc.Written.front() == '<',
247 syntax::FileRange(SM, SynthesizedFilenameTok.getLocation(),
248 SynthesizedFilenameTok.getEndLoc())
249 .toCharRange(SM),
250 File, "SearchPath", "RelPath",
251 /*SuggestedModule=*/nullptr, /*ModuleImported=*/false, Inc.FileKind);
252 if (File)
253 Delegate->FileSkipped(*File, SynthesizedFilenameTok, Inc.FileKind);
254 }
255 }
256
257 const std::vector<Inclusion> Includes;
258 const MainFileMacros Macros;
259 PPCallbacks *Delegate;
260 const SourceManager &SM;
261 Preprocessor &PP;
262 std::vector<syntax::Token> MainFileTokens;
263};
264
265std::vector<Diag> getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code,
266 const ThreadsafeFS &TFS) {
267 auto &Cfg = Config::current();
268 if (Cfg.Diagnostics.SuppressAll)
269 return {};
270 bool SuppressMissing =
271 Cfg.Diagnostics.Suppress.contains("missing-includes") ||
272 Cfg.Diagnostics.MissingIncludes == Config::IncludesPolicy::None;
273 bool SuppressUnused =
274 Cfg.Diagnostics.Suppress.contains("unused-includes") ||
275 Cfg.Diagnostics.UnusedIncludes == Config::IncludesPolicy::None;
276 if (SuppressMissing && SuppressUnused)
277 return {};
278 auto Findings = computeIncludeCleanerFindings(
279 AST, Cfg.Diagnostics.Includes.AnalyzeAngledIncludes);
280 if (SuppressMissing)
281 Findings.MissingIncludes.clear();
282 if (SuppressUnused)
283 Findings.UnusedIncludes.clear();
285 AST, Code, Findings, TFS, Cfg.Diagnostics.Includes.IgnoreHeader,
286 Cfg.Style.AngledHeaders, Cfg.Style.QuotedHeaders);
287}
288
289} // namespace
290
291std::optional<ParsedAST>
292ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
293 std::unique_ptr<clang::CompilerInvocation> CI,
294 llvm::ArrayRef<Diag> CompilerInvocationDiags,
295 std::shared_ptr<const PreambleData> Preamble) {
296 trace::Span Tracer("BuildAST");
297 SPAN_ATTACH(Tracer, "File", Filename);
298 const Config &Cfg = Config::current();
299
300 auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
301 if (Preamble && Preamble->StatCache)
302 VFS = Preamble->StatCache->getConsumingFS(std::move(VFS));
303
304 assert(CI);
305
306 if (CI->getFrontendOpts().Inputs.size() > 0) {
307 auto Lang = CI->getFrontendOpts().Inputs[0].getKind().getLanguage();
308 if (Lang == Language::Asm || Lang == Language::LLVM_IR) {
309 elog("Clangd does not support assembly or IR source files");
310 return std::nullopt;
311 }
312 }
313
314 // Command-line parsing sets DisableFree to true by default, but we don't want
315 // to leak memory in clangd.
316 CI->getFrontendOpts().DisableFree = false;
317 const PrecompiledPreamble *PreamblePCH =
318 Preamble ? &Preamble->Preamble : nullptr;
319
320 // This is on-by-default in windows to allow parsing SDK headers, but it
321 // breaks many features. Disable it for the main-file (not preamble).
322 CI->getLangOpts().DelayedTemplateParsing = false;
323
324 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
325 if (Inputs.FeatureModules) {
326 for (auto &M : *Inputs.FeatureModules) {
327 if (auto Listener = M.astListeners())
328 ASTListeners.emplace_back(std::move(Listener));
329 }
330 }
331 StoreDiags ASTDiags;
332 ASTDiags.setDiagCallback(
333 [&ASTListeners](const clang::Diagnostic &D, clangd::Diag &Diag) {
334 for (const auto &L : ASTListeners)
335 L->sawDiagnostic(D, Diag);
336 });
337 ASTDiags.setDiagFinalizer([&ASTListeners](clangd::Diag &Diag) {
338 for (const auto &L : ASTListeners)
339 L->finalizeDiagnostic(Diag);
340 });
341
342 // Adjust header search options to load the built module files recorded
343 // in RequiredModules.
344 if (Preamble && Preamble->RequiredModules)
345 Preamble->RequiredModules->adjustHeaderSearchOptions(
346 CI->getHeaderSearchOpts());
347
348 std::optional<PreamblePatch> Patch;
349 // We might use an ignoring diagnostic consumer if they are going to be
350 // dropped later on to not pay for extra latency by processing them.
351 DiagnosticConsumer *DiagConsumer = &ASTDiags;
352 IgnoreDiagnostics DropDiags;
353 if (Preamble) {
354 Patch = PreamblePatch::createFullPatch(Filename, Inputs, *Preamble);
355 Patch->apply(*CI);
356 }
357 auto Clang = prepareCompilerInstance(
358 std::move(CI), Inputs.Opts.SkipPreambleBuild ? nullptr : PreamblePCH,
359 llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS,
360 *DiagConsumer);
361
362 if (!Clang) {
363 // The last diagnostic contains information about the reason of this
364 // failure.
365 std::vector<Diag> Diags(ASTDiags.take());
366 elog("Failed to prepare a compiler instance: {0}",
367 !Diags.empty() ? static_cast<DiagBase &>(Diags.back()).Message
368 : "unknown error");
369 return std::nullopt;
370 }
371 auto Action = std::make_unique<ClangdFrontendAction>();
372 for (const auto &L : ASTListeners)
373 L->beforeBeginSourceFile(*Clang);
374 const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
375 if (!Action->BeginSourceFile(*Clang, MainInput)) {
376 elog("BeginSourceFile() failed when building AST for {0}",
377 MainInput.getFile());
378 return std::nullopt;
379 }
380 // If we saw an include guard in the preamble section of the main file,
381 // mark the main-file as include-guarded.
382 // This information is part of the HeaderFileInfo but is not loaded from the
383 // preamble as the file's size is part of its identity and may have changed.
384 // (The rest of HeaderFileInfo is not relevant for our purposes).
385 if (Preamble && Preamble->MainIsIncludeGuarded) {
386 const SourceManager &SM = Clang->getSourceManager();
387 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
388 Clang->getPreprocessor().getHeaderSearchInfo().MarkFileIncludeOnce(*MainFE);
389 }
390
391 // Must outlive FixIncludes.
392 auto BuildDir = VFS->getCurrentWorkingDirectory();
393 std::optional<IncludeFixer> FixIncludes;
394 llvm::DenseMap<diag::kind, DiagnosticsEngine::Level> OverriddenSeverity;
395 // Clang only corrects typos for use of undeclared functions in C if that
396 // use is an error. Include fixer relies on typo correction, so pretend
397 // this is an error. (The actual typo correction is nice too).
398 // We restore the original severity in the level adjuster.
399 // FIXME: It would be better to have a real API for this, but what?
400 for (auto ID : {diag::ext_implicit_function_decl_c99,
401 diag::ext_implicit_lib_function_decl,
402 diag::ext_implicit_lib_function_decl_c99,
403 diag::warn_implicit_function_decl}) {
404 OverriddenSeverity.try_emplace(
405 ID, Clang->getDiagnostics().getDiagnosticLevel(ID, SourceLocation()));
406 Clang->getDiagnostics().setSeverity(ID, diag::Severity::Error,
407 SourceLocation());
408 }
409 ASTDiags.setLevelAdjuster(
410 [&](DiagnosticsEngine::Level Level, const clang::Diagnostic &Info) {
411 auto It = OverriddenSeverity.find(Info.getID());
412 return It == OverriddenSeverity.end() ? Level : It->second;
413 });
414
415 // Add IncludeFixer which can recover diagnostics caused by missing includes
416 // (e.g. incomplete type) and attach include insertion fixes to diagnostics.
417 if (Inputs.Index && !BuildDir.getError()) {
418 auto Style =
419 getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS, false);
420 auto Inserter = std::make_shared<IncludeInserter>(
421 Filename, Inputs.Contents, Style, BuildDir.get(),
422 &Clang->getPreprocessor().getHeaderSearchInfo(),
424 ArrayRef<Inclusion> MainFileIncludes;
425 if (Preamble) {
426 MainFileIncludes = Preamble->Includes.MainFileIncludes;
427 for (const auto &Inc : Preamble->Includes.MainFileIncludes)
428 Inserter->addExisting(Inc);
429 }
430 // FIXME: Consider piping through ASTSignals to fetch this to handle the
431 // case where a header file contains ObjC decls but no #imports.
432 Symbol::IncludeDirective Directive =
434 ? preferredIncludeDirective(Filename, Clang->getLangOpts(),
435 MainFileIncludes, {})
437 FixIncludes.emplace(Filename, Inserter, *Inputs.Index,
438 /*IndexRequestLimit=*/5, Directive);
439 ASTDiags.contributeFixes([&FixIncludes](DiagnosticsEngine::Level Level,
440 const clang::Diagnostic &Info) {
441 return FixIncludes->fix(Level, Info);
442 });
443 Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder());
444 }
445
446 // ReplayPreamble must capture callbacks installed by feature modules.
447 for (const auto &L : ASTListeners)
448 L->beforePPCallbacks(*Clang);
449
450 IncludeStructure Includes;
451 include_cleaner::PragmaIncludes PI;
452 // If we are using a preamble, copy existing includes.
453 if (Preamble) {
454 Includes = Preamble->Includes;
455 Includes.MainFileIncludes = Patch->preambleIncludes();
456 // Replay the preamble includes so that clang-tidy checks can see them.
457 ReplayPreamble::attach(Patch->preambleIncludes(), Patch->mainFileMacros(),
458 *Clang, Patch->modifiedBounds());
459 PI = *Preamble->Pragmas;
460 }
461 // Important: collectIncludeStructure is registered *after* ReplayPreamble!
462 // Otherwise we would collect the replayed includes again...
463 // (We can't *just* use the replayed includes, they don't have Resolved path).
464 Includes.collect(*Clang);
465 // Same for pragma-includes, we're already inheriting preamble includes, so we
466 // should only receive callbacks for non-preamble mainfile includes.
467 PI.record(*Clang);
468 // Copy over the macros in the preamble region of the main file, and combine
469 // with non-preamble macros below.
470 MainFileMacros Macros;
471 std::vector<PragmaMark> Marks;
472 if (Preamble) {
473 Macros = Patch->mainFileMacros();
474 Marks = Patch->marks();
475 }
476 auto &PP = Clang->getPreprocessor();
477 auto MacroCollector = std::make_unique<CollectMainFileMacros>(PP, Macros);
478 auto *MacroCollectorPtr = MacroCollector.get(); // so we can call doneParse()
479 PP.addPPCallbacks(std::move(MacroCollector));
480
481 PP.addPPCallbacks(
482 collectPragmaMarksCallback(Clang->getSourceManager(), Marks));
483
484 // FIXME: Attach a comment handler to take care of
485 // keep/export/no_include etc. IWYU pragmas.
486
487 // Collect tokens of the main file.
488 syntax::TokenCollector CollectTokens(PP);
489
490 // To remain consistent with preamble builds, these callbacks must be called
491 // exactly here, after preprocessor is initialized and BeginSourceFile() was
492 // called already.
493 for (const auto &L : ASTListeners)
494 L->beforeExecute(*Clang);
495
496 if (llvm::Error Err = Action->Execute())
497 log("Execute() failed when building AST for {0}: {1}", MainInput.getFile(),
498 toString(std::move(Err)));
499
500 // Disable the macro collector for the remainder of this function, e.g.
501 // clang-tidy checkers.
502 MacroCollectorPtr->doneParse();
503
504 // We have to consume the tokens before running clang-tidy to avoid collecting
505 // tokens from running the preprocessor inside the checks (only
506 // modernize-use-trailing-return-type does that today).
507 syntax::TokenBuffer Tokens = std::move(CollectTokens).consume();
508 // Makes SelectionTree build much faster.
509 Tokens.indexExpandedTokens();
510 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();
511 // AST traversals should exclude the preamble, to avoid performance cliffs.
512 Clang->getASTContext().setTraversalScope(ParsedDecls);
513 for (const auto &L : ASTListeners)
514 L->afterExecute(*Clang);
515
516 // XXX: This is messy: clang-tidy checks flush some diagnostics at EOF.
517 // However Action->EndSourceFile() would destroy the ASTContext!
518 // So just inform the preprocessor of EOF, while keeping everything alive.
519 PP.EndSourceFile();
520 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
521 // has a longer lifetime.
522 Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
523 // CompilerInstance won't run this callback, do it directly.
524 ASTDiags.EndSourceFile();
525
526 std::vector<Diag> Diags = CompilerInvocationDiags;
527 // FIXME: Also skip generation of diagnostics altogether to speed up ast
528 // builds when we are patching a stale preamble.
529 // Add diagnostics from the preamble, if any.
530 if (Preamble)
531 llvm::append_range(Diags, Patch->patchedDiags());
532 // Finally, add diagnostics coming from the AST.
533 {
534 std::vector<Diag> D = ASTDiags.take();
535 Diags.insert(Diags.end(), D.begin(), D.end());
536 }
537 ParsedAST Result(Filename, Inputs.Version, std::move(Preamble),
538 std::move(Clang), std::move(Action), std::move(Tokens),
539 std::move(Macros), std::move(Marks), std::move(ParsedDecls),
540 std::move(Diags), std::move(Includes), std::move(PI));
541 llvm::move(getIncludeCleanerDiags(Result, Inputs.Contents, *Inputs.TFS),
542 std::back_inserter(Result.Diags));
543 return std::move(Result);
544}
545
546ParsedAST::ParsedAST(ParsedAST &&Other) = default;
547
548ParsedAST &ParsedAST::operator=(ParsedAST &&Other) = default;
549
551 if (Action) {
552 // We already notified the PP of end-of-file earlier, so detach it first.
553 // We must keep it alive until after EndSourceFile(), Sema relies on this.
554 auto PP = Clang->getPreprocessorPtr(); // Keep PP alive for now.
555 Clang->setPreprocessor(nullptr); // Detach so we don't send EOF again.
556 Action->EndSourceFile(); // Destroy ASTContext and Sema.
557 // Now Sema is gone, it's safe for PP to go out of scope.
558 }
559}
560
561ASTContext &ParsedAST::getASTContext() { return Clang->getASTContext(); }
562
563const ASTContext &ParsedAST::getASTContext() const {
564 return Clang->getASTContext();
565}
566
567Sema &ParsedAST::getSema() { return Clang->getSema(); }
568
569Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
570
571std::shared_ptr<Preprocessor> ParsedAST::getPreprocessorPtr() {
572 return Clang->getPreprocessorPtr();
573}
574
575const Preprocessor &ParsedAST::getPreprocessor() const {
576 return Clang->getPreprocessor();
577}
578
579llvm::ArrayRef<Decl *> ParsedAST::getLocalTopLevelDecls() {
580 return LocalTopLevelDecls;
581}
582
583llvm::ArrayRef<const Decl *> ParsedAST::getLocalTopLevelDecls() const {
584 return LocalTopLevelDecls;
585}
586
587const MainFileMacros &ParsedAST::getMacros() const { return Macros; }
588const std::vector<PragmaMark> &ParsedAST::getMarks() const { return Marks; }
589
590std::size_t ParsedAST::getUsedBytes() const {
591 auto &AST = getASTContext();
592 // FIXME(ibiryukov): we do not account for the dynamically allocated part of
593 // Message and Fixes inside each diagnostic.
594 std::size_t Total =
595 clangd::getUsedBytes(LocalTopLevelDecls) + clangd::getUsedBytes(Diags);
596
597 // FIXME: the rest of the function is almost a direct copy-paste from
598 // libclang's clang_getCXTUResourceUsage. We could share the implementation.
599
600 // Sum up various allocators inside the ast context and the preprocessor.
601 Total += AST.getASTAllocatedMemory();
602 Total += AST.getSideTableAllocatedMemory();
603 Total += AST.Idents.getAllocator().getTotalMemory();
604 Total += AST.Selectors.getTotalMemory();
605
606 Total += AST.getSourceManager().getContentCacheSize();
607 Total += AST.getSourceManager().getDataStructureSizes();
608 Total += AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
609
610 if (ExternalASTSource *Ext = AST.getExternalSource())
611 Total += Ext->getMemoryBufferSizes().malloc_bytes;
612
613 const Preprocessor &PP = getPreprocessor();
614 Total += PP.getTotalMemory();
615 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
616 Total += PRec->getTotalMemory();
617 Total += PP.getHeaderSearchInfo().getTotalMemory();
618
619 return Total;
620}
621
623 return Includes;
624}
625
626ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
627 std::shared_ptr<const PreambleData> Preamble,
628 std::unique_ptr<CompilerInstance> Clang,
629 std::unique_ptr<FrontendAction> Action,
630 syntax::TokenBuffer Tokens, MainFileMacros Macros,
631 std::vector<PragmaMark> Marks,
632 std::vector<Decl *> LocalTopLevelDecls,
633 std::vector<Diag> Diags, IncludeStructure Includes,
634 include_cleaner::PragmaIncludes PI)
635 : TUPath(TUPath), Version(Version), Preamble(std::move(Preamble)),
636 Clang(std::move(Clang)), Action(std::move(Action)),
637 Tokens(std::move(Tokens)), Macros(std::move(Macros)),
638 Marks(std::move(Marks)), Diags(std::move(Diags)),
639 LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
640 Includes(std::move(Includes)), PI(std::move(PI)),
641 Resolver(std::make_unique<HeuristicResolver>(getASTContext())) {
642 assert(this->Clang);
643 assert(this->Action);
644}
645
646const include_cleaner::PragmaIncludes &ParsedAST::getPragmaIncludes() const {
647 return PI;
648}
649
650std::optional<llvm::StringRef> ParsedAST::preambleVersion() const {
651 if (!Preamble)
652 return std::nullopt;
653 return llvm::StringRef(Preamble->Version);
654}
655
656llvm::ArrayRef<Diag> ParsedAST::getDiagnostics() const { return Diags; }
657} // namespace clangd
658} // namespace clang
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for Markdown output.")
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition Trace.h:164
void collect(const CompilerInstance &CI)
Definition Headers.cpp:178
Stores and provides access to parsed AST.
Definition ParsedAST.h:47
std::size_t getUsedBytes() const
Returns the estimated size of the AST and the accessory structures, in bytes.
std::optional< llvm::StringRef > preambleVersion() const
Returns the version of the ParseInputs used to build Preamble part of this AST.
const include_cleaner::PragmaIncludes & getPragmaIncludes() const
Returns the PramaIncludes for preamble + main file includes.
const std::vector< PragmaMark > & getMarks() const
Gets all pragma marks in the main file.
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
static std::optional< ParsedAST > build(llvm::StringRef Filename, const ParseInputs &Inputs, std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble)
Attempts to run Clang and store the parsed AST.
llvm::ArrayRef< Diag > getDiagnostics() const
std::shared_ptr< Preprocessor > getPreprocessorPtr()
Preprocessor & getPreprocessor()
ArrayRef< Decl * > getLocalTopLevelDecls()
This function returns top-level decls present in the main file of the AST.
ParsedAST & operator=(ParsedAST &&Other)
const IncludeStructure & getIncludeStructure() const
ParsedAST(ParsedAST &&Other)
const MainFileMacros & getMacros() const
Gets all macro references (definition, expansions) present in the main file, including those in the p...
static PreamblePatch createFullPatch(llvm::StringRef FileName, const ParseInputs &Modified, const PreambleData &Baseline)
Builds a patch that contains new PP directives introduced to the preamble section of Modified compare...
Definition Preamble.cpp:928
StoreDiags collects the diagnostics that can later be reported by clangd.
void contributeFixes(DiagFixer Fixer)
If set, possibly adds fixes for diagnostics using Fixer.
void setDiagFinalizer(DiagFinalizer F)
Invokes a callback after notes and fixes have been attached.
void setLevelAdjuster(LevelAdjuster Adjuster)
If set, this allows the client of this class to adjust the level of diagnostics, such as promoting wa...
void setDiagCallback(DiagCallback CB)
Invokes a callback when a main diagnostic is first formed, before notes and fixes are attached.
void EndSourceFile() override
std::vector< Diag > take()
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
Records an event whose duration is the lifetime of the Span object.
Definition Trace.h:143
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
@ Info
An information message.
Definition Protocol.h:755
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
static const char * toString(OffsetEncoding OE)
std::unique_ptr< PPCallbacks > collectPragmaMarksCallback(const SourceManager &SM, std::vector< PragmaMark > &Out)
Collect all pragma marks from the main file.
Symbol::IncludeDirective preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts, ArrayRef< Inclusion > MainFileIncludes, ArrayRef< const Decl * > TopLevelDecls)
Infer the include directive to use for the given FileName.
Definition AST.cpp:386
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
Definition Compiler.cpp:132
void log(const char *Fmt, Ts &&... Vals)
Definition Logger.h:67
IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST, bool AnalyzeAngledIncludes)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition Path.h:29
bool isImplicitTemplateInstantiation(const NamedDecl *D)
Indicates if D is a template instantiation implicitly generated by the compiler, e....
Definition AST.cpp:183
std::vector< Diag > issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code, const IncludeCleanerFindings &Findings, const ThreadsafeFS &TFS, HeaderFilter IgnoreHeaders, HeaderFilter AngledHeaders, HeaderFilter QuotedHeaders)
void elog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:61
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, const ThreadsafeFS &TFS, bool FormatFile)
Choose the clang-format style we should apply to a certain file.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Settings that express user/project preferences and control clangd behavior.
Definition Config.h:45
struct clang::clangd::Config::@314053012031341203055315320366267371313202370174 Style
Style of the codebase.
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
Definition Config.cpp:17
std::vector< std::function< bool(llvm::StringRef)> > QuotedHeaders
Definition Config.h:136
std::vector< std::function< bool(llvm::StringRef)> > AngledHeaders
Definition Config.h:137
Contains basic information about a diagnostic.
Definition Diagnostics.h:55
A top-level diagnostic that may have Notes and Fixes.
Definition Diagnostics.h:95
Information required to run clang, e.g. to parse AST or do code completion.
Definition Compiler.h:50
tooling::CompileCommand CompileCommand
Definition Compiler.h:51
const ThreadsafeFS * TFS
Definition Compiler.h:52
FeatureModuleSet * FeatureModules
Definition Compiler.h:63
const SymbolIndex * Index
Definition Compiler.h:60
@ Include
#include "header.h"
Definition Symbol.h:107