clang-tools  3.9.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  bool IsWarningAsError,
120  StringRef BuildDirectory)
121  : CheckName(CheckName), BuildDirectory(BuildDirectory), DiagLevel(DiagLevel),
122  IsWarningAsError(IsWarningAsError) {}
123 
124 // Returns true if GlobList starts with the negative indicator ('-'), removes it
125 // from the GlobList.
126 static bool ConsumeNegativeIndicator(StringRef &GlobList) {
127  if (GlobList.startswith("-")) {
128  GlobList = GlobList.substr(1);
129  return true;
130  }
131  return false;
132 }
133 // Converts first glob from the comma-separated list of globs to Regex and
134 // removes it and the trailing comma from the GlobList.
135 static llvm::Regex ConsumeGlob(StringRef &GlobList) {
136  StringRef Glob = GlobList.substr(0, GlobList.find(',')).trim();
137  GlobList = GlobList.substr(Glob.size() + 1);
138  SmallString<128> RegexText("^");
139  StringRef MetaChars("()^$|*+?.[]\\{}");
140  for (char C : Glob) {
141  if (C == '*')
142  RegexText.push_back('.');
143  else if (MetaChars.find(C) != StringRef::npos)
144  RegexText.push_back('\\');
145  RegexText.push_back(C);
146  }
147  RegexText.push_back('$');
148  return llvm::Regex(RegexText);
149 }
150 
151 GlobList::GlobList(StringRef Globs)
152  : Positive(!ConsumeNegativeIndicator(Globs)), Regex(ConsumeGlob(Globs)),
153  NextGlob(Globs.empty() ? nullptr : new GlobList(Globs)) {}
154 
155 bool GlobList::contains(StringRef S, bool Contains) {
156  if (Regex.match(S))
157  Contains = Positive;
158 
159  if (NextGlob)
160  Contains = NextGlob->contains(S, Contains);
161  return Contains;
162 }
163 
165  std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider)
166  : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)),
167  Profile(nullptr) {
168  // Before the first translation unit we can get errors related to command-line
169  // parsing, use empty string for the file name in this case.
170  setCurrentFile("");
171 }
172 
173 DiagnosticBuilder ClangTidyContext::diag(
174  StringRef CheckName, SourceLocation Loc, StringRef Description,
175  DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
176  assert(Loc.isValid());
177  unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
178  Level, (Description + " [" + CheckName + "]").str());
179  if (CheckNamesByDiagnosticID.count(ID) == 0)
180  CheckNamesByDiagnosticID.insert(std::make_pair(ID, CheckName.str()));
181  return DiagEngine->Report(Loc, ID);
182 }
183 
184 void ClangTidyContext::setDiagnosticsEngine(DiagnosticsEngine *Engine) {
185  DiagEngine = Engine;
186 }
187 
189  DiagEngine->setSourceManager(SourceMgr);
190 }
191 
193  CurrentFile = File;
194  CurrentOptions = getOptionsForFile(CurrentFile);
195  CheckFilter.reset(new GlobList(*getOptions().Checks));
196  WarningAsErrorFilter.reset(new GlobList(*getOptions().WarningsAsErrors));
197 }
198 
200  DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
201  LangOpts = Context->getLangOpts();
202 }
203 
205  return OptionsProvider->getGlobalOptions();
206 }
207 
209  return CurrentOptions;
210 }
211 
213  // Merge options on top of getDefaults() as a safeguard against options with
214  // unset values.
216  OptionsProvider->getOptions(File));
217 }
218 
220 
222  assert(CheckFilter != nullptr);
223  return *CheckFilter;
224 }
225 
227  assert(WarningAsErrorFilter != nullptr);
228  return *WarningAsErrorFilter;
229 }
230 
231 /// \brief Store a \c ClangTidyError.
232 void ClangTidyContext::storeError(const ClangTidyError &Error) {
233  Errors.push_back(Error);
234 }
235 
236 StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const {
237  llvm::DenseMap<unsigned, std::string>::const_iterator I =
238  CheckNamesByDiagnosticID.find(DiagnosticID);
239  if (I != CheckNamesByDiagnosticID.end())
240  return I->second;
241  return "";
242 }
243 
245  : Context(Ctx), LastErrorRelatesToUserCode(false),
246  LastErrorPassesLineFilter(false) {
247  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
248  Diags.reset(new DiagnosticsEngine(
249  IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, this,
250  /*ShouldOwnClient=*/false));
251  Context.setDiagnosticsEngine(Diags.get());
252 }
253 
254 void ClangTidyDiagnosticConsumer::finalizeLastError() {
255  if (!Errors.empty()) {
256  ClangTidyError &Error = Errors.back();
257  if (!Context.getChecksFilter().contains(Error.CheckName) &&
258  Error.DiagLevel != ClangTidyError::Error) {
259  ++Context.Stats.ErrorsIgnoredCheckFilter;
260  Errors.pop_back();
261  } else if (!LastErrorRelatesToUserCode) {
262  ++Context.Stats.ErrorsIgnoredNonUserCode;
263  Errors.pop_back();
264  } else if (!LastErrorPassesLineFilter) {
265  ++Context.Stats.ErrorsIgnoredLineFilter;
266  Errors.pop_back();
267  } else {
268  ++Context.Stats.ErrorsDisplayed;
269  }
270  }
271  LastErrorRelatesToUserCode = false;
272  LastErrorPassesLineFilter = false;
273 }
274 
275 static bool LineIsMarkedWithNOLINT(SourceManager& SM, SourceLocation Loc) {
276  bool Invalid;
277  const char *CharacterData = SM.getCharacterData(Loc, &Invalid);
278  if (!Invalid) {
279  const char *P = CharacterData;
280  while (*P != '\0' && *P != '\r' && *P != '\n')
281  ++P;
282  StringRef RestOfLine(CharacterData, P - CharacterData + 1);
283  // FIXME: Handle /\bNOLINT\b(\([^)]*\))?/ as cpplint.py does.
284  if (RestOfLine.find("NOLINT") != StringRef::npos) {
285  return true;
286  }
287  }
288  return false;
289 }
290 
292  DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
293  if (Info.getLocation().isValid() &&
294  DiagLevel != DiagnosticsEngine::Error &&
295  DiagLevel != DiagnosticsEngine::Fatal &&
296  LineIsMarkedWithNOLINT(Diags->getSourceManager(), Info.getLocation())) {
297  ++Context.Stats.ErrorsIgnoredNOLINT;
298  return;
299  }
300  // Count warnings/errors.
301  DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
302 
303  if (DiagLevel == DiagnosticsEngine::Note) {
304  assert(!Errors.empty() &&
305  "A diagnostic note can only be appended to a message.");
306  } else {
307  finalizeLastError();
308  StringRef WarningOption =
309  Context.DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(
310  Info.getID());
311  std::string CheckName = !WarningOption.empty()
312  ? ("clang-diagnostic-" + WarningOption).str()
313  : Context.getCheckName(Info.getID()).str();
314 
315  if (CheckName.empty()) {
316  // This is a compiler diagnostic without a warning option. Assign check
317  // name based on its level.
318  switch (DiagLevel) {
319  case DiagnosticsEngine::Error:
320  case DiagnosticsEngine::Fatal:
321  CheckName = "clang-diagnostic-error";
322  break;
323  case DiagnosticsEngine::Warning:
324  CheckName = "clang-diagnostic-warning";
325  break;
326  default:
327  CheckName = "clang-diagnostic-unknown";
328  break;
329  }
330  }
331 
333  if (DiagLevel == DiagnosticsEngine::Error ||
334  DiagLevel == DiagnosticsEngine::Fatal) {
335  // Force reporting of Clang errors regardless of filters and non-user
336  // code.
337  Level = ClangTidyError::Error;
338  LastErrorRelatesToUserCode = true;
339  LastErrorPassesLineFilter = true;
340  }
341  bool IsWarningAsError =
342  DiagLevel == DiagnosticsEngine::Warning &&
343  Context.getWarningAsErrorFilter().contains(CheckName);
344  Errors.push_back(ClangTidyError(CheckName, Level, IsWarningAsError,
345  Context.getCurrentBuildDirectory()));
346  }
347 
348  ClangTidyDiagnosticRenderer Converter(
349  Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(),
350  Errors.back());
351  SmallString<100> Message;
352  Info.FormatDiagnostic(Message);
353  SourceManager *Sources = nullptr;
354  if (Info.hasSourceManager())
355  Sources = &Info.getSourceManager();
356  Converter.emitDiagnostic(Info.getLocation(), DiagLevel, Message,
357  Info.getRanges(), Info.getFixItHints(), Sources);
358 
359  checkFilters(Info.getLocation());
360 }
361 
362 bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
363  unsigned LineNumber) const {
364  if (Context.getGlobalOptions().LineFilter.empty())
365  return true;
366  for (const FileFilter &Filter : Context.getGlobalOptions().LineFilter) {
367  if (FileName.endswith(Filter.Name)) {
368  if (Filter.LineRanges.empty())
369  return true;
370  for (const FileFilter::LineRange &Range : Filter.LineRanges) {
371  if (Range.first <= LineNumber && LineNumber <= Range.second)
372  return true;
373  }
374  return false;
375  }
376  }
377  return false;
378 }
379 
380 void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location) {
381  // Invalid location may mean a diagnostic in a command line, don't skip these.
382  if (!Location.isValid()) {
383  LastErrorRelatesToUserCode = true;
384  LastErrorPassesLineFilter = true;
385  return;
386  }
387 
388  const SourceManager &Sources = Diags->getSourceManager();
389  if (!*Context.getOptions().SystemHeaders &&
390  Sources.isInSystemHeader(Location))
391  return;
392 
393  // FIXME: We start with a conservative approach here, but the actual type of
394  // location needed depends on the check (in particular, where this check wants
395  // to apply fixes).
396  FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
397  const FileEntry *File = Sources.getFileEntryForID(FID);
398 
399  // -DMACRO definitions on the command line have locations in a virtual buffer
400  // that doesn't have a FileEntry. Don't skip these as well.
401  if (!File) {
402  LastErrorRelatesToUserCode = true;
403  LastErrorPassesLineFilter = true;
404  return;
405  }
406 
407  StringRef FileName(File->getName());
408  LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
409  Sources.isInMainFile(Location) ||
410  getHeaderFilter()->match(FileName);
411 
412  unsigned LineNumber = Sources.getExpansionLineNumber(Location);
413  LastErrorPassesLineFilter =
414  LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
415 }
416 
417 llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
418  if (!HeaderFilter)
419  HeaderFilter.reset(
420  new llvm::Regex(*Context.getOptions().HeaderFilterRegex));
421  return HeaderFilter.get();
422 }
423 
424 void ClangTidyDiagnosticConsumer::removeIncompatibleErrors(
425  SmallVectorImpl<ClangTidyError> &Errors) const {
426  // Each error is modelled as the set of intervals in which it applies
427  // replacements. To detect overlapping replacements, we use a sweep line
428  // algorithm over these sets of intervals.
429  // An event here consists of the opening or closing of an interval. During the
430  // proccess, we maintain a counter with the amount of open intervals. If we
431  // find an endpoint of an interval and this counter is different from 0, it
432  // means that this interval overlaps with another one, so we set it as
433  // inapplicable.
434  struct Event {
435  // An event can be either the begin or the end of an interval.
436  enum EventType {
437  ET_Begin = 1,
438  ET_End = -1,
439  };
440 
441  Event(unsigned Begin, unsigned End, EventType Type, unsigned ErrorId,
442  unsigned ErrorSize)
443  : Type(Type), ErrorId(ErrorId) {
444  // The events are going to be sorted by their position. In case of draw:
445  //
446  // * If an interval ends at the same position at which other interval
447  // begins, this is not an overlapping, so we want to remove the ending
448  // interval before adding the starting one: end events have higher
449  // priority than begin events.
450  //
451  // * If we have several begin points at the same position, we will mark as
452  // inapplicable the ones that we proccess later, so the first one has to
453  // be the one with the latest end point, because this one will contain
454  // all the other intervals. For the same reason, if we have several end
455  // points in the same position, the last one has to be the one with the
456  // earliest begin point. In both cases, we sort non-increasingly by the
457  // position of the complementary.
458  //
459  // * In case of two equal intervals, the one whose error is bigger can
460  // potentially contain the other one, so we want to proccess its begin
461  // points before and its end points later.
462  //
463  // * Finally, if we have two equal intervals whose errors have the same
464  // size, none of them will be strictly contained inside the other.
465  // Sorting by ErrorId will guarantee that the begin point of the first
466  // one will be proccessed before, disallowing the second one, and the
467  // end point of the first one will also be proccessed before,
468  // disallowing the first one.
469  if (Type == ET_Begin)
470  Priority = std::make_tuple(Begin, Type, -End, -ErrorSize, ErrorId);
471  else
472  Priority = std::make_tuple(End, Type, -Begin, ErrorSize, ErrorId);
473  }
474 
475  bool operator<(const Event &Other) const {
476  return Priority < Other.Priority;
477  }
478 
479  // Determines if this event is the begin or the end of an interval.
480  EventType Type;
481  // The index of the error to which the interval that generated this event
482  // belongs.
483  unsigned ErrorId;
484  // The events will be sorted based on this field.
485  std::tuple<unsigned, EventType, int, int, unsigned> Priority;
486  };
487 
488  // Compute error sizes.
489  std::vector<int> Sizes;
490  for (const auto &Error : Errors) {
491  int Size = 0;
492  for (const auto &Replace : Error.Fix)
493  Size += Replace.getLength();
494  Sizes.push_back(Size);
495  }
496 
497  // Build events from error intervals.
498  std::map<std::string, std::vector<Event>> FileEvents;
499  for (unsigned I = 0; I < Errors.size(); ++I) {
500  for (const auto &Replace : Errors[I].Fix) {
501  unsigned Begin = Replace.getOffset();
502  unsigned End = Begin + Replace.getLength();
503  const std::string &FilePath = Replace.getFilePath();
504  // FIXME: Handle empty intervals, such as those from insertions.
505  if (Begin == End)
506  continue;
507  FileEvents[FilePath].push_back(
508  Event(Begin, End, Event::ET_Begin, I, Sizes[I]));
509  FileEvents[FilePath].push_back(
510  Event(Begin, End, Event::ET_End, I, Sizes[I]));
511  }
512  }
513 
514  std::vector<bool> Apply(Errors.size(), true);
515  for (auto &FileAndEvents : FileEvents) {
516  std::vector<Event> &Events = FileAndEvents.second;
517  // Sweep.
518  std::sort(Events.begin(), Events.end());
519  int OpenIntervals = 0;
520  for (const auto &Event : Events) {
521  if (Event.Type == Event::ET_End)
522  --OpenIntervals;
523  // This has to be checked after removing the interval from the count if it
524  // is an end event, or before adding it if it is a begin event.
525  if (OpenIntervals != 0)
526  Apply[Event.ErrorId] = false;
527  if (Event.Type == Event::ET_Begin)
528  ++OpenIntervals;
529  }
530  assert(OpenIntervals == 0 && "Amount of begin/end points doesn't match");
531  }
532 
533  for (unsigned I = 0; I < Errors.size(); ++I) {
534  if (!Apply[I]) {
535  Errors[I].Fix.clear();
536  Errors[I].Notes.push_back(
537  ClangTidyMessage("this fix will not be applied because"
538  " it overlaps with another fix"));
539  }
540  }
541 }
542 
543 namespace {
544 struct LessClangTidyError {
545  bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const {
546  const ClangTidyMessage &M1 = LHS.Message;
547  const ClangTidyMessage &M2 = RHS.Message;
548 
549  return std::tie(M1.FilePath, M1.FileOffset, M1.Message) <
550  std::tie(M2.FilePath, M2.FileOffset, M2.Message);
551  }
552 };
553 struct EqualClangTidyError {
554  bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const {
555  LessClangTidyError Less;
556  return !Less(LHS, RHS) && !Less(RHS, LHS);
557  }
558 };
559 } // end anonymous namespace
560 
561 // Flushes the internal diagnostics buffer to the ClangTidyContext.
563  finalizeLastError();
564 
565  std::sort(Errors.begin(), Errors.end(), LessClangTidyError());
566  Errors.erase(std::unique(Errors.begin(), Errors.end(), EqualClangTidyError()),
567  Errors.end());
568  removeIncompatibleErrors(Errors);
569 
570  for (const ClangTidyError &Error : Errors)
571  Context.storeError(Error);
572  Errors.clear();
573 }
SourceLocation Loc
'#' location in the include directive
LangOptions LangOpts
Definition: ClangTidy.cpp:189
ClangTidyError(StringRef CheckName, Level DiagLevel, bool IsWarningAsError, StringRef BuildDirectory)
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:211
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:193
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...
GlobList & getWarningAsErrorFilter()
Returns check filter for the CurrentFile which selects checks for upgrade to error.
unsigned WarningsAsErrors
Definition: ClangTidy.cpp:198
const ClangTidyGlobalOptions & getGlobalOptions() const
Returns global options.
const LangOptions & getLangOpts() const
Gets the language options from the AST context.
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:190
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
static bool LineIsMarkedWithNOLINT(SourceManager &SM, SourceLocation Loc)
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(R"( Apply suggested fixes. Without -fix-errors clang-tidy will bail out if any compilation errors were found. )"), cl::init(false), cl::cat(ClangTidyCategory))
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
GlobList & getChecksFilter()
Returns check filter for the CurrentFile.
Container for clang-tidy profiling data.
const std::string & getCurrentBuildDirectory()
Returns build directory of the current translation unit.