clang-tools 22.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"
14#include "AST.h"
15#include "CollectMacros.h"
16#include "Compiler.h"
17#include "Config.h"
18#include "Diagnostics.h"
19#include "Feature.h"
20#include "FeatureModule.h"
21#include "Headers.h"
22#include "IncludeCleaner.h"
23#include "IncludeFixer.h"
24#include "Preamble.h"
25#include "SourceCode.h"
26#include "TidyProvider.h"
27#include "clang-include-cleaner/Record.h"
28#include "index/Symbol.h"
29#include "support/Logger.h"
30#include "support/Path.h"
31#include "support/Trace.h"
32#include "clang/AST/ASTContext.h"
33#include "clang/AST/Decl.h"
34#include "clang/AST/DeclGroup.h"
35#include "clang/AST/ExternalASTSource.h"
36#include "clang/ASTMatchers/ASTMatchFinder.h"
37#include "clang/Basic/Diagnostic.h"
38#include "clang/Basic/DiagnosticIDs.h"
39#include "clang/Basic/DiagnosticSema.h"
40#include "clang/Basic/FileEntry.h"
41#include "clang/Basic/LLVM.h"
42#include "clang/Basic/LangOptions.h"
43#include "clang/Basic/SourceLocation.h"
44#include "clang/Basic/SourceManager.h"
45#include "clang/Basic/TokenKinds.h"
46#include "clang/Frontend/CompilerInstance.h"
47#include "clang/Frontend/CompilerInvocation.h"
48#include "clang/Frontend/FrontendActions.h"
49#include "clang/Frontend/FrontendOptions.h"
50#include "clang/Frontend/PrecompiledPreamble.h"
51#include "clang/Lex/Lexer.h"
52#include "clang/Lex/PPCallbacks.h"
53#include "clang/Lex/Preprocessor.h"
54#include "clang/Sema/HeuristicResolver.h"
55#include "clang/Serialization/ASTWriter.h"
56#include "clang/Tooling/CompilationDatabase.h"
57#include "clang/Tooling/Core/Diagnostic.h"
58#include "clang/Tooling/Syntax/Tokens.h"
59#include "llvm/ADT/ArrayRef.h"
60#include "llvm/ADT/DenseMap.h"
61#include "llvm/ADT/DenseSet.h"
62#include "llvm/ADT/STLExtras.h"
63#include "llvm/ADT/STLFunctionalExtras.h"
64#include "llvm/ADT/SmallVector.h"
65#include "llvm/ADT/StringRef.h"
66#include "llvm/Support/Error.h"
67#include "llvm/Support/MemoryBuffer.h"
68#include <cassert>
69#include <cstddef>
70#include <iterator>
71#include <memory>
72#include <optional>
73#include <string>
74#include <tuple>
75#include <utility>
76#include <vector>
77
78// Force the linker to link in Clang-tidy modules.
79// clangd doesn't support the static analyzer.
80#if CLANGD_TIDY_CHECKS
81#define CLANG_TIDY_DISABLE_STATIC_ANALYZER_CHECKS
83#endif
84
85namespace clang {
86namespace clangd {
87namespace {
88
89template <class T> std::size_t getUsedBytes(const std::vector<T> &Vec) {
90 return Vec.capacity() * sizeof(T);
91}
92
93class DeclTrackingASTConsumer : public ASTConsumer {
94public:
95 DeclTrackingASTConsumer(std::vector<Decl *> &TopLevelDecls)
96 : TopLevelDecls(TopLevelDecls) {}
97
98 bool HandleTopLevelDecl(DeclGroupRef DG) override {
99 for (Decl *D : DG) {
100 auto &SM = D->getASTContext().getSourceManager();
101 if (!isInsideMainFile(D->getLocation(), SM))
102 continue;
103 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
105 continue;
106
107 // ObjCMethodDecl are not actually top-level decls.
108 if (isa<ObjCMethodDecl>(D))
109 continue;
110
111 TopLevelDecls.push_back(D);
112 }
113 return true;
114 }
115
116private:
117 std::vector<Decl *> &TopLevelDecls;
118};
119
120class ClangdFrontendAction : public SyntaxOnlyAction {
121public:
122 std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
123
124protected:
125 std::unique_ptr<ASTConsumer>
126 CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
127 return std::make_unique<DeclTrackingASTConsumer>(/*ref*/ TopLevelDecls);
128 }
129
130private:
131 std::vector<Decl *> TopLevelDecls;
132};
133
134// When using a preamble, only preprocessor events outside its bounds are seen.
135// This is almost what we want: replaying transitive preprocessing wastes time.
136// However this confuses clang-tidy checks: they don't see any #includes!
137// So we replay the *non-transitive* #includes that appear in the main-file.
138// It would be nice to replay other events (macro definitions, ifdefs etc) but
139// this addresses the most common cases fairly cheaply.
140class ReplayPreamble : private PPCallbacks {
141public:
142 // Attach preprocessor hooks such that preamble events will be injected at
143 // the appropriate time.
144 // Events will be delivered to the *currently registered* PP callbacks.
145 static void attach(std::vector<Inclusion> Includes, CompilerInstance &Clang,
146 const PreambleBounds &PB) {
147 auto &PP = Clang.getPreprocessor();
148 auto *ExistingCallbacks = PP.getPPCallbacks();
149 // No need to replay events if nobody is listening.
150 if (!ExistingCallbacks)
151 return;
152 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new ReplayPreamble(
153 std::move(Includes), ExistingCallbacks, Clang.getSourceManager(), PP,
154 Clang.getLangOpts(), PB)));
155 // We're relying on the fact that addPPCallbacks keeps the old PPCallbacks
156 // around, creating a chaining wrapper. Guard against other implementations.
157 assert(PP.getPPCallbacks() != ExistingCallbacks &&
158 "Expected chaining implementation");
159 }
160
161private:
162 ReplayPreamble(std::vector<Inclusion> Includes, PPCallbacks *Delegate,
163 const SourceManager &SM, Preprocessor &PP,
164 const LangOptions &LangOpts, const PreambleBounds &PB)
165 : Includes(std::move(Includes)), Delegate(Delegate), SM(SM), PP(PP) {
166 // Only tokenize the preamble section of the main file, as we are not
167 // interested in the rest of the tokens.
168 MainFileTokens = syntax::tokenize(
169 syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts);
170 }
171
172 // In a normal compile, the preamble traverses the following structure:
173 //
174 // mainfile.cpp
175 // <built-in>
176 // ... macro definitions like __cplusplus ...
177 // <command-line>
178 // ... macro definitions for args like -Dfoo=bar ...
179 // "header1.h"
180 // ... header file contents ...
181 // "header2.h"
182 // ... header file contents ...
183 // ... main file contents ...
184 //
185 // When using a preamble, the "header1" and "header2" subtrees get skipped.
186 // We insert them right after the built-in header, which still appears.
187 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
188 SrcMgr::CharacteristicKind Kind, FileID PrevFID) override {
189 // It'd be nice if there was a better way to identify built-in headers...
190 if (Reason == FileChangeReason::ExitFile &&
191 SM.getBufferOrFake(PrevFID).getBufferIdentifier() == "<built-in>")
192 replay();
193 }
194
195 void replay() {
196 for (const auto &Inc : Includes) {
197 OptionalFileEntryRef File;
198 if (Inc.Resolved != "")
199 File = expectedToOptional(SM.getFileManager().getFileRef(Inc.Resolved));
200
201 // Re-lex the #include directive to find its interesting parts.
202 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
203 auto HashTok = llvm::partition_point(MainFileTokens,
204 [&HashLoc](const syntax::Token &T) {
205 return T.location() < HashLoc;
206 });
207 assert(HashTok != MainFileTokens.end() && HashTok->kind() == tok::hash);
208
209 auto IncludeTok = std::next(HashTok);
210 assert(IncludeTok != MainFileTokens.end());
211
212 auto FileTok = std::next(IncludeTok);
213 assert(FileTok != MainFileTokens.end());
214
215 // Create a fake import/include token, none of the callers seem to care
216 // about clang::Token::Flags.
217 Token SynthesizedIncludeTok;
218 SynthesizedIncludeTok.startToken();
219 SynthesizedIncludeTok.setLocation(IncludeTok->location());
220 SynthesizedIncludeTok.setLength(IncludeTok->length());
221 SynthesizedIncludeTok.setKind(tok::raw_identifier);
222 SynthesizedIncludeTok.setRawIdentifierData(IncludeTok->text(SM).data());
223 PP.LookUpIdentifierInfo(SynthesizedIncludeTok);
224
225 // Same here, create a fake one for Filename, including angles or quotes.
226 Token SynthesizedFilenameTok;
227 SynthesizedFilenameTok.startToken();
228 SynthesizedFilenameTok.setLocation(FileTok->location());
229 // Note that we can't make use of FileTok->length/text in here as in the
230 // case of angled includes this will contain tok::less instead of
231 // filename. Whereas Inc.Written contains the full header name including
232 // quotes/angles.
233 SynthesizedFilenameTok.setLength(Inc.Written.length());
234 SynthesizedFilenameTok.setKind(tok::header_name);
235 SynthesizedFilenameTok.setLiteralData(Inc.Written.data());
236
237 llvm::StringRef WrittenFilename =
238 llvm::StringRef(Inc.Written).drop_front().drop_back();
239 Delegate->InclusionDirective(
240 HashTok->location(), SynthesizedIncludeTok, WrittenFilename,
241 Inc.Written.front() == '<',
242 syntax::FileRange(SM, SynthesizedFilenameTok.getLocation(),
243 SynthesizedFilenameTok.getEndLoc())
244 .toCharRange(SM),
245 File, "SearchPath", "RelPath",
246 /*SuggestedModule=*/nullptr, /*ModuleImported=*/false, Inc.FileKind);
247 if (File)
248 Delegate->FileSkipped(*File, SynthesizedFilenameTok, Inc.FileKind);
249 }
250 }
251
252 const std::vector<Inclusion> Includes;
253 PPCallbacks *Delegate;
254 const SourceManager &SM;
255 Preprocessor &PP;
256 std::vector<syntax::Token> MainFileTokens;
257};
258
259// Filter for clang diagnostics groups enabled by CTOptions.Checks.
260//
261// These are check names like clang-diagnostics-unused.
262// Note that unlike -Wunused, clang-diagnostics-unused does not imply
263// subcategories like clang-diagnostics-unused-function.
264//
265// This is used to determine which diagnostics can be enabled by ExtraArgs in
266// the clang-tidy configuration.
267class TidyDiagnosticGroups {
268 // Whether all diagnostic groups are enabled by default.
269 // True if we've seen clang-diagnostic-*.
270 bool Default = false;
271 // Set of diag::Group whose enablement != Default.
272 // If Default is false, this is foo where we've seen clang-diagnostic-foo.
273 llvm::DenseSet<unsigned> Exceptions;
274
275public:
276 TidyDiagnosticGroups(llvm::StringRef Checks) {
277 constexpr llvm::StringLiteral CDPrefix = "clang-diagnostic-";
278
279 llvm::StringRef Check;
280 while (!Checks.empty()) {
281 std::tie(Check, Checks) = Checks.split(',');
282 Check = Check.trim();
283
284 if (Check.empty())
285 continue;
286
287 bool Enable = !Check.consume_front("-");
288 bool Glob = Check.consume_back("*");
289 if (Glob) {
290 // Is this clang-diagnostic-*, or *, or so?
291 // (We ignore all other types of globs).
292 if (CDPrefix.starts_with(Check)) {
293 Default = Enable;
294 Exceptions.clear();
295 }
296 continue;
297 }
298
299 // In "*,clang-diagnostic-foo", the latter is a no-op.
300 if (Default == Enable)
301 continue;
302 // The only non-glob entries we care about are clang-diagnostic-foo.
303 if (!Check.consume_front(CDPrefix))
304 continue;
305
306 if (auto Group = DiagnosticIDs::getGroupForWarningOption(Check))
307 Exceptions.insert(static_cast<unsigned>(*Group));
308 }
309 }
310
311 bool operator()(diag::Group GroupID) const {
312 return Exceptions.contains(static_cast<unsigned>(GroupID)) ? !Default
313 : Default;
314 }
315};
316
317// Find -W<group> and -Wno-<group> options in ExtraArgs and apply them to Diags.
318//
319// This is used to handle ExtraArgs in clang-tidy configuration.
320// We don't use clang's standard handling of this as we want slightly different
321// behavior (e.g. we want to exclude these from -Wno-error).
322void applyWarningOptions(llvm::ArrayRef<std::string> ExtraArgs,
323 llvm::function_ref<bool(diag::Group)> EnabledGroups,
324 DiagnosticsEngine &Diags) {
325 for (llvm::StringRef Group : ExtraArgs) {
326 // Only handle args that are of the form -W[no-]<group>.
327 // Other flags are possible but rare and deliberately out of scope.
328 llvm::SmallVector<diag::kind> Members;
329 if (!Group.consume_front("-W") || Group.empty())
330 continue;
331 bool Enable = !Group.consume_front("no-");
332 if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
333 diag::Flavor::WarningOrError, Group, Members))
334 continue;
335
336 // Upgrade (or downgrade) the severity of each diagnostic in the group.
337 // If -Werror is on, newly added warnings will be treated as errors.
338 // We don't want this, so keep track of them to fix afterwards.
339 bool NeedsWerrorExclusion = false;
340 for (diag::kind ID : Members) {
341 if (Enable) {
342 if (Diags.getDiagnosticLevel(ID, SourceLocation()) <
343 DiagnosticsEngine::Warning) {
344 auto Group = Diags.getDiagnosticIDs()->getGroupForDiag(ID);
345 if (!Group || !EnabledGroups(*Group))
346 continue;
347 Diags.setSeverity(ID, diag::Severity::Warning, SourceLocation());
348 if (Diags.getWarningsAsErrors())
349 NeedsWerrorExclusion = true;
350 }
351 } else {
352 Diags.setSeverity(ID, diag::Severity::Ignored, SourceLocation());
353 }
354 }
355 if (NeedsWerrorExclusion) {
356 // FIXME: there's no API to suppress -Werror for single diagnostics.
357 // In some cases with sub-groups, we may end up erroneously
358 // downgrading diagnostics that were -Werror in the compile command.
359 Diags.setDiagnosticGroupWarningAsError(Group, false);
360 }
361 }
362}
363
364std::vector<Diag> getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code,
365 const ThreadsafeFS &TFS) {
366 auto &Cfg = Config::current();
367 if (Cfg.Diagnostics.SuppressAll)
368 return {};
369 bool SuppressMissing =
370 Cfg.Diagnostics.Suppress.contains("missing-includes") ||
371 Cfg.Diagnostics.MissingIncludes == Config::IncludesPolicy::None;
372 bool SuppressUnused =
373 Cfg.Diagnostics.Suppress.contains("unused-includes") ||
374 Cfg.Diagnostics.UnusedIncludes == Config::IncludesPolicy::None;
375 if (SuppressMissing && SuppressUnused)
376 return {};
377 auto Findings = computeIncludeCleanerFindings(
378 AST, Cfg.Diagnostics.Includes.AnalyzeAngledIncludes);
379 if (SuppressMissing)
380 Findings.MissingIncludes.clear();
381 if (SuppressUnused)
382 Findings.UnusedIncludes.clear();
384 AST, Code, Findings, TFS, Cfg.Diagnostics.Includes.IgnoreHeader,
385 Cfg.Style.AngledHeaders, Cfg.Style.QuotedHeaders);
386}
387
388tidy::ClangTidyCheckFactories
389filterFastTidyChecks(const tidy::ClangTidyCheckFactories &All,
391 if (Policy == Config::FastCheckPolicy::None)
392 return All;
393 bool AllowUnknown = Policy == Config::FastCheckPolicy::Loose;
394 tidy::ClangTidyCheckFactories Fast;
395 for (const auto &Factory : All) {
396 if (isFastTidyCheck(Factory.getKey()).value_or(AllowUnknown))
397 Fast.registerCheckFactory(Factory.first(), Factory.second);
398 }
399 return Fast;
400}
401
402} // namespace
403
404std::optional<ParsedAST>
405ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
406 std::unique_ptr<clang::CompilerInvocation> CI,
407 llvm::ArrayRef<Diag> CompilerInvocationDiags,
408 std::shared_ptr<const PreambleData> Preamble) {
409 trace::Span Tracer("BuildAST");
410 SPAN_ATTACH(Tracer, "File", Filename);
411 const Config &Cfg = Config::current();
412
413 auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
414 if (Preamble && Preamble->StatCache)
415 VFS = Preamble->StatCache->getConsumingFS(std::move(VFS));
416
417 assert(CI);
418
419 if (CI->getFrontendOpts().Inputs.size() > 0) {
420 auto Lang = CI->getFrontendOpts().Inputs[0].getKind().getLanguage();
421 if (Lang == Language::Asm || Lang == Language::LLVM_IR) {
422 elog("Clangd does not support assembly or IR source files");
423 return std::nullopt;
424 }
425 }
426
427 // Command-line parsing sets DisableFree to true by default, but we don't want
428 // to leak memory in clangd.
429 CI->getFrontendOpts().DisableFree = false;
430 const PrecompiledPreamble *PreamblePCH =
431 Preamble ? &Preamble->Preamble : nullptr;
432
433 // This is on-by-default in windows to allow parsing SDK headers, but it
434 // breaks many features. Disable it for the main-file (not preamble).
435 CI->getLangOpts().DelayedTemplateParsing = false;
436
437 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
438 if (Inputs.FeatureModules) {
439 for (auto &M : *Inputs.FeatureModules) {
440 if (auto Listener = M.astListeners())
441 ASTListeners.emplace_back(std::move(Listener));
442 }
443 }
444 StoreDiags ASTDiags;
445 ASTDiags.setDiagCallback(
446 [&ASTListeners](const clang::Diagnostic &D, clangd::Diag &Diag) {
447 for (const auto &L : ASTListeners)
448 L->sawDiagnostic(D, Diag);
449 });
450
451 // Adjust header search options to load the built module files recorded
452 // in RequiredModules.
453 if (Preamble && Preamble->RequiredModules)
454 Preamble->RequiredModules->adjustHeaderSearchOptions(
455 CI->getHeaderSearchOpts());
456
457 std::optional<PreamblePatch> Patch;
458 // We might use an ignoring diagnostic consumer if they are going to be
459 // dropped later on to not pay for extra latency by processing them.
460 DiagnosticConsumer *DiagConsumer = &ASTDiags;
461 IgnoreDiagnostics DropDiags;
462 if (Preamble) {
463 Patch = PreamblePatch::createFullPatch(Filename, Inputs, *Preamble);
464 Patch->apply(*CI);
465 }
466 auto Clang = prepareCompilerInstance(
467 std::move(CI), PreamblePCH,
468 llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS,
469 *DiagConsumer);
470
471 if (!Clang) {
472 // The last diagnostic contains information about the reason of this
473 // failure.
474 std::vector<Diag> Diags(ASTDiags.take());
475 elog("Failed to prepare a compiler instance: {0}",
476 !Diags.empty() ? static_cast<DiagBase &>(Diags.back()).Message
477 : "unknown error");
478 return std::nullopt;
479 }
480 tidy::ClangTidyOptions ClangTidyOpts;
481 {
482 trace::Span Tracer("ClangTidyOpts");
483 ClangTidyOpts = getTidyOptionsForFile(Inputs.ClangTidyProvider, Filename);
484 dlog("ClangTidy configuration for file {0}: {1}", Filename,
485 tidy::configurationAsText(ClangTidyOpts));
486
487 // If clang-tidy is configured to emit clang warnings, we should too.
488 //
489 // Such clang-tidy configuration consists of two parts:
490 // - ExtraArgs: ["-Wfoo"] causes clang to produce the warnings
491 // - Checks: "clang-diagnostic-foo" prevents clang-tidy filtering them out
492 //
493 // In clang-tidy, diagnostics are emitted if they pass both checks.
494 // When groups contain subgroups, -Wparent includes the child, but
495 // clang-diagnostic-parent does not.
496 //
497 // We *don't* want to change the compile command directly. This can have
498 // too many unexpected effects: breaking the command, interactions with
499 // -- and -Werror, etc. Besides, we've already parsed the command.
500 // Instead we parse the -W<group> flags and handle them directly.
501 //
502 // Similarly, we don't want to use Checks to filter clang diagnostics after
503 // they are generated, as this spreads clang-tidy emulation everywhere.
504 // Instead, we just use these to filter which extra diagnostics we enable.
505 auto &Diags = Clang->getDiagnostics();
506 TidyDiagnosticGroups TidyGroups(ClangTidyOpts.Checks ? *ClangTidyOpts.Checks
507 : llvm::StringRef());
508 if (ClangTidyOpts.ExtraArgsBefore)
509 applyWarningOptions(*ClangTidyOpts.ExtraArgsBefore, TidyGroups, Diags);
510 if (ClangTidyOpts.ExtraArgs)
511 applyWarningOptions(*ClangTidyOpts.ExtraArgs, TidyGroups, Diags);
512 }
513
514 auto Action = std::make_unique<ClangdFrontendAction>();
515 const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
516 if (!Action->BeginSourceFile(*Clang, MainInput)) {
517 elog("BeginSourceFile() failed when building AST for {0}",
518 MainInput.getFile());
519 return std::nullopt;
520 }
521 // If we saw an include guard in the preamble section of the main file,
522 // mark the main-file as include-guarded.
523 // This information is part of the HeaderFileInfo but is not loaded from the
524 // preamble as the file's size is part of its identity and may have changed.
525 // (The rest of HeaderFileInfo is not relevant for our purposes).
526 if (Preamble && Preamble->MainIsIncludeGuarded) {
527 const SourceManager &SM = Clang->getSourceManager();
528 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
529 Clang->getPreprocessor().getHeaderSearchInfo().MarkFileIncludeOnce(*MainFE);
530 }
531
532 // Set up ClangTidy. Must happen after BeginSourceFile() so ASTContext exists.
533 // Clang-tidy has some limitations to ensure reasonable performance:
534 // - checks don't see all preprocessor events in the preamble
535 // - matchers run only over the main-file top-level decls (and can't see
536 // ancestors outside this scope).
537 // In practice almost all checks work well without modifications.
538 std::vector<std::unique_ptr<tidy::ClangTidyCheck>> CTChecks;
539 ast_matchers::MatchFinder CTFinder;
540 std::optional<tidy::ClangTidyContext> CTContext;
541 // Must outlive FixIncludes.
542 auto BuildDir = VFS->getCurrentWorkingDirectory();
543 std::optional<IncludeFixer> FixIncludes;
544 llvm::DenseMap<diag::kind, DiagnosticsEngine::Level> OverriddenSeverity;
545 // No need to run clang-tidy or IncludeFixerif we are not going to surface
546 // diagnostics.
547 {
548 trace::Span Tracer("ClangTidyInit");
549 static const auto *AllCTFactories = [] {
550 auto *CTFactories = new tidy::ClangTidyCheckFactories;
551 for (const auto &E : tidy::ClangTidyModuleRegistry::entries())
552 E.instantiate()->addCheckFactories(*CTFactories);
553 return CTFactories;
554 }();
555 tidy::ClangTidyCheckFactories FastFactories = filterFastTidyChecks(
556 *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
557 CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
558 tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
559 // The lifetime of DiagnosticOptions is managed by \c Clang.
560 CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics());
561 CTContext->setASTContext(&Clang->getASTContext());
562 CTContext->setCurrentFile(Filename);
563 CTContext->setSelfContainedDiags(true);
564 CTChecks = FastFactories.createChecksForLanguage(&*CTContext);
565 Preprocessor *PP = &Clang->getPreprocessor();
566 for (const auto &Check : CTChecks) {
567 Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP);
568 Check->registerMatchers(&CTFinder);
569 }
570
571 // Clang only corrects typos for use of undeclared functions in C if that
572 // use is an error. Include fixer relies on typo correction, so pretend
573 // this is an error. (The actual typo correction is nice too).
574 // We restore the original severity in the level adjuster.
575 // FIXME: It would be better to have a real API for this, but what?
576 for (auto ID : {diag::ext_implicit_function_decl_c99,
577 diag::ext_implicit_lib_function_decl,
578 diag::ext_implicit_lib_function_decl_c99,
579 diag::warn_implicit_function_decl}) {
580 OverriddenSeverity.try_emplace(
581 ID, Clang->getDiagnostics().getDiagnosticLevel(ID, SourceLocation()));
582 Clang->getDiagnostics().setSeverity(ID, diag::Severity::Error,
583 SourceLocation());
584 }
585
586 ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
587 const clang::Diagnostic &Info) {
588 if (Cfg.Diagnostics.SuppressAll ||
590 Clang->getLangOpts()))
591 return DiagnosticsEngine::Ignored;
592
593 auto It = OverriddenSeverity.find(Info.getID());
594 if (It != OverriddenSeverity.end())
595 DiagLevel = It->second;
596
597 if (!CTChecks.empty()) {
598 std::string CheckName = CTContext->getCheckName(Info.getID());
599 bool IsClangTidyDiag = !CheckName.empty();
600 if (IsClangTidyDiag) {
601 if (Cfg.Diagnostics.Suppress.contains(CheckName))
602 return DiagnosticsEngine::Ignored;
603 // Check for suppression comment. Skip the check for diagnostics not
604 // in the main file, because we don't want that function to query the
605 // source buffer for preamble files. For the same reason, we ask
606 // shouldSuppressDiagnostic to avoid I/O.
607 // We let suppression comments take precedence over warning-as-error
608 // to match clang-tidy's behaviour.
609 bool IsInsideMainFile =
610 Info.hasSourceManager() &&
611 isInsideMainFile(Info.getLocation(), Info.getSourceManager());
612 SmallVector<tooling::Diagnostic, 1> TidySuppressedErrors;
613 if (IsInsideMainFile && CTContext->shouldSuppressDiagnostic(
614 DiagLevel, Info, TidySuppressedErrors,
615 /*AllowIO=*/false,
616 /*EnableNolintBlocks=*/true)) {
617 // FIXME: should we expose the suppression error (invalid use of
618 // NOLINT comments)?
619 return DiagnosticsEngine::Ignored;
620 }
621 if (!CTContext->getOptions().SystemHeaders.value_or(false) &&
622 Info.hasSourceManager() &&
623 Info.getSourceManager().isInSystemMacro(Info.getLocation()))
624 return DiagnosticsEngine::Ignored;
625
626 // Check for warning-as-error.
627 if (DiagLevel == DiagnosticsEngine::Warning &&
628 CTContext->treatAsError(CheckName)) {
629 return DiagnosticsEngine::Error;
630 }
631 }
632 }
633 return DiagLevel;
634 });
635
636 // Add IncludeFixer which can recover diagnostics caused by missing includes
637 // (e.g. incomplete type) and attach include insertion fixes to diagnostics.
638 if (Inputs.Index && !BuildDir.getError()) {
639 auto Style =
640 getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS, false);
641 auto Inserter = std::make_shared<IncludeInserter>(
642 Filename, Inputs.Contents, Style, BuildDir.get(),
643 &Clang->getPreprocessor().getHeaderSearchInfo(),
645 ArrayRef<Inclusion> MainFileIncludes;
646 if (Preamble) {
647 MainFileIncludes = Preamble->Includes.MainFileIncludes;
648 for (const auto &Inc : Preamble->Includes.MainFileIncludes)
649 Inserter->addExisting(Inc);
650 }
651 // FIXME: Consider piping through ASTSignals to fetch this to handle the
652 // case where a header file contains ObjC decls but no #imports.
653 Symbol::IncludeDirective Directive =
655 ? preferredIncludeDirective(Filename, Clang->getLangOpts(),
656 MainFileIncludes, {})
658 FixIncludes.emplace(Filename, Inserter, *Inputs.Index,
659 /*IndexRequestLimit=*/5, Directive);
660 ASTDiags.contributeFixes([&FixIncludes](DiagnosticsEngine::Level DiagLevl,
661 const clang::Diagnostic &Info) {
662 return FixIncludes->fix(DiagLevl, Info);
663 });
664 Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder());
665 }
666 }
667
668 IncludeStructure Includes;
669 include_cleaner::PragmaIncludes PI;
670 // If we are using a preamble, copy existing includes.
671 if (Preamble) {
672 Includes = Preamble->Includes;
673 Includes.MainFileIncludes = Patch->preambleIncludes();
674 // Replay the preamble includes so that clang-tidy checks can see them.
675 ReplayPreamble::attach(Patch->preambleIncludes(), *Clang,
676 Patch->modifiedBounds());
677 PI = *Preamble->Pragmas;
678 }
679 // Important: collectIncludeStructure is registered *after* ReplayPreamble!
680 // Otherwise we would collect the replayed includes again...
681 // (We can't *just* use the replayed includes, they don't have Resolved path).
682 Includes.collect(*Clang);
683 // Same for pragma-includes, we're already inheriting preamble includes, so we
684 // should only receive callbacks for non-preamble mainfile includes.
685 PI.record(*Clang);
686 // Copy over the macros in the preamble region of the main file, and combine
687 // with non-preamble macros below.
688 MainFileMacros Macros;
689 std::vector<PragmaMark> Marks;
690 if (Preamble) {
691 Macros = Patch->mainFileMacros();
692 Marks = Patch->marks();
693 }
694 auto &PP = Clang->getPreprocessor();
695 auto MacroCollector = std::make_unique<CollectMainFileMacros>(PP, Macros);
696 auto *MacroCollectorPtr = MacroCollector.get(); // so we can call doneParse()
697 PP.addPPCallbacks(std::move(MacroCollector));
698
699 PP.addPPCallbacks(
700 collectPragmaMarksCallback(Clang->getSourceManager(), Marks));
701
702 // FIXME: Attach a comment handler to take care of
703 // keep/export/no_include etc. IWYU pragmas.
704
705 // Collect tokens of the main file.
706 syntax::TokenCollector CollectTokens(PP);
707
708 // To remain consistent with preamble builds, these callbacks must be called
709 // exactly here, after preprocessor is initialized and BeginSourceFile() was
710 // called already.
711 for (const auto &L : ASTListeners)
712 L->beforeExecute(*Clang);
713
714 if (llvm::Error Err = Action->Execute())
715 log("Execute() failed when building AST for {0}: {1}", MainInput.getFile(),
716 toString(std::move(Err)));
717
718 // Disable the macro collector for the remainder of this function, e.g.
719 // clang-tidy checkers.
720 MacroCollectorPtr->doneParse();
721
722 // We have to consume the tokens before running clang-tidy to avoid collecting
723 // tokens from running the preprocessor inside the checks (only
724 // modernize-use-trailing-return-type does that today).
725 syntax::TokenBuffer Tokens = std::move(CollectTokens).consume();
726 // Makes SelectionTree build much faster.
727 Tokens.indexExpandedTokens();
728 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();
729 // AST traversals should exclude the preamble, to avoid performance cliffs.
730 Clang->getASTContext().setTraversalScope(ParsedDecls);
731 if (!CTChecks.empty()) {
732 // Run the AST-dependent part of the clang-tidy checks.
733 // (The preprocessor part ran already, via PPCallbacks).
734 trace::Span Tracer("ClangTidyMatch");
735 CTFinder.matchAST(Clang->getASTContext());
736 }
737
738 // XXX: This is messy: clang-tidy checks flush some diagnostics at EOF.
739 // However Action->EndSourceFile() would destroy the ASTContext!
740 // So just inform the preprocessor of EOF, while keeping everything alive.
741 PP.EndSourceFile();
742 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
743 // has a longer lifetime.
744 Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
745 // CompilerInstance won't run this callback, do it directly.
746 ASTDiags.EndSourceFile();
747
748 std::vector<Diag> Diags = CompilerInvocationDiags;
749 // FIXME: Also skip generation of diagnostics altogether to speed up ast
750 // builds when we are patching a stale preamble.
751 // Add diagnostics from the preamble, if any.
752 if (Preamble)
753 llvm::append_range(Diags, Patch->patchedDiags());
754 // Finally, add diagnostics coming from the AST.
755 {
756 std::vector<Diag> D = ASTDiags.take(&*CTContext);
757 Diags.insert(Diags.end(), D.begin(), D.end());
758 }
759 ParsedAST Result(Filename, Inputs.Version, std::move(Preamble),
760 std::move(Clang), std::move(Action), std::move(Tokens),
761 std::move(Macros), std::move(Marks), std::move(ParsedDecls),
762 std::move(Diags), std::move(Includes), std::move(PI));
763 llvm::move(getIncludeCleanerDiags(Result, Inputs.Contents, *Inputs.TFS),
764 std::back_inserter(Result.Diags));
765 return std::move(Result);
766}
767
768ParsedAST::ParsedAST(ParsedAST &&Other) = default;
769
770ParsedAST &ParsedAST::operator=(ParsedAST &&Other) = default;
771
773 if (Action) {
774 // We already notified the PP of end-of-file earlier, so detach it first.
775 // We must keep it alive until after EndSourceFile(), Sema relies on this.
776 auto PP = Clang->getPreprocessorPtr(); // Keep PP alive for now.
777 Clang->setPreprocessor(nullptr); // Detach so we don't send EOF again.
778 Action->EndSourceFile(); // Destroy ASTContext and Sema.
779 // Now Sema is gone, it's safe for PP to go out of scope.
780 }
781}
782
783ASTContext &ParsedAST::getASTContext() { return Clang->getASTContext(); }
784
785const ASTContext &ParsedAST::getASTContext() const {
786 return Clang->getASTContext();
787}
788
789Sema &ParsedAST::getSema() { return Clang->getSema(); }
790
791Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
792
793std::shared_ptr<Preprocessor> ParsedAST::getPreprocessorPtr() {
794 return Clang->getPreprocessorPtr();
795}
796
797const Preprocessor &ParsedAST::getPreprocessor() const {
798 return Clang->getPreprocessor();
799}
800
801llvm::ArrayRef<Decl *> ParsedAST::getLocalTopLevelDecls() {
802 return LocalTopLevelDecls;
803}
804
805llvm::ArrayRef<const Decl *> ParsedAST::getLocalTopLevelDecls() const {
806 return LocalTopLevelDecls;
807}
808
809const MainFileMacros &ParsedAST::getMacros() const { return Macros; }
810const std::vector<PragmaMark> &ParsedAST::getMarks() const { return Marks; }
811
812std::size_t ParsedAST::getUsedBytes() const {
813 auto &AST = getASTContext();
814 // FIXME(ibiryukov): we do not account for the dynamically allocated part of
815 // Message and Fixes inside each diagnostic.
816 std::size_t Total =
817 clangd::getUsedBytes(LocalTopLevelDecls) + clangd::getUsedBytes(Diags);
818
819 // FIXME: the rest of the function is almost a direct copy-paste from
820 // libclang's clang_getCXTUResourceUsage. We could share the implementation.
821
822 // Sum up various allocators inside the ast context and the preprocessor.
823 Total += AST.getASTAllocatedMemory();
824 Total += AST.getSideTableAllocatedMemory();
825 Total += AST.Idents.getAllocator().getTotalMemory();
826 Total += AST.Selectors.getTotalMemory();
827
828 Total += AST.getSourceManager().getContentCacheSize();
829 Total += AST.getSourceManager().getDataStructureSizes();
830 Total += AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
831
832 if (ExternalASTSource *Ext = AST.getExternalSource())
833 Total += Ext->getMemoryBufferSizes().malloc_bytes;
834
835 const Preprocessor &PP = getPreprocessor();
836 Total += PP.getTotalMemory();
837 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
838 Total += PRec->getTotalMemory();
839 Total += PP.getHeaderSearchInfo().getTotalMemory();
840
841 return Total;
842}
843
845 return Includes;
846}
847
848ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
849 std::shared_ptr<const PreambleData> Preamble,
850 std::unique_ptr<CompilerInstance> Clang,
851 std::unique_ptr<FrontendAction> Action,
852 syntax::TokenBuffer Tokens, MainFileMacros Macros,
853 std::vector<PragmaMark> Marks,
854 std::vector<Decl *> LocalTopLevelDecls,
855 std::vector<Diag> Diags, IncludeStructure Includes,
856 include_cleaner::PragmaIncludes PI)
857 : TUPath(TUPath), Version(Version), Preamble(std::move(Preamble)),
858 Clang(std::move(Clang)), Action(std::move(Action)),
859 Tokens(std::move(Tokens)), Macros(std::move(Macros)),
860 Marks(std::move(Marks)), Diags(std::move(Diags)),
861 LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
862 Includes(std::move(Includes)), PI(std::move(PI)),
863 Resolver(std::make_unique<HeuristicResolver>(getASTContext())) {
864 assert(this->Clang);
865 assert(this->Action);
866}
867
868const include_cleaner::PragmaIncludes &ParsedAST::getPragmaIncludes() const {
869 return PI;
870}
871
872std::optional<llvm::StringRef> ParsedAST::preambleVersion() const {
873 if (!Preamble)
874 return std::nullopt;
875 return llvm::StringRef(Preamble->Version);
876}
877
878llvm::ArrayRef<Diag> ParsedAST::getDiagnostics() const { return Diags; }
879} // namespace clangd
880} // namespace clang
static cl::opt< std::string > Checks("checks", desc(R"( Comma-separated list of globs with optional '-' prefix. Globs are processed in order of appearance in the list. Globs without '-' prefix add checks with matching names to the set, globs with the '-' prefix remove checks with matching names from the set of enabled checks. This option's value is appended to the value of the 'Checks' option in .clang-tidy file, if any. )"), cl::init(""), cl::cat(ClangTidyCategory))
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
#define dlog(...)
Definition Logger.h:101
#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:46
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:899
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 setLevelAdjuster(LevelAdjuster Adjuster)
If set, this allows the client of this class to adjust the level of diagnostics, such as promoting wa...
std::vector< Diag > take(const clang::tidy::ClangTidyContext *Tidy=nullptr)
void setDiagCallback(DiagCallback CB)
Invokes a callback every time a diagnostics is completely formed.
void EndSourceFile() override
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
A collection of ClangTidyCheckFactory instances.
std::vector< std::unique_ptr< ClangTidyCheck > > createChecksForLanguage(ClangTidyContext *Context) const
Create instances of checks that are enabled for the current Language.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
bool isDiagnosticSuppressed(const clang::Diagnostic &Diag, const llvm::StringSet<> &Suppress, const LangOptions &LangOpts)
Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
@ Info
An information message.
Definition Protocol.h:738
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.
std::optional< bool > isFastTidyCheck(llvm::StringRef Check)
Returns if Check is known-fast, known-slow, or its speed is unknown.
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:385
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:131
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
tidy::ClangTidyOptions getTidyOptionsForFile(TidyProviderRef Provider, llvm::StringRef Filename)
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.
std::string configurationAsText(const ClangTidyOptions &Options)
Serializes configuration to a YAML-encoded string.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Settings that express user/project preferences and control clangd behavior.
Definition Config.h:44
struct clang::clangd::Config::@314053012031341203055315320366267371313202370174 Style
Style of the codebase.
FastCheckPolicy FastCheckFilter
Definition Config.h:112
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
Definition Config.cpp:17
struct clang::clangd::Config::@343034053122374337352226322054223376344037116252 Diagnostics
Controls warnings and errors when parsing code.
llvm::StringSet Suppress
Definition Config.h:105
struct clang::clangd::Config::@343034053122374337352226322054223376344037116252::@107156241027253143221327255130274177352007274355 ClangTidy
Configures what clang-tidy checks to run and options to use with them.
std::vector< std::function< bool(llvm::StringRef)> > QuotedHeaders
Definition Config.h:134
std::vector< std::function< bool(llvm::StringRef)> > AngledHeaders
Definition Config.h:135
Contains basic information about a diagnostic.
Definition Diagnostics.h:58
A top-level diagnostic that may have Notes and Fixes.
Definition Diagnostics.h:98
Information required to run clang, e.g. to parse AST or do code completion.
Definition Compiler.h:49
TidyProviderRef ClangTidyProvider
Definition Compiler.h:61
tooling::CompileCommand CompileCommand
Definition Compiler.h:50
const ThreadsafeFS * TFS
Definition Compiler.h:51
FeatureModuleSet * FeatureModules
Definition Compiler.h:63
const SymbolIndex * Index
Definition Compiler.h:59
@ Include
#include "header.h"
Definition Symbol.h:93
Contains options for clang-tidy.
std::optional< std::string > Checks
Checks filter.
std::optional< ArgList > ExtraArgsBefore
Add extra compilation arguments to the start of the list.
std::optional< ArgList > ExtraArgs
Add extra compilation arguments to the end of the list.