clang-tools  3.8.0
ClangTidyDiagnosticConsumer.cpp
Go to the documentation of this file.
1 //===--- tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp ----------=== //
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 ClangTidyDiagnosticConsumer, ClangTidyMessage,
11 /// ClangTidyContext and ClangTidyError classes.
12 ///
13 /// This tool uses the Clang Tooling infrastructure, see
14 /// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
15 /// for details on setting it up with LLVM source tree.
16 ///
17 //===----------------------------------------------------------------------===//
18 
20 #include "ClangTidyOptions.h"
21 #include "clang/AST/ASTDiagnostic.h"
22 #include "clang/Basic/DiagnosticOptions.h"
23 #include "clang/Frontend/DiagnosticRenderer.h"
24 #include "llvm/ADT/SmallString.h"
25 #include <tuple>
26 #include <vector>
27 using namespace clang;
28 using namespace tidy;
29 
30 namespace {
31 class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
32 public:
33  ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
34  DiagnosticOptions *DiagOpts,
35  ClangTidyError &Error)
36  : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
37 
38 protected:
39  void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
40  DiagnosticsEngine::Level Level, StringRef Message,
41  ArrayRef<CharSourceRange> Ranges,
42  const SourceManager *SM,
43  DiagOrStoredDiag Info) override {
44  // Remove check name from the message.
45  // FIXME: Remove this once there's a better way to pass check names than
46  // appending the check name to the message in ClangTidyContext::diag and
47  // using getCustomDiagID.
48  std::string CheckNameInMessage = " [" + Error.CheckName + "]";
49  if (Message.endswith(CheckNameInMessage))
50  Message = Message.substr(0, Message.size() - CheckNameInMessage.size());
51 
52  ClangTidyMessage TidyMessage = Loc.isValid()
53  ? ClangTidyMessage(Message, *SM, Loc)
54  : ClangTidyMessage(Message);
55  if (Level == DiagnosticsEngine::Note) {
56  Error.Notes.push_back(TidyMessage);
57  return;
58  }
59  assert(Error.Message.Message.empty() && "Overwriting a diagnostic message");
60  Error.Message = TidyMessage;
61  }
62 
63  void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
64  DiagnosticsEngine::Level Level,
65  ArrayRef<CharSourceRange> Ranges,
66  const SourceManager &SM) override {}
67 
68  void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level,
69  SmallVectorImpl<CharSourceRange> &Ranges,
70  ArrayRef<FixItHint> Hints,
71  const SourceManager &SM) override {
72  assert(Loc.isValid());
73  for (const auto &FixIt : Hints) {
74  CharSourceRange Range = FixIt.RemoveRange;
75  assert(Range.getBegin().isValid() && Range.getEnd().isValid() &&
76  "Invalid range in the fix-it hint.");
77  assert(Range.getBegin().isFileID() && Range.getEnd().isFileID() &&
78  "Only file locations supported in fix-it hints.");
79 
80  Error.Fix.insert(tooling::Replacement(SM, Range, FixIt.CodeToInsert));
81  }
82  }
83 
84  void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
85  const SourceManager &SM) override {}
86 
87  void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
88  StringRef ModuleName,
89  const SourceManager &SM) override {}
90 
91  void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
92  StringRef ModuleName,
93  const SourceManager &SM) override {}
94 
95  void endDiagnostic(DiagOrStoredDiag D,
96  DiagnosticsEngine::Level Level) override {
97  assert(!Error.Message.Message.empty() && "Message has not been set");
98  }
99 
100 private:
101  ClangTidyError &Error;
102 };
103 } // end anonymous namespace
104 
106  : Message(Message), FileOffset(0) {}
107 
109  const SourceManager &Sources,
110  SourceLocation Loc)
111  : Message(Message) {
112  assert(Loc.isValid() && Loc.isFileID());
113  FilePath = Sources.getFilename(Loc);
114  FileOffset = Sources.getFileOffset(Loc);
115 }
116 
117 ClangTidyError::ClangTidyError(StringRef CheckName,
118  ClangTidyError::Level DiagLevel)
119  : CheckName(CheckName), DiagLevel(DiagLevel) {}
120 
121 // Returns true if GlobList starts with the negative indicator ('-'), removes it
122 // from the GlobList.
123 static bool ConsumeNegativeIndicator(StringRef &GlobList) {
124  if (GlobList.startswith("-")) {
125  GlobList = GlobList.substr(1);
126  return true;
127  }
128  return false;
129 }
130 // Converts first glob from the comma-separated list of globs to Regex and
131 // removes it and the trailing comma from the GlobList.
132 static llvm::Regex ConsumeGlob(StringRef &GlobList) {
133  StringRef Glob = GlobList.substr(0, GlobList.find(',')).trim();
134  GlobList = GlobList.substr(Glob.size() + 1);
135  SmallString<128> RegexText("^");
136  StringRef MetaChars("()^$|*+?.[]\\{}");
137  for (char C : Glob) {
138  if (C == '*')
139  RegexText.push_back('.');
140  else if (MetaChars.find(C) != StringRef::npos)
141  RegexText.push_back('\\');
142  RegexText.push_back(C);
143  }
144  RegexText.push_back('$');
145  return llvm::Regex(RegexText);
146 }
147 
148 GlobList::GlobList(StringRef Globs)
149  : Positive(!ConsumeNegativeIndicator(Globs)), Regex(ConsumeGlob(Globs)),
150  NextGlob(Globs.empty() ? nullptr : new GlobList(Globs)) {}
151 
152 bool GlobList::contains(StringRef S, bool Contains) {
153  if (Regex.match(S))
154  Contains = Positive;
155 
156  if (NextGlob)
157  Contains = NextGlob->contains(S, Contains);
158  return Contains;
159 }
160 
162  std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider)
163  : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)),
164  Profile(nullptr) {
165  // Before the first translation unit we can get errors related to command-line
166  // parsing, use empty string for the file name in this case.
167  setCurrentFile("");
168 }
169 
170 DiagnosticBuilder ClangTidyContext::diag(
171  StringRef CheckName, SourceLocation Loc, StringRef Description,
172  DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
173  assert(Loc.isValid());
174  bool Invalid;
175  const char *CharacterData =
176  DiagEngine->getSourceManager().getCharacterData(Loc, &Invalid);
177  if (!Invalid) {
178  const char *P = CharacterData;
179  while (*P != '\0' && *P != '\r' && *P != '\n')
180  ++P;
181  StringRef RestOfLine(CharacterData, P - CharacterData + 1);
182  // FIXME: Handle /\bNOLINT\b(\([^)]*\))?/ as cpplint.py does.
183  if (RestOfLine.find("NOLINT") != StringRef::npos) {
184  Level = DiagnosticIDs::Ignored;
185  ++Stats.ErrorsIgnoredNOLINT;
186  }
187  }
188  unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
189  Level, (Description + " [" + CheckName + "]").str());
190  if (CheckNamesByDiagnosticID.count(ID) == 0)
191  CheckNamesByDiagnosticID.insert(std::make_pair(ID, CheckName.str()));
192  return DiagEngine->Report(Loc, ID);
193 }
194 
195 void ClangTidyContext::setDiagnosticsEngine(DiagnosticsEngine *Engine) {
196  DiagEngine = Engine;
197 }
198 
200  DiagEngine->setSourceManager(SourceMgr);
201 }
202 
204  CurrentFile = File;
205  CurrentOptions = getOptionsForFile(CurrentFile);
206  CheckFilter.reset(new GlobList(*getOptions().Checks));
207 }
208 
210  DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
211  LangOpts = Context->getLangOpts();
212 }
213 
215  return OptionsProvider->getGlobalOptions();
216 }
217 
219  return CurrentOptions;
220 }
221 
223  // Merge options on top of getDefaults() as a safeguard against options with
224  // unset values.
226  OptionsProvider->getOptions(CurrentFile));
227 }
228 
230 
232  assert(CheckFilter != nullptr);
233  return *CheckFilter;
234 }
235 
236 bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const {
237  return CheckFilter->contains(CheckName);
238 }
239 
240 /// \brief Store a \c ClangTidyError.
241 void ClangTidyContext::storeError(const ClangTidyError &Error) {
242  Errors.push_back(Error);
243 }
244 
245 StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const {
246  llvm::DenseMap<unsigned, std::string>::const_iterator I =
247  CheckNamesByDiagnosticID.find(DiagnosticID);
248  if (I != CheckNamesByDiagnosticID.end())
249  return I->second;
250  return "";
251 }
252 
254  : Context(Ctx), LastErrorRelatesToUserCode(false),
255  LastErrorPassesLineFilter(false) {
256  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
257  Diags.reset(new DiagnosticsEngine(
258  IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, this,
259  /*ShouldOwnClient=*/false));
260  Context.setDiagnosticsEngine(Diags.get());
261 }
262 
263 void ClangTidyDiagnosticConsumer::finalizeLastError() {
264  if (!Errors.empty()) {
265  ClangTidyError &Error = Errors.back();
266  if (!Context.getChecksFilter().contains(Error.CheckName) &&
267  Error.DiagLevel != ClangTidyError::Error) {
268  ++Context.Stats.ErrorsIgnoredCheckFilter;
269  Errors.pop_back();
270  } else if (!LastErrorRelatesToUserCode) {
271  ++Context.Stats.ErrorsIgnoredNonUserCode;
272  Errors.pop_back();
273  } else if (!LastErrorPassesLineFilter) {
274  ++Context.Stats.ErrorsIgnoredLineFilter;
275  Errors.pop_back();
276  } else {
277  ++Context.Stats.ErrorsDisplayed;
278  }
279  }
280  LastErrorRelatesToUserCode = false;
281  LastErrorPassesLineFilter = false;
282 }
283 
285  DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
286  // Count warnings/errors.
287  DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
288 
289  if (DiagLevel == DiagnosticsEngine::Note) {
290  assert(!Errors.empty() &&
291  "A diagnostic note can only be appended to a message.");
292  } else {
293  finalizeLastError();
294  StringRef WarningOption =
295  Context.DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(
296  Info.getID());
297  std::string CheckName = !WarningOption.empty()
298  ? ("clang-diagnostic-" + WarningOption).str()
299  : Context.getCheckName(Info.getID()).str();
300 
301  if (CheckName.empty()) {
302  // This is a compiler diagnostic without a warning option. Assign check
303  // name based on its level.
304  switch (DiagLevel) {
305  case DiagnosticsEngine::Error:
306  case DiagnosticsEngine::Fatal:
307  CheckName = "clang-diagnostic-error";
308  break;
309  case DiagnosticsEngine::Warning:
310  CheckName = "clang-diagnostic-warning";
311  break;
312  default:
313  CheckName = "clang-diagnostic-unknown";
314  break;
315  }
316  }
317 
319  if (DiagLevel == DiagnosticsEngine::Error ||
320  DiagLevel == DiagnosticsEngine::Fatal) {
321  // Force reporting of Clang errors regardless of filters and non-user
322  // code.
323  Level = ClangTidyError::Error;
324  LastErrorRelatesToUserCode = true;
325  LastErrorPassesLineFilter = true;
326  }
327  Errors.push_back(ClangTidyError(CheckName, Level));
328  }
329 
330  // FIXME: Provide correct LangOptions for each file.
331  LangOptions LangOpts;
332  ClangTidyDiagnosticRenderer Converter(
333  LangOpts, &Context.DiagEngine->getDiagnosticOptions(), Errors.back());
334  SmallString<100> Message;
335  Info.FormatDiagnostic(Message);
336  SourceManager *Sources = nullptr;
337  if (Info.hasSourceManager())
338  Sources = &Info.getSourceManager();
339  Converter.emitDiagnostic(Info.getLocation(), DiagLevel, Message,
340  Info.getRanges(), Info.getFixItHints(), Sources);
341 
342  checkFilters(Info.getLocation());
343 }
344 
345 bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
346  unsigned LineNumber) const {
347  if (Context.getGlobalOptions().LineFilter.empty())
348  return true;
349  for (const FileFilter &Filter : Context.getGlobalOptions().LineFilter) {
350  if (FileName.endswith(Filter.Name)) {
351  if (Filter.LineRanges.empty())
352  return true;
353  for (const FileFilter::LineRange &Range : Filter.LineRanges) {
354  if (Range.first <= LineNumber && LineNumber <= Range.second)
355  return true;
356  }
357  return false;
358  }
359  }
360  return false;
361 }
362 
363 void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location) {
364  // Invalid location may mean a diagnostic in a command line, don't skip these.
365  if (!Location.isValid()) {
366  LastErrorRelatesToUserCode = true;
367  LastErrorPassesLineFilter = true;
368  return;
369  }
370 
371  const SourceManager &Sources = Diags->getSourceManager();
372  if (!*Context.getOptions().SystemHeaders &&
373  Sources.isInSystemHeader(Location))
374  return;
375 
376  // FIXME: We start with a conservative approach here, but the actual type of
377  // location needed depends on the check (in particular, where this check wants
378  // to apply fixes).
379  FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
380  const FileEntry *File = Sources.getFileEntryForID(FID);
381 
382  // -DMACRO definitions on the command line have locations in a virtual buffer
383  // that doesn't have a FileEntry. Don't skip these as well.
384  if (!File) {
385  LastErrorRelatesToUserCode = true;
386  LastErrorPassesLineFilter = true;
387  return;
388  }
389 
390  StringRef FileName(File->getName());
391  LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
392  Sources.isInMainFile(Location) ||
393  getHeaderFilter()->match(FileName);
394 
395  unsigned LineNumber = Sources.getExpansionLineNumber(Location);
396  LastErrorPassesLineFilter =
397  LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
398 }
399 
400 llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
401  if (!HeaderFilter)
402  HeaderFilter.reset(
403  new llvm::Regex(*Context.getOptions().HeaderFilterRegex));
404  return HeaderFilter.get();
405 }
406 
407 void ClangTidyDiagnosticConsumer::removeIncompatibleErrors(
408  SmallVectorImpl<ClangTidyError> &Errors) const {
409  // Each error is modelled as the set of intervals in which it applies
410  // replacements. To detect overlapping replacements, we use a sweep line
411  // algorithm over these sets of intervals.
412  // An event here consists of the opening or closing of an interval. During the
413  // proccess, we maintain a counter with the amount of open intervals. If we
414  // find an endpoint of an interval and this counter is different from 0, it
415  // means that this interval overlaps with another one, so we set it as
416  // inapplicable.
417  struct Event {
418  // An event can be either the begin or the end of an interval.
419  enum EventType {
420  ET_Begin = 1,
421  ET_End = -1,
422  };
423 
424  Event(unsigned Begin, unsigned End, EventType Type, unsigned ErrorId,
425  unsigned ErrorSize)
426  : Type(Type), ErrorId(ErrorId) {
427  // The events are going to be sorted by their position. In case of draw:
428  //
429  // * If an interval ends at the same position at which other interval
430  // begins, this is not an overlapping, so we want to remove the ending
431  // interval before adding the starting one: end events have higher
432  // priority than begin events.
433  //
434  // * If we have several begin points at the same position, we will mark as
435  // inapplicable the ones that we proccess later, so the first one has to
436  // be the one with the latest end point, because this one will contain
437  // all the other intervals. For the same reason, if we have several end
438  // points in the same position, the last one has to be the one with the
439  // earliest begin point. In both cases, we sort non-increasingly by the
440  // position of the complementary.
441  //
442  // * In case of two equal intervals, the one whose error is bigger can
443  // potentially contain the other one, so we want to proccess its begin
444  // points before and its end points later.
445  //
446  // * Finally, if we have two equal intervals whose errors have the same
447  // size, none of them will be strictly contained inside the other.
448  // Sorting by ErrorId will guarantee that the begin point of the first
449  // one will be proccessed before, disallowing the second one, and the
450  // end point of the first one will also be proccessed before,
451  // disallowing the first one.
452  if (Type == ET_Begin)
453  Priority = std::make_tuple(Begin, Type, -End, -ErrorSize, ErrorId);
454  else
455  Priority = std::make_tuple(End, Type, -Begin, ErrorSize, ErrorId);
456  }
457 
458  bool operator<(const Event &Other) const {
459  return Priority < Other.Priority;
460  }
461 
462  // Determines if this event is the begin or the end of an interval.
463  EventType Type;
464  // The index of the error to which the interval that generated this event
465  // belongs.
466  unsigned ErrorId;
467  // The events will be sorted based on this field.
468  std::tuple<unsigned, EventType, int, int, unsigned> Priority;
469  };
470 
471  // Compute error sizes.
472  std::vector<int> Sizes;
473  for (const auto &Error : Errors) {
474  int Size = 0;
475  for (const auto &Replace : Error.Fix)
476  Size += Replace.getLength();
477  Sizes.push_back(Size);
478  }
479 
480  // Build events from error intervals.
481  std::map<std::string, std::vector<Event>> FileEvents;
482  for (unsigned I = 0; I < Errors.size(); ++I) {
483  for (const auto &Replace : Errors[I].Fix) {
484  unsigned Begin = Replace.getOffset();
485  unsigned End = Begin + Replace.getLength();
486  const std::string &FilePath = Replace.getFilePath();
487  // FIXME: Handle empty intervals, such as those from insertions.
488  if (Begin == End)
489  continue;
490  FileEvents[FilePath].push_back(
491  Event(Begin, End, Event::ET_Begin, I, Sizes[I]));
492  FileEvents[FilePath].push_back(
493  Event(Begin, End, Event::ET_End, I, Sizes[I]));
494  }
495  }
496 
497  std::vector<bool> Apply(Errors.size(), true);
498  for (auto &FileAndEvents : FileEvents) {
499  std::vector<Event> &Events = FileAndEvents.second;
500  // Sweep.
501  std::sort(Events.begin(), Events.end());
502  int OpenIntervals = 0;
503  for (const auto &Event : Events) {
504  if (Event.Type == Event::ET_End)
505  --OpenIntervals;
506  // This has to be checked after removing the interval from the count if it
507  // is an end event, or before adding it if it is a begin event.
508  if (OpenIntervals != 0)
509  Apply[Event.ErrorId] = false;
510  if (Event.Type == Event::ET_Begin)
511  ++OpenIntervals;
512  }
513  assert(OpenIntervals == 0 && "Amount of begin/end points doesn't match");
514  }
515 
516  for (unsigned I = 0; I < Errors.size(); ++I) {
517  if (!Apply[I]) {
518  Errors[I].Fix.clear();
519  Errors[I].Notes.push_back(
520  ClangTidyMessage("this fix will not be applied because"
521  " it overlaps with another fix"));
522  }
523  }
524 }
525 
526 namespace {
527 struct LessClangTidyError {
528  bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const {
529  const ClangTidyMessage &M1 = LHS.Message;
530  const ClangTidyMessage &M2 = RHS.Message;
531 
532  return std::tie(M1.FilePath, M1.FileOffset, M1.Message) <
533  std::tie(M2.FilePath, M2.FileOffset, M2.Message);
534  }
535 };
536 struct EqualClangTidyError {
537  bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const {
538  LessClangTidyError Less;
539  return !Less(LHS, RHS) && !Less(RHS, LHS);
540  }
541 };
542 } // end anonymous namespace
543 
544 // Flushes the internal diagnostics buffer to the ClangTidyContext.
546  finalizeLastError();
547 
548  std::sort(Errors.begin(), Errors.end(), LessClangTidyError());
549  Errors.erase(std::unique(Errors.begin(), Errors.end(), EqualClangTidyError()),
550  Errors.end());
551  removeIncompatibleErrors(Errors);
552 
553  for (const ClangTidyError &Error : Errors)
554  Context.storeError(Error);
555  Errors.clear();
556 }
SourceLocation Loc
'#' location in the include directive
LangOptions LangOpts
Definition: ClangTidy.cpp:168
Read-only set of strings represented as a list of positive and negative globs.
GlobList(StringRef Globs)
GlobList is a comma-separated list of globs (only '*' metacharacter is supported) with optional '-' p...
std::vector< std::unique_ptr< ClangTidyCheck > > Checks
Definition: ClangTidy.cpp:189
HeaderHandle File
void finish() override
Flushes the internal diagnostics buffer to the ClangTidyContext.
bool contains(StringRef S)
Returns true if the pattern matches S.
A message from a clang-tidy check.
llvm::Optional< std::string > HeaderFilterRegex
Output warnings from headers matching this filter.
Contains options for clang-tidy.
static bool ConsumeNegativeIndicator(StringRef &GlobList)
llvm::Optional< bool > SystemHeaders
Output warnings from system headers matching HeaderFilterRegex.
SourceManager SourceMgr
Definition: ClangTidy.cpp:172
ClangTidyOptions getOptionsForFile(StringRef File) const
Returns options for File.
SourceManager & SM
std::pair< unsigned, unsigned > LineRange
LineRange is a pair<start, end> (inclusive).
void setCurrentFile(StringRef File)
Should be called when starting to process new translation unit.
const ClangTidyOptions & getOptions() const
Returns options for CurrentFile.
static llvm::Regex ConsumeGlob(StringRef &GlobList)
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.
ClangTidyContext(std::unique_ptr< ClangTidyOptionsProvider > OptionsProvider)
Initializes ClangTidyContext instance.
void setASTContext(ASTContext *Context)
Sets ASTContext for the current translation unit.
std::vector< FileFilter > LineFilter
Output warnings from certain line ranges of certain files only.
ClangTidyOptions mergeWith(const ClangTidyOptions &Other) const
Creates a new ClangTidyOptions instance combined from all fields of this instance overridden by the f...
ClangTidyError(StringRef CheckName, Level DiagLevel)
const ClangTidyGlobalOptions & getGlobalOptions() const
Returns global options.
void setSourceManager(SourceManager *SourceMgr)
Sets the SourceManager of the used DiagnosticsEngine.
Contains a list of line ranges in a single file.
CharSourceRange Range
SourceRange for the file name.
StringRef getCheckName(unsigned DiagnosticID) const
Returns the name of the clang-tidy check which produced this diagnostic ID.
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.
static ClangTidyOptions getDefaults()
These options are used for all settings that haven't been overridden by the OptionsProvider.
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))
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
bool isCheckEnabled(StringRef CheckName) const
Returns true if the check name is enabled for the CurrentFile.
GlobList & getChecksFilter()
Returns check filter for the CurrentFile.
Container for clang-tidy profiling data.