clang-tools  3.8.0
ClangTidy.cpp
Go to the documentation of this file.
1 //===--- tools/extra/clang-tidy/ClangTidy.cpp - Clang tidy tool -----------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file This file implements a clang-tidy tool.
11 ///
12 /// This tool uses the Clang Tooling infrastructure, see
13 /// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
14 /// for details on setting it up with LLVM source tree.
15 ///
16 //===----------------------------------------------------------------------===//
17 
18 #include "ClangTidy.h"
21 #include "clang/AST/ASTConsumer.h"
22 #include "clang/AST/ASTContext.h"
23 #include "clang/AST/Decl.h"
24 #include "clang/ASTMatchers/ASTMatchFinder.h"
25 #include "clang/Frontend/ASTConsumers.h"
26 #include "clang/Frontend/CompilerInstance.h"
27 #include "clang/Frontend/FrontendActions.h"
28 #include "clang/Frontend/FrontendDiagnostic.h"
29 #include "clang/Frontend/MultiplexConsumer.h"
30 #include "clang/Frontend/TextDiagnosticPrinter.h"
31 #include "clang/Lex/PPCallbacks.h"
32 #include "clang/Lex/Preprocessor.h"
33 #include "clang/Rewrite/Frontend/FixItRewriter.h"
34 #include "clang/Rewrite/Frontend/FrontendActions.h"
35 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
36 #include "clang/Tooling/Refactoring.h"
37 #include "clang/Tooling/ReplacementsYaml.h"
38 #include "clang/Tooling/Tooling.h"
39 #include "llvm/Support/Process.h"
40 #include "llvm/Support/Signals.h"
41 #include <algorithm>
42 #include <utility>
43 
44 using namespace clang::ast_matchers;
45 using namespace clang::driver;
46 using namespace clang::tooling;
47 using namespace llvm;
48 
49 template class llvm::Registry<clang::tidy::ClangTidyModule>;
50 
51 namespace clang {
52 namespace tidy {
53 
54 namespace {
55 static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
56 
57 static const StringRef StaticAnalyzerChecks[] = {
58 #define GET_CHECKERS
59 #define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \
60  FULLNAME,
61 #include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc"
62 #undef CHECKER
63 #undef GET_CHECKERS
64 };
65 
66 class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
67 public:
68  AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {}
69 
70  void FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags,
71  FilesMade *filesMade) override {
72  for (const ento::PathDiagnostic *PD : Diags) {
73  SmallString<64> CheckName(AnalyzerCheckNamePrefix);
74  CheckName += PD->getCheckName();
75  Context.diag(CheckName, PD->getLocation().asLocation(),
76  PD->getShortDescription())
77  << PD->path.back()->getRanges();
78 
79  for (const auto &DiagPiece :
80  PD->path.flatten(/*ShouldFlattenMacros=*/true)) {
81  Context.diag(CheckName, DiagPiece->getLocation().asLocation(),
82  DiagPiece->getString(), DiagnosticIDs::Note)
83  << DiagPiece->getRanges();
84  }
85  }
86  }
87 
88  StringRef getName() const override { return "ClangTidyDiags"; }
89  bool supportsLogicalOpControlFlow() const override { return true; }
90  bool supportsCrossFileDiagnostics() const override { return true; }
91 
92 private:
93  ClangTidyContext &Context;
94 };
95 
96 class ErrorReporter {
97 public:
98  ErrorReporter(bool ApplyFixes)
99  : Files(FileSystemOptions()), DiagOpts(new DiagnosticOptions()),
100  DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
101  Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
102  DiagPrinter),
104  ApplyFixes(ApplyFixes), TotalFixes(0), AppliedFixes(0) {
105  DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
106  DiagPrinter->BeginSourceFile(LangOpts);
107  }
108 
109  void reportDiagnostic(const ClangTidyError &Error) {
110  const ClangTidyMessage &Message = Error.Message;
111  SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
112  // Contains a pair for each attempted fix: location and whether the fix was
113  // applied successfully.
114  SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
115  {
116  auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
117  auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]"))
118  << Message.Message << Error.CheckName;
119  for (const tooling::Replacement &Fix : Error.Fix) {
120  SourceLocation FixLoc = getLocation(Fix.getFilePath(), Fix.getOffset());
121  SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength());
122  Diag << FixItHint::CreateReplacement(SourceRange(FixLoc, FixEndLoc),
123  Fix.getReplacementText());
124  ++TotalFixes;
125  if (ApplyFixes) {
126  bool Success = Fix.isApplicable() && Fix.apply(Rewrite);
127  if (Success)
128  ++AppliedFixes;
129  FixLocations.push_back(std::make_pair(FixLoc, Success));
130  }
131  }
132  }
133  for (auto Fix : FixLocations) {
134  Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
135  : diag::note_fixit_failed);
136  }
137  for (const ClangTidyMessage &Note : Error.Notes)
138  reportNote(Note);
139  }
140 
141  void Finish() {
142  // FIXME: Run clang-format on changes.
143  if (ApplyFixes && TotalFixes > 0) {
144  llvm::errs() << "clang-tidy applied " << AppliedFixes << " of "
145  << TotalFixes << " suggested fixes.\n";
146  Rewrite.overwriteChangedFiles();
147  }
148  }
149 
150 private:
151  SourceLocation getLocation(StringRef FilePath, unsigned Offset) {
152  if (FilePath.empty())
153  return SourceLocation();
154 
155  const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
156  FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
157  return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
158  }
159 
160  void reportNote(const ClangTidyMessage &Message) {
161  SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
162  DiagnosticBuilder Diag =
163  Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
164  << Message.Message;
165  }
166 
167  FileManager Files;
168  LangOptions LangOpts; // FIXME: use langopts from each original file
169  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
171  DiagnosticsEngine Diags;
172  SourceManager SourceMgr;
173  Rewriter Rewrite;
175  unsigned TotalFixes;
176  unsigned AppliedFixes;
177 };
178 
179 class ClangTidyASTConsumer : public MultiplexConsumer {
180 public:
181  ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers,
182  std::unique_ptr<ast_matchers::MatchFinder> Finder,
183  std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
184  : MultiplexConsumer(std::move(Consumers)), Finder(std::move(Finder)),
185  Checks(std::move(Checks)) {}
186 
187 private:
188  std::unique_ptr<ast_matchers::MatchFinder> Finder;
189  std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
190 };
191 
192 } // namespace
193 
194 ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
196  : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
197  for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
198  E = ClangTidyModuleRegistry::end();
199  I != E; ++I) {
200  std::unique_ptr<ClangTidyModule> Module(I->instantiate());
201  Module->addCheckFactories(*CheckFactories);
202  }
203 }
204 
206  AnalyzerOptionsRef AnalyzerOptions) {
207  StringRef AnalyzerPrefix(AnalyzerCheckNamePrefix);
208  for (const auto &Opt : Opts.CheckOptions) {
209  StringRef OptName(Opt.first);
210  if (!OptName.startswith(AnalyzerPrefix))
211  continue;
212  AnalyzerOptions->Config[OptName.substr(AnalyzerPrefix.size())] = Opt.second;
213  }
214 }
215 
216 std::unique_ptr<clang::ASTConsumer>
218  clang::CompilerInstance &Compiler, StringRef File) {
219  // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
220  // modify Compiler.
221  Context.setSourceManager(&Compiler.getSourceManager());
222  Context.setCurrentFile(File);
223  Context.setASTContext(&Compiler.getASTContext());
224 
225  std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
226  CheckFactories->createChecks(&Context, Checks);
227 
228  ast_matchers::MatchFinder::MatchFinderOptions FinderOptions;
229  if (auto *P = Context.getCheckProfileData())
230  FinderOptions.CheckProfiling.emplace(P->Records);
231 
232  std::unique_ptr<ast_matchers::MatchFinder> Finder(
233  new ast_matchers::MatchFinder(std::move(FinderOptions)));
234 
235  for (auto &Check : Checks) {
236  Check->registerMatchers(&*Finder);
237  Check->registerPPCallbacks(Compiler);
238  }
239 
240  std::vector<std::unique_ptr<ASTConsumer>> Consumers;
241  if (!Checks.empty())
242  Consumers.push_back(Finder->newASTConsumer());
243 
244  AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
245  // FIXME: Remove this option once clang's cfg-temporary-dtors option defaults
246  // to true.
247  AnalyzerOptions->Config["cfg-temporary-dtors"] =
248  Context.getOptions().AnalyzeTemporaryDtors ? "true" : "false";
249 
250  GlobList &Filter = Context.getChecksFilter();
251  AnalyzerOptions->CheckersControlList = getCheckersControlList(Filter);
252  if (!AnalyzerOptions->CheckersControlList.empty()) {
253  setStaticAnalyzerCheckerOpts(Context.getOptions(), AnalyzerOptions);
254  AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
255  AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
256  AnalyzerOptions->AnalyzeNestedBlocks = true;
257  AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
258  std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
259  ento::CreateAnalysisConsumer(Compiler);
260  AnalysisConsumer->AddDiagnosticConsumer(
261  new AnalyzerDiagnosticConsumer(Context));
262  Consumers.push_back(std::move(AnalysisConsumer));
263  }
264  return llvm::make_unique<ClangTidyASTConsumer>(
265  std::move(Consumers), std::move(Finder), std::move(Checks));
266 }
267 
268 std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
269  std::vector<std::string> CheckNames;
270  GlobList &Filter = Context.getChecksFilter();
271  for (const auto &CheckFactory : *CheckFactories) {
272  if (Filter.contains(CheckFactory.first))
273  CheckNames.push_back(CheckFactory.first);
274  }
275 
276  for (const auto &AnalyzerCheck : getCheckersControlList(Filter))
277  CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
278 
279  std::sort(CheckNames.begin(), CheckNames.end());
280  return CheckNames;
281 }
282 
285  std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
286  CheckFactories->createChecks(&Context, Checks);
287  for (const auto &Check : Checks)
288  Check->storeOptions(Options);
289  return Options;
290 }
291 
292 ClangTidyASTConsumerFactory::CheckersList
293 ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
294  CheckersList List;
295 
296  bool AnalyzerChecksEnabled = false;
297  for (StringRef CheckName : StaticAnalyzerChecks) {
298  std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
299  AnalyzerChecksEnabled =
300  AnalyzerChecksEnabled ||
301  (!CheckName.startswith("debug") && Filter.contains(Checker));
302  }
303 
304  if (AnalyzerChecksEnabled) {
305  // Run our regex against all possible static analyzer checkers. Note that
306  // debug checkers print values / run programs to visualize the CFG and are
307  // thus not applicable to clang-tidy in general.
308  //
309  // Always add all core checkers if any other static analyzer checks are
310  // enabled. This is currently necessary, as other path sensitive checks
311  // rely on the core checkers.
312  for (StringRef CheckName : StaticAnalyzerChecks) {
313  std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
314 
315  if (CheckName.startswith("core") ||
316  (!CheckName.startswith("debug") && Filter.contains(Checker)))
317  List.push_back(std::make_pair(CheckName, true));
318  }
319  }
320  return List;
321 }
322 
323 DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
324  DiagnosticIDs::Level Level) {
325  return Context->diag(CheckName, Loc, Message, Level);
326 }
327 
328 void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
329  Context->setSourceManager(Result.SourceManager);
330  check(Result);
331 }
332 
333 OptionsView::OptionsView(StringRef CheckName,
334  const ClangTidyOptions::OptionMap &CheckOptions)
335  : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
336 
337 std::string OptionsView::get(StringRef LocalName, std::string Default) const {
338  const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
339  if (Iter != CheckOptions.end())
340  return Iter->second;
341  return Default;
342 }
343 
345  StringRef LocalName, StringRef Value) const {
346  Options[NamePrefix + LocalName.str()] = Value;
347 }
348 
350  StringRef LocalName, int64_t Value) const {
351  store(Options, LocalName, llvm::itostr(Value));
352 }
353 
354 std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
356  llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
357  Options));
358  ClangTidyASTConsumerFactory Factory(Context);
359  return Factory.getCheckNames();
360 }
361 
364  llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
365  Options));
366  ClangTidyASTConsumerFactory Factory(Context);
367  return Factory.getCheckOptions();
368 }
369 
370 ClangTidyStats
371 runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
372  const tooling::CompilationDatabase &Compilations,
373  ArrayRef<std::string> InputFiles,
374  std::vector<ClangTidyError> *Errors, ProfileData *Profile) {
375  ClangTool Tool(Compilations, InputFiles);
376  clang::tidy::ClangTidyContext Context(std::move(OptionsProvider));
377  ArgumentsAdjuster PerFileExtraArgumentsInserter = [&Context](
378  const CommandLineArguments &Args, StringRef Filename) {
380  CommandLineArguments AdjustedArgs;
381  if (Opts.ExtraArgsBefore)
382  AdjustedArgs = *Opts.ExtraArgsBefore;
383  AdjustedArgs.insert(AdjustedArgs.begin(), Args.begin(), Args.end());
384  if (Opts.ExtraArgs)
385  AdjustedArgs.insert(AdjustedArgs.end(), Opts.ExtraArgs->begin(),
386  Opts.ExtraArgs->end());
387  return AdjustedArgs;
388  };
389  Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter);
390  if (Profile)
391  Context.setCheckProfileData(Profile);
392 
393  ClangTidyDiagnosticConsumer DiagConsumer(Context);
394 
395  Tool.setDiagnosticConsumer(&DiagConsumer);
396 
397  class ActionFactory : public FrontendActionFactory {
398  public:
399  ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
400  FrontendAction *create() override { return new Action(&ConsumerFactory); }
401 
402  private:
403  class Action : public ASTFrontendAction {
404  public:
405  Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
406  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
407  StringRef File) override {
408  return Factory->CreateASTConsumer(Compiler, File);
409  }
410 
411  private:
413  };
414 
415  ClangTidyASTConsumerFactory ConsumerFactory;
416  };
417 
418  ActionFactory Factory(Context);
419  Tool.run(&Factory);
420  *Errors = Context.getErrors();
421  return Context.getStats();
422 }
423 
424 void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix) {
425  ErrorReporter Reporter(Fix);
426  for (const ClangTidyError &Error : Errors)
427  Reporter.reportDiagnostic(Error);
428  Reporter.Finish();
429 }
430 
431 void exportReplacements(const std::vector<ClangTidyError> &Errors,
432  raw_ostream &OS) {
433  tooling::TranslationUnitReplacements TUR;
434  for (const ClangTidyError &Error : Errors)
435  TUR.Replacements.insert(TUR.Replacements.end(), Error.Fix.begin(),
436  Error.Fix.end());
437 
438  yaml::Output YAML(OS);
439  YAML << TUR;
440 }
441 
442 } // namespace tidy
443 } // namespace clang
SourceLocation Loc
'#' location in the include directive
std::vector< std::string > getCheckNames()
Get the list of enabled checks.
Definition: ClangTidy.cpp:268
SetLongJmpCheck & Check
llvm::Optional< ArgList > ExtraArgs
Add extra compilation arguments to the end of the list.
LangOptions LangOpts
Definition: ClangTidy.cpp:168
std::string get(StringRef LocalName, std::string Default) const
Read a named option from the Context.
Definition: ClangTidy.cpp:337
Read-only set of strings represented as a list of positive and negative globs.
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
ClangTidyOptions::OptionMap getCheckOptions()
Get the union of options from all checks.
Definition: ClangTidy.cpp:283
std::vector< std::unique_ptr< ClangTidyCheck > > Checks
Definition: ClangTidy.cpp:189
HeaderHandle File
bool contains(StringRef S)
Returns true if the pattern matches S.
Rewriter Rewrite
Definition: ClangTidy.cpp:173
ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options)
Returns the effective check-specific options.
Definition: ClangTidy.cpp:362
Contains options for clang-tidy.
unsigned AppliedFixes
Definition: ClangTidy.cpp:176
A collection of ClangTidyCheckFactory instances.
const std::vector< ClangTidyError > & getErrors() const
Returns all collected errors.
OptionMap CheckOptions
Key-value mapping used to store check-specific options.
SourceManager SourceMgr
Definition: ClangTidy.cpp:172
llvm::Optional< ArgList > ExtraArgsBefore
Add extra compilation arguments to the start of the list.
ClangTidyOptions getOptionsForFile(StringRef File) const
Returns options for File.
void exportReplacements(const std::vector< ClangTidyError > &Errors, raw_ostream &OS)
Serializes replacements into YAML and writes them to the specified output stream. ...
Definition: ClangTidy.cpp:431
void handleErrors(const std::vector< ClangTidyError > &Errors, bool Fix)
Displays the found Errors to the users.
Definition: ClangTidy.cpp:424
void setCurrentFile(StringRef File)
Should be called when starting to process new translation unit.
const ClangTidyOptions & getOptions() const
Returns options for CurrentFile.
std::string Filename
Filename as a string.
DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors detected using this method.
void setCheckProfileData(ProfileData *Profile)
Set the output struct for profile data.
void setASTContext(ASTContext *Context)
Sets ASTContext for the current translation unit.
A diagnostic consumer that turns each Diagnostic into a SourceManager-independent ClangTidyError...
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Definition: ClangTidy.cpp:344
std::map< std::string, std::string > OptionMap
std::vector< std::string > getCheckNames(const ClangTidyOptions &Options)
Fills the list of check names that are enabled when the provided filters are applied.
Definition: ClangTidy.cpp:354
ClangTidyStats runClangTidy(std::unique_ptr< ClangTidyOptionsProvider > OptionsProvider, const tooling::CompilationDatabase &Compilations, ArrayRef< std::string > InputFiles, std::vector< ClangTidyError > *Errors, ProfileData *Profile)
Run a set of clang-tidy checks on a set of files.
Definition: ClangTidy.cpp:371
static void setStaticAnalyzerCheckerOpts(const ClangTidyOptions &Opts, AnalyzerOptionsRef AnalyzerOptions)
Definition: ClangTidy.cpp:205
void setSourceManager(SourceManager *SourceMgr)
Sets the SourceManager of the used DiagnosticsEngine.
OptionsView(StringRef CheckName, const ClangTidyOptions::OptionMap &CheckOptions)
Initializes the instance using CheckName + "." as a prefix.
Definition: ClangTidy.cpp:333
llvm::Optional< bool > AnalyzeTemporaryDtors
Turns on temporary destructor-based analysis.
const ClangTidyStats & getStats() const
Returns ClangTidyStats containing issued and ignored diagnostic counters.
bool ApplyFixes
Definition: ClangTidy.cpp:174
A detected error complete with information to display diagnostic and automatic fix.
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
Definition: ClangTidy.cpp:169
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(clang::CompilerInstance &Compiler, StringRef File)
Returns an ASTConsumer that runs the specified clang-tidy checks.
Definition: ClangTidy.cpp:217
FileManager Files
Definition: ClangTidy.cpp:167
static cl::opt< bool > Fix("fix", cl::desc("Apply suggested fixes. Without -fix-errors\n""clang-tidy will bail out if any compilation\n""errors were found."), cl::init(false), cl::cat(ClangTidyCategory))
virtual void check(const ast_matchers::MatchFinder::MatchResult &Result)
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: ClangTidy.h:138
GlobList & getChecksFilter()
Returns check filter for the CurrentFile.
DiagnosticsEngine Diags
Definition: ClangTidy.cpp:171
unsigned TotalFixes
Definition: ClangTidy.cpp:175
Container for clang-tidy profiling data.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidy.cpp:323
const NamedDecl * Result
Definition: USRFinder.cpp:121
DiagnosticConsumer * DiagPrinter
Definition: ClangTidy.cpp:170