22#include "clang/AST/ASTContext.h"
23#include "clang/AST/ASTDiagnostic.h"
24#include "clang/AST/Attr.h"
25#include "clang/AST/Expr.h"
26#include "clang/Basic/CharInfo.h"
27#include "clang/Basic/Diagnostic.h"
28#include "clang/Basic/DiagnosticOptions.h"
29#include "clang/Basic/FileManager.h"
30#include "clang/Basic/SourceManager.h"
31#include "clang/Frontend/DiagnosticRenderer.h"
32#include "clang/Lex/Lexer.h"
33#include "clang/Tooling/Core/Diagnostic.h"
34#include "clang/Tooling/Core/Replacement.h"
35#include "llvm/ADT/BitVector.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/StringMap.h"
38#include "llvm/Support/FormatVariadic.h"
39#include "llvm/Support/Regex.h"
48class ClangTidyDiagnosticRenderer :
public DiagnosticRenderer {
50 ClangTidyDiagnosticRenderer(
const LangOptions &LangOpts,
51 DiagnosticOptions &DiagOpts,
52 ClangTidyError &Error)
53 : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
56 void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
57 DiagnosticsEngine::Level Level, StringRef Message,
58 ArrayRef<CharSourceRange> Ranges,
59 DiagOrStoredDiag Info)
override {
64 std::string CheckNameInMessage =
" [" + Error.DiagnosticName +
"]";
65 Message.consume_back(CheckNameInMessage);
69 ? tooling::DiagnosticMessage(Message, Loc.getManager(), Loc)
70 : tooling::DiagnosticMessage(Message);
76 auto ToCharRange = [
this, &Loc](
const CharSourceRange &SourceRange) {
77 if (SourceRange.isCharRange())
79 assert(SourceRange.isTokenRange());
80 SourceLocation End = Lexer::getLocForEndOfToken(
81 SourceRange.getEnd(), 0, Loc.getManager(), LangOpts);
82 return CharSourceRange::getCharRange(SourceRange.getBegin(), End);
87 llvm::make_filter_range(Ranges, [](
const CharSourceRange &R) {
88 return R.getAsRange().isValid();
91 if (Level == DiagnosticsEngine::Note) {
92 Error.Notes.push_back(TidyMessage);
93 for (
const CharSourceRange &SourceRange : ValidRanges)
94 Error.Notes.back().Ranges.emplace_back(Loc.getManager(),
95 ToCharRange(SourceRange));
98 assert(Error.Message.Message.empty() &&
"Overwriting a diagnostic message");
99 Error.Message = TidyMessage;
100 for (
const CharSourceRange &SourceRange : ValidRanges)
101 Error.Message.Ranges.emplace_back(Loc.getManager(),
102 ToCharRange(SourceRange));
105 void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
106 DiagnosticsEngine::Level Level,
107 ArrayRef<CharSourceRange> Ranges)
override {}
109 void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
110 SmallVectorImpl<CharSourceRange> &Ranges,
111 ArrayRef<FixItHint> Hints)
override {
112 assert(Loc.isValid());
113 tooling::DiagnosticMessage *DiagWithFix =
114 Level == DiagnosticsEngine::Note ? &Error.Notes.back() : &Error.Message;
116 for (
const auto &FixIt : Hints) {
117 CharSourceRange Range = FixIt.RemoveRange;
118 assert(Range.getBegin().isValid() && Range.getEnd().isValid() &&
119 "Invalid range in the fix-it hint.");
120 assert(Range.getBegin().isFileID() && Range.getEnd().isFileID() &&
121 "Only file locations supported in fix-it hints.");
123 tooling::Replacement Replacement(Loc.getManager(), Range,
126 DiagWithFix->Fix[Replacement.getFilePath()].add(Replacement);
130 llvm::errs() <<
"Fix conflicts with existing fix! "
131 << llvm::toString(std::move(Err)) <<
"\n";
132 assert(
false &&
"Fix conflicts with existing fix!");
137 void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc)
override {}
139 void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
140 StringRef ModuleName)
override {}
142 void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
143 StringRef ModuleName)
override {}
145 void endDiagnostic(DiagOrStoredDiag D,
146 DiagnosticsEngine::Level Level)
override {
147 assert(!Error.Message.Message.empty() &&
"Message has not been set");
151 ClangTidyError &Error;
156 ClangTidyError::Level DiagLevel,
158 :
tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory),
162 std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
163 bool AllowEnablingAnalyzerAlphaCheckers,
bool EnableModuleHeadersParsing,
164 bool ExperimentalCustomChecks)
165 : OptionsProvider(std::
move(OptionsProvider)),
166 AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers),
167 EnableModuleHeadersParsing(EnableModuleHeadersParsing),
168 ExperimentalCustomChecks(ExperimentalCustomChecks) {
177 StringRef CheckName, SourceLocation Loc, StringRef Description,
178 DiagnosticIDs::Level Level ) {
179 assert(Loc.isValid());
180 unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
181 Level, (Description +
" [" + CheckName +
"]").str());
182 CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
183 return DiagEngine->Report(Loc, ID);
187 StringRef CheckName, StringRef Description,
188 DiagnosticIDs::Level Level ) {
189 unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
190 Level, (Description +
" [" + CheckName +
"]").str());
191 CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
192 return DiagEngine->Report(ID);
196 SourceManager &SM = DiagEngine->getSourceManager();
197 FileManager &FM = SM.getFileManager();
198 FileEntryRef File = llvm::cantFail(FM.getFileRef(Error.Message.FilePath));
199 FileID ID = SM.getOrCreateFileID(File, SrcMgr::C_User);
200 SourceLocation FileStartLoc = SM.getLocForStartOfFile(ID);
201 SourceLocation Loc = FileStartLoc.getLocWithOffset(
202 static_cast<SourceLocation::IntTy
>(Error.Message.FileOffset));
203 return diag(Error.DiagnosticName, Loc, Error.Message.Message,
204 static_cast<DiagnosticIDs::Level
>(Error.DiagLevel));
209 DiagnosticIDs::Level Level ) {
210 return diag(
"clang-tidy-config", Message, Level);
214 DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info,
215 SmallVectorImpl<tooling::Diagnostic> &NoLintErrors,
bool AllowIO,
216 bool EnableNoLintBlocks) {
218 return NoLintHandler.shouldSuppress(DiagLevel, Info, CheckName, NoLintErrors,
219 AllowIO, EnableNoLintBlocks);
223 DiagEngine->setSourceManager(SourceMgr);
228 FileExtensions.clear();
229 for (StringRef Suffix : AllFileExtensions) {
230 StringRef Extension = Suffix.trim();
231 if (!llvm::all_of(Extension, isAlphanumeric))
233 FileExtensions.insert(Extension);
239 CurrentFile = std::string(File);
242 WarningAsErrorFilter =
245 HeaderFileExtensions))
248 ImplementationFileExtensions))
253 DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
254 LangOpts = Context->getLangOpts();
258 return OptionsProvider->getGlobalOptions();
262 return CurrentOptions;
269 OptionsProvider->getOptions(File), 0);
275 ProfilePrefix = std::string(Prefix);
278std::optional<ClangTidyProfiling::StorageParams>
280 if (ProfilePrefix.empty())
287 assert(CheckFilter !=
nullptr);
288 return CheckFilter->contains(CheckName);
292 assert(WarningAsErrorFilter !=
nullptr);
293 return WarningAsErrorFilter->contains(CheckName);
297 std::string ClangWarningOption = std::string(
298 DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID));
299 if (!ClangWarningOption.empty())
300 return "clang-diagnostic-" + ClangWarningOption;
301 llvm::DenseMap<unsigned, std::string>::const_iterator I =
302 CheckNamesByDiagnosticID.find(DiagnosticID);
303 if (I != CheckNamesByDiagnosticID.end())
310 bool RemoveIncompatibleErrors,
bool GetFixesFromNotes,
311 bool EnableNolintBlocks)
312 : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine),
313 RemoveIncompatibleErrors(RemoveIncompatibleErrors),
314 GetFixesFromNotes(GetFixesFromNotes),
315 EnableNolintBlocks(EnableNolintBlocks) {}
317void ClangTidyDiagnosticConsumer::finalizeLastError() {
318 if (!Errors.empty()) {
320 if (Error.DiagnosticName ==
"clang-tidy-config") {
323 Error.DiagLevel != ClangTidyError::Error) {
326 }
else if (!LastErrorRelatesToUserCode) {
329 }
else if (!LastErrorPassesLineFilter) {
330 ++Context.Stats.ErrorsIgnoredLineFilter;
333 ++Context.Stats.ErrorsDisplayed;
336 LastErrorRelatesToUserCode =
false;
337 LastErrorPassesLineFilter =
false;
340namespace clang::tidy {
342const llvm::StringMap<tooling::Replacements> *
343getFixIt(
const tooling::Diagnostic &Diagnostic,
bool AnyFix) {
344 if (!Diagnostic.Message.Fix.empty())
345 return &Diagnostic.Message.Fix;
348 const llvm::StringMap<tooling::Replacements> *Result =
nullptr;
349 for (
const auto &Note : Diagnostic.Notes) {
350 if (!Note.Fix.empty()) {
363 const Preprocessor *PP) {
364 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
366 assert(!InSourceFile);
371 assert(InSourceFile);
372 InSourceFile =
false;
374 DiagnosticConsumer::EndSourceFile();
378 DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
381 assert(InSourceFile || Info.getLocation().isInvalid());
383 if (LastErrorWasIgnored && DiagLevel == DiagnosticsEngine::Note)
386 SmallVector<tooling::Diagnostic, 1> SuppressionErrors;
387 if (Context.shouldSuppressDiagnostic(DiagLevel, Info, SuppressionErrors,
388 EnableNolintBlocks)) {
389 ++Context.Stats.ErrorsIgnoredNOLINT;
391 LastErrorWasIgnored =
true;
392 for (
const auto &Error : SuppressionErrors)
397 LastErrorWasIgnored =
false;
399 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
401 if (DiagLevel == DiagnosticsEngine::Note) {
402 assert(!Errors.empty() &&
403 "A diagnostic note can only be appended to a message.");
406 std::string CheckName = Context.getCheckName(Info.getID());
407 if (CheckName.empty()) {
411 case DiagnosticsEngine::Error:
412 case DiagnosticsEngine::Fatal:
413 CheckName =
"clang-diagnostic-error";
415 case DiagnosticsEngine::Warning:
416 CheckName =
"clang-diagnostic-warning";
418 case DiagnosticsEngine::Remark:
419 CheckName =
"clang-diagnostic-remark";
422 CheckName =
"clang-diagnostic-unknown";
427 ClangTidyError::Level Level = ClangTidyError::Warning;
428 if (DiagLevel == DiagnosticsEngine::Error ||
429 DiagLevel == DiagnosticsEngine::Fatal) {
432 Level = ClangTidyError::Error;
433 LastErrorRelatesToUserCode =
true;
434 LastErrorPassesLineFilter =
true;
435 }
else if (DiagLevel == DiagnosticsEngine::Remark) {
436 Level = ClangTidyError::Remark;
439 bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning &&
440 Context.treatAsError(CheckName);
441 Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(),
445 if (ExternalDiagEngine) {
448 forwardDiagnostic(Info);
450 ClangTidyDiagnosticRenderer Converter(
451 Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
453 SmallString<100> Message;
454 Info.FormatDiagnostic(Message);
456 if (Info.hasSourceManager())
457 Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
458 else if (Context.DiagEngine->hasSourceManager())
459 Loc = FullSourceLoc(Info.getLocation(),
460 Context.DiagEngine->getSourceManager());
461 Converter.emitDiagnostic(Loc, DiagLevel, Message, Info.getRanges(),
462 Info.getFixItHints());
465 if (Info.hasSourceManager())
466 checkFilters(Info.getLocation(), Info.getSourceManager());
468 for (
const auto &Error : SuppressionErrors)
472bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
473 unsigned LineNumber)
const {
477 if (FileName.ends_with(Filter.Name)) {
478 if (Filter.LineRanges.empty())
481 if (Range.first <= LineNumber && LineNumber <= Range.second)
490void ClangTidyDiagnosticConsumer::forwardDiagnostic(
const Diagnostic &Info) {
492 auto DiagLevelAndFormatString =
493 Context.getDiagLevelAndFormatString(
Info.getID(),
Info.getLocation());
494 unsigned ExternalID = ExternalDiagEngine->getDiagnosticIDs()->getCustomDiagID(
495 DiagLevelAndFormatString.first, DiagLevelAndFormatString.second);
498 auto Builder = ExternalDiagEngine->Report(
Info.getLocation(), ExternalID);
499 for (
const FixItHint &Hint :
Info.getFixItHints())
501 for (
auto Range :
Info.getRanges())
503 for (
unsigned Index = 0; Index <
Info.getNumArgs(); ++Index) {
504 DiagnosticsEngine::ArgumentKind Kind =
Info.getArgKind(Index);
506 case clang::DiagnosticsEngine::ak_std_string:
507 Builder <<
Info.getArgStdStr(Index);
509 case clang::DiagnosticsEngine::ak_c_string:
510 Builder <<
Info.getArgCStr(Index);
512 case clang::DiagnosticsEngine::ak_sint:
513 Builder <<
Info.getArgSInt(Index);
515 case clang::DiagnosticsEngine::ak_uint:
516 Builder <<
Info.getArgUInt(Index);
518 case clang::DiagnosticsEngine::ak_tokenkind:
519 Builder << static_cast<tok::TokenKind>(
Info.getRawArg(Index));
521 case clang::DiagnosticsEngine::ak_identifierinfo:
522 Builder <<
Info.getArgIdentifier(Index);
524 case clang::DiagnosticsEngine::ak_qual:
525 Builder << Qualifiers::fromOpaqueValue(
Info.getRawArg(Index));
527 case clang::DiagnosticsEngine::ak_qualtype:
528 Builder << QualType::getFromOpaquePtr((
void *)
Info.getRawArg(Index));
530 case clang::DiagnosticsEngine::ak_declarationname:
531 Builder << DeclarationName::getFromOpaqueInteger(
Info.getRawArg(Index));
533 case clang::DiagnosticsEngine::ak_nameddecl:
534 Builder << reinterpret_cast<const NamedDecl *>(
Info.getRawArg(Index));
536 case clang::DiagnosticsEngine::ak_nestednamespec:
537 Builder << NestedNameSpecifier::getFromVoidPointer(
538 reinterpret_cast<void *
>(
Info.getRawArg(Index)));
540 case clang::DiagnosticsEngine::ak_declcontext:
541 Builder << reinterpret_cast<DeclContext *>(
Info.getRawArg(Index));
543 case clang::DiagnosticsEngine::ak_qualtype_pair:
546 case clang::DiagnosticsEngine::ak_attr:
547 Builder << reinterpret_cast<Attr *>(
Info.getRawArg(Index));
549 case clang::DiagnosticsEngine::ak_attr_info:
550 Builder << reinterpret_cast<AttributeCommonInfo *>(
Info.getRawArg(Index));
552 case clang::DiagnosticsEngine::ak_addrspace:
553 Builder << static_cast<LangAS>(
Info.getRawArg(Index));
555 case clang::DiagnosticsEngine::ak_expr:
556 Builder << reinterpret_cast<const Expr *>(
Info.getRawArg(Index));
561void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location,
562 const SourceManager &Sources) {
564 if (!Location.isValid()) {
565 LastErrorRelatesToUserCode =
true;
566 LastErrorPassesLineFilter =
true;
570 if (!*Context.getOptions().SystemHeaders &&
571 (Sources.isInSystemHeader(Location) || Sources.isInSystemMacro(Location)))
577 FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
578 OptionalFileEntryRef
File = Sources.getFileEntryRefForID(FID);
583 LastErrorRelatesToUserCode =
true;
584 LastErrorPassesLineFilter =
true;
588 StringRef FileName(
File->getName());
589 LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
590 Sources.isInMainFile(Location) ||
591 (getHeaderFilter()->match(FileName) &&
592 !getExcludeHeaderFilter()->match(FileName));
594 unsigned LineNumber = Sources.getExpansionLineNumber(Location);
595 LastErrorPassesLineFilter =
596 LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
599llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
602 std::make_unique<llvm::Regex>(*Context.getOptions().HeaderFilterRegex);
603 return HeaderFilter.get();
606llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() {
607 if (!ExcludeHeaderFilter)
608 ExcludeHeaderFilter = std::make_unique<llvm::Regex>(
609 *Context.getOptions().ExcludeHeaderFilterRegex);
610 return ExcludeHeaderFilter.get();
613void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() {
630 Event(
unsigned Begin,
unsigned End, EventType Type,
unsigned ErrorId,
660 Priority = std::make_tuple(Begin, Type, -End, -ErrorSize, ErrorId);
663 Priority = std::make_tuple(Begin, Type, -End, ErrorSize, ErrorId);
666 Priority = std::make_tuple(End, Type, -Begin, ErrorSize, ErrorId);
671 bool operator<(
const Event &Other)
const {
672 return Priority < Other.Priority;
681 std::tuple<unsigned, EventType, int, int, unsigned> Priority;
684 removeDuplicatedDiagnosticsOfAliasCheckers();
687 std::vector<int> Sizes;
689 std::pair<ClangTidyError *, llvm::StringMap<tooling::Replacements> *>>
691 for (
auto &Error : Errors) {
692 if (
const auto *
Fix =
getFixIt(Error, GetFixesFromNotes))
693 ErrorFixes.emplace_back(
694 &Error,
const_cast<llvm::StringMap<tooling::Replacements> *
>(
Fix));
696 for (
const auto &ErrorAndFix : ErrorFixes) {
698 for (
const auto &FileAndReplaces : *ErrorAndFix.second) {
699 for (
const auto &Replace : FileAndReplaces.second)
700 Size += Replace.getLength();
702 Sizes.push_back(Size);
706 llvm::StringMap<std::vector<Event>> FileEvents;
707 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
708 for (
const auto &FileAndReplace : *ErrorFixes[I].second) {
709 for (
const auto &Replace : FileAndReplace.second) {
710 unsigned Begin = Replace.getOffset();
711 unsigned End = Begin + Replace.getLength();
712 auto &Events = FileEvents[Replace.getFilePath()];
714 Events.emplace_back(Begin, End, Event::ET_Insert, I, Sizes[I]);
716 Events.emplace_back(Begin, End, Event::ET_Begin, I, Sizes[I]);
717 Events.emplace_back(Begin, End, Event::ET_End, I, Sizes[I]);
723 llvm::BitVector Apply(ErrorFixes.size(),
true);
724 for (
auto &FileAndEvents : FileEvents) {
725 std::vector<Event> &Events = FileAndEvents.second;
728 int OpenIntervals = 0;
729 for (
const auto &Event : Events) {
730 switch (
Event.Type) {
731 case Event::ET_Begin:
732 if (OpenIntervals++ != 0)
733 Apply[
Event.ErrorId] =
false;
735 case Event::ET_Insert:
736 if (OpenIntervals != 0)
737 Apply[
Event.ErrorId] =
false;
740 if (--OpenIntervals != 0)
741 Apply[
Event.ErrorId] =
false;
745 assert(OpenIntervals == 0 &&
"Amount of begin/end points doesn't match");
748 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
750 ErrorFixes[I].second->clear();
751 ErrorFixes[I].first->Notes.emplace_back(
752 "this fix will not be applied because it overlaps with another fix");
758struct LessClangTidyError {
759 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
760 const tooling::DiagnosticMessage &M1 = LHS.Message;
761 const tooling::DiagnosticMessage &M2 = RHS.Message;
763 return std::tie(M1.FilePath, M1.FileOffset, LHS.DiagnosticName,
765 std::tie(M2.FilePath, M2.FileOffset, RHS.DiagnosticName, M2.Message);
768struct EqualClangTidyError {
769 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
770 LessClangTidyError Less;
771 return !Less(LHS, RHS) && !Less(RHS, LHS);
779 llvm::stable_sort(Errors, LessClangTidyError());
780 Errors.erase(llvm::unique(Errors, EqualClangTidyError()), Errors.end());
781 if (RemoveIncompatibleErrors)
782 removeIncompatibleErrors();
783 return std::move(Errors);
787struct LessClangTidyErrorWithoutDiagnosticName {
789 const tooling::DiagnosticMessage &M1 = LHS->Message;
790 const tooling::DiagnosticMessage &M2 = RHS->Message;
792 return std::tie(M1.FilePath, M1.FileOffset, M1.Message) <
793 std::tie(M2.FilePath, M2.FileOffset, M2.Message);
798void ClangTidyDiagnosticConsumer::removeDuplicatedDiagnosticsOfAliasCheckers() {
799 using UniqueErrorSet =
800 std::set<ClangTidyError *, LessClangTidyErrorWithoutDiagnosticName>;
801 UniqueErrorSet UniqueErrors;
803 auto IT = Errors.begin();
804 while (IT != Errors.end()) {
805 ClangTidyError &
Error = *IT;
806 std::pair<UniqueErrorSet::iterator, bool> Inserted =
807 UniqueErrors.insert(&Error);
810 if (Inserted.second) {
813 ClangTidyError &ExistingError = **Inserted.first;
814 const llvm::StringMap<tooling::Replacements> &CandidateFix =
816 const llvm::StringMap<tooling::Replacements> &ExistingFix =
817 (*Inserted.first)->Message.Fix;
819 if (CandidateFix != ExistingFix) {
822 ExistingError.Message.Fix.clear();
823 ExistingError.Notes.emplace_back(
824 llvm::formatv(
"cannot apply fix-it because an alias checker has "
825 "suggested a different fix-it; please remove one of "
826 "the checkers ('{0}', '{1}') or "
827 "ensure they are both configured the same",
828 ExistingError.DiagnosticName,
Error.DiagnosticName)
832 if (
Error.IsWarningAsError)
833 ExistingError.IsWarningAsError =
true;
836 ExistingError.EnabledDiagnosticAliases.emplace_back(
Error.DiagnosticName);
837 IT = Errors.erase(IT);
static bool parseFileExtensions(llvm::ArrayRef< std::string > AllFileExtensions, FileExtensionsSet &FileExtensions)
static cl::opt< bool > Fix("fix", 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))
static cl::opt< std::string > WarningsAsErrors("warnings-as-errors", desc(R"(
Upgrades warnings to errors. Same format as
'-checks'.
This option's value is appended to the value of
the 'WarningsAsErrors' option in .clang-tidy
file, if any.
)"), cl::init(""), cl::cat(ClangTidyCategory))
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))
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
ClangTidyContext(std::unique_ptr< ClangTidyOptionsProvider > OptionsProvider)
bool isCheckEnabled(StringRef CheckName) const
Returns true if the check is enabled for the CurrentFile.
std::string getCheckName(unsigned DiagnosticID) const
Returns the name of the clang-tidy check which produced this diagnostic ID.
const ClangTidyOptions & getOptions() const
Returns options for CurrentFile.
DiagnosticBuilder configurationDiag(StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors to do with reading the configuration using this method.
void setASTContext(ASTContext *Context)
Sets ASTContext for the current translation unit.
void setProfileStoragePrefix(StringRef ProfilePrefix)
Control storage of profile date.
void setEnableProfiling(bool Profile)
Control profile collection in clang-tidy.
void setCurrentFile(StringRef File)
Should be called when starting to process new translation unit.
bool shouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info, SmallVectorImpl< tooling::Diagnostic > &NoLintErrors, bool AllowIO=true, bool EnableNoLintBlocks=true)
Check whether a given diagnostic should be suppressed due to the presence of a "NOLINT" suppression c...
bool treatAsError(StringRef CheckName) const
Returns true if the check should be upgraded to error for the CurrentFile.
DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors detected using this method.
ClangTidyOptions getOptionsForFile(StringRef File) const
Returns options for File.
std::optional< ClangTidyProfiling::StorageParams > getProfileStorageParams() const
const ClangTidyGlobalOptions & getGlobalOptions() const
Returns global options.
void setSourceManager(SourceManager *SourceMgr)
Sets the SourceManager of the used DiagnosticsEngine.
ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx, DiagnosticsEngine *ExternalDiagEngine=nullptr, bool RemoveIncompatibleErrors=true, bool GetFixesFromNotes=false, bool EnableNolintBlocks=true)
void EndSourceFile() override
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr) override
std::vector< ClangTidyError > take()
@ Info
An information message.
bool operator<(const Ref &L, const Ref &R)
@ Type
An inlay hint that for a type annotation.
const llvm::StringMap< tooling::Replacements > * getFixIt(const tooling::Diagnostic &Diagnostic, bool AnyFix)
Gets the Fix attached to Diagnostic.
llvm::SmallSet< llvm::StringRef, 5 > FileExtensionsSet
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccess P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A detected error complete with information to display diagnostic and automatic fix.
ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory, bool IsWarningAsError)
std::vector< FileFilter > LineFilter
Output warnings from certain line ranges of certain files only.
Contains options for clang-tidy.
ClangTidyOptions merge(const ClangTidyOptions &Other, unsigned Order) const
Creates a new ClangTidyOptions instance combined from all fields of this instance overridden by the f...
static ClangTidyOptions getDefaults()
These options are used for all settings that haven't been overridden by the OptionsProvider.
unsigned ErrorsIgnoredCheckFilter
unsigned ErrorsIgnoredNonUserCode
Contains a list of line ranges in a single file.
std::pair< unsigned int, unsigned int > LineRange
LineRange is a pair<start, end> (inclusive).