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