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 const 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 const 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 const 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 const 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 const 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 const 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 const FileEntryRef File =
199 llvm::cantFail(FM.getFileRef(Error.Message.FilePath));
200 const FileID ID = SM.getOrCreateFileID(File, SrcMgr::C_User);
201 const SourceLocation FileStartLoc = SM.getLocForStartOfFile(ID);
202 const SourceLocation Loc = FileStartLoc.getLocWithOffset(
203 static_cast<SourceLocation::IntTy
>(Error.Message.FileOffset));
204 return diag(Error.DiagnosticName, Loc, Error.Message.Message,
205 static_cast<DiagnosticIDs::Level
>(Error.DiagLevel));
210 DiagnosticIDs::Level Level ) {
211 return diag(
"clang-tidy-config", Message, Level);
215 DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info,
216 SmallVectorImpl<tooling::Diagnostic> &NoLintErrors,
bool AllowIO,
217 bool EnableNoLintBlocks) {
218 const std::string CheckName =
getCheckName(Info.getID());
219 return NoLintHandler.shouldSuppress(DiagLevel, Info, CheckName, NoLintErrors,
220 AllowIO, EnableNoLintBlocks);
224 DiagEngine->setSourceManager(SourceMgr);
229 FileExtensions.clear();
230 for (
const StringRef Suffix : AllFileExtensions) {
231 StringRef Extension = Suffix.trim();
232 if (!llvm::all_of(Extension, isAlphanumeric))
234 FileExtensions.insert(Extension);
240 CurrentFile = std::string(File);
243 WarningAsErrorFilter =
246 HeaderFileExtensions))
249 ImplementationFileExtensions))
254 DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
255 LangOpts = Context->getLangOpts();
259 return OptionsProvider->getGlobalOptions();
263 return CurrentOptions;
270 OptionsProvider->getOptions(File), 0);
276 ProfilePrefix = std::string(Prefix);
279std::optional<ClangTidyProfiling::StorageParams>
281 if (ProfilePrefix.empty())
288 assert(CheckFilter !=
nullptr);
289 return CheckFilter->contains(CheckName);
293 assert(WarningAsErrorFilter !=
nullptr);
294 return WarningAsErrorFilter->contains(CheckName);
298 const std::string ClangWarningOption = std::string(
299 DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID));
300 if (!ClangWarningOption.empty())
301 return "clang-diagnostic-" + ClangWarningOption;
302 const llvm::DenseMap<unsigned, std::string>::const_iterator I =
303 CheckNamesByDiagnosticID.find(DiagnosticID);
304 if (I != CheckNamesByDiagnosticID.end())
311 bool RemoveIncompatibleErrors,
bool GetFixesFromNotes,
312 bool EnableNolintBlocks)
313 : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine),
314 RemoveIncompatibleErrors(RemoveIncompatibleErrors),
315 GetFixesFromNotes(GetFixesFromNotes),
316 EnableNolintBlocks(EnableNolintBlocks) {}
318void ClangTidyDiagnosticConsumer::finalizeLastError() {
319 if (!Errors.empty()) {
321 if (Error.DiagnosticName ==
"clang-tidy-config") {
324 Error.DiagLevel != ClangTidyError::Error) {
327 }
else if (!LastErrorRelatesToUserCode) {
330 }
else if (!LastErrorPassesLineFilter) {
331 ++Context.Stats.ErrorsIgnoredLineFilter;
334 ++Context.Stats.ErrorsDisplayed;
337 LastErrorRelatesToUserCode =
false;
338 LastErrorPassesLineFilter =
false;
341namespace clang::tidy {
343const llvm::StringMap<tooling::Replacements> *
344getFixIt(
const tooling::Diagnostic &Diagnostic,
bool AnyFix) {
345 if (!Diagnostic.Message.Fix.empty())
346 return &Diagnostic.Message.Fix;
349 const llvm::StringMap<tooling::Replacements> *Result =
nullptr;
350 for (
const auto &Note : Diagnostic.Notes) {
351 if (!Note.Fix.empty()) {
364 const Preprocessor *PP) {
365 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
367 assert(!InSourceFile);
372 assert(InSourceFile);
373 InSourceFile =
false;
375 DiagnosticConsumer::EndSourceFile();
379 DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
382 assert(InSourceFile || Info.getLocation().isInvalid());
384 if (LastErrorWasIgnored && DiagLevel == DiagnosticsEngine::Note)
387 SmallVector<tooling::Diagnostic, 1> SuppressionErrors;
388 if (Context.shouldSuppressDiagnostic(DiagLevel, Info, SuppressionErrors,
389 EnableNolintBlocks)) {
390 ++Context.Stats.ErrorsIgnoredNOLINT;
392 LastErrorWasIgnored =
true;
393 for (
const auto &Error : SuppressionErrors)
398 LastErrorWasIgnored =
false;
400 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
402 if (DiagLevel == DiagnosticsEngine::Note) {
403 assert(!Errors.empty() &&
404 "A diagnostic note can only be appended to a message.");
407 std::string CheckName = Context.getCheckName(Info.getID());
408 if (CheckName.empty()) {
412 case DiagnosticsEngine::Error:
413 case DiagnosticsEngine::Fatal:
414 CheckName =
"clang-diagnostic-error";
416 case DiagnosticsEngine::Warning:
417 CheckName =
"clang-diagnostic-warning";
419 case DiagnosticsEngine::Remark:
420 CheckName =
"clang-diagnostic-remark";
423 CheckName =
"clang-diagnostic-unknown";
428 ClangTidyError::Level Level = ClangTidyError::Warning;
429 if (DiagLevel == DiagnosticsEngine::Error ||
430 DiagLevel == DiagnosticsEngine::Fatal) {
433 Level = ClangTidyError::Error;
434 LastErrorRelatesToUserCode =
true;
435 LastErrorPassesLineFilter =
true;
436 }
else if (DiagLevel == DiagnosticsEngine::Remark) {
437 Level = ClangTidyError::Remark;
440 const bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning &&
441 Context.treatAsError(CheckName);
442 Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(),
446 if (ExternalDiagEngine) {
449 forwardDiagnostic(Info);
451 ClangTidyDiagnosticRenderer Converter(
452 Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
454 SmallString<100> Message;
455 Info.FormatDiagnostic(Message);
457 if (Info.hasSourceManager())
458 Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
459 else if (Context.DiagEngine->hasSourceManager())
460 Loc = FullSourceLoc(Info.getLocation(),
461 Context.DiagEngine->getSourceManager());
462 Converter.emitDiagnostic(Loc, DiagLevel, Message, Info.getRanges(),
463 Info.getFixItHints());
466 if (Info.hasSourceManager())
467 checkFilters(Info.getLocation(), Info.getSourceManager());
469 for (
const auto &Error : SuppressionErrors)
473bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
474 unsigned LineNumber)
const {
478 if (FileName.ends_with(Filter.Name)) {
479 if (Filter.LineRanges.empty())
482 if (Range.first <= LineNumber && LineNumber <= Range.second)
491void ClangTidyDiagnosticConsumer::forwardDiagnostic(
const Diagnostic &Info) {
493 auto DiagLevelAndFormatString =
494 Context.getDiagLevelAndFormatString(
Info.getID(),
Info.getLocation());
495 const unsigned ExternalID =
496 ExternalDiagEngine->getDiagnosticIDs()->getCustomDiagID(
497 DiagLevelAndFormatString.first, DiagLevelAndFormatString.second);
500 auto Builder = ExternalDiagEngine->Report(
Info.getLocation(), ExternalID);
501 for (
const FixItHint &Hint :
Info.getFixItHints())
503 for (
auto Range :
Info.getRanges())
505 for (
unsigned Index = 0; Index <
Info.getNumArgs(); ++Index) {
506 const DiagnosticsEngine::ArgumentKind Kind =
Info.getArgKind(Index);
508 case clang::DiagnosticsEngine::ak_std_string:
509 Builder <<
Info.getArgStdStr(Index);
511 case clang::DiagnosticsEngine::ak_c_string:
512 Builder <<
Info.getArgCStr(Index);
514 case clang::DiagnosticsEngine::ak_sint:
515 Builder <<
Info.getArgSInt(Index);
517 case clang::DiagnosticsEngine::ak_uint:
518 Builder <<
Info.getArgUInt(Index);
520 case clang::DiagnosticsEngine::ak_tokenkind:
521 Builder << static_cast<tok::TokenKind>(
Info.getRawArg(Index));
523 case clang::DiagnosticsEngine::ak_identifierinfo:
524 Builder <<
Info.getArgIdentifier(Index);
526 case clang::DiagnosticsEngine::ak_qual:
527 Builder << Qualifiers::fromOpaqueValue(
Info.getRawArg(Index));
529 case clang::DiagnosticsEngine::ak_qualtype:
530 Builder << QualType::getFromOpaquePtr((
void *)
Info.getRawArg(Index));
532 case clang::DiagnosticsEngine::ak_declarationname:
533 Builder << DeclarationName::getFromOpaqueInteger(
Info.getRawArg(Index));
535 case clang::DiagnosticsEngine::ak_nameddecl:
536 Builder << reinterpret_cast<const NamedDecl *>(
Info.getRawArg(Index));
538 case clang::DiagnosticsEngine::ak_nestednamespec:
539 Builder << NestedNameSpecifier::getFromVoidPointer(
540 reinterpret_cast<void *
>(
Info.getRawArg(Index)));
542 case clang::DiagnosticsEngine::ak_declcontext:
543 Builder << reinterpret_cast<DeclContext *>(
Info.getRawArg(Index));
545 case clang::DiagnosticsEngine::ak_qualtype_pair:
548 case clang::DiagnosticsEngine::ak_attr:
549 Builder << reinterpret_cast<Attr *>(
Info.getRawArg(Index));
551 case clang::DiagnosticsEngine::ak_attr_info:
552 Builder << reinterpret_cast<AttributeCommonInfo *>(
Info.getRawArg(Index));
554 case clang::DiagnosticsEngine::ak_addrspace:
555 Builder << static_cast<LangAS>(
Info.getRawArg(Index));
557 case clang::DiagnosticsEngine::ak_expr:
558 Builder << reinterpret_cast<const Expr *>(
Info.getRawArg(Index));
563void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location,
564 const SourceManager &Sources) {
566 if (!Location.isValid()) {
567 LastErrorRelatesToUserCode =
true;
568 LastErrorPassesLineFilter =
true;
572 if (!*Context.getOptions().SystemHeaders &&
573 (Sources.isInSystemHeader(Location) || Sources.isInSystemMacro(Location)))
579 const FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
580 OptionalFileEntryRef
File = Sources.getFileEntryRefForID(FID);
585 LastErrorRelatesToUserCode =
true;
586 LastErrorPassesLineFilter =
true;
590 const StringRef FileName(
File->getName());
591 LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
592 Sources.isInMainFile(Location) ||
593 (getHeaderFilter()->match(FileName) &&
594 !getExcludeHeaderFilter()->match(FileName));
596 const unsigned LineNumber = Sources.getExpansionLineNumber(Location);
597 LastErrorPassesLineFilter =
598 LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
601llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
604 std::make_unique<llvm::Regex>(*Context.getOptions().HeaderFilterRegex);
605 return HeaderFilter.get();
608llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() {
609 if (!ExcludeHeaderFilter)
610 ExcludeHeaderFilter = std::make_unique<llvm::Regex>(
611 *Context.getOptions().ExcludeHeaderFilterRegex);
612 return ExcludeHeaderFilter.get();
615void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() {
632 Event(
unsigned Begin,
unsigned End, EventType Type,
unsigned ErrorId,
662 Priority = std::make_tuple(Begin, Type, -End, -ErrorSize, ErrorId);
665 Priority = std::make_tuple(Begin, Type, -End, ErrorSize, ErrorId);
668 Priority = std::make_tuple(End, Type, -Begin, ErrorSize, ErrorId);
673 bool operator<(
const Event &Other)
const {
674 return Priority < Other.Priority;
683 std::tuple<unsigned, EventType, int, int, unsigned> Priority;
686 removeDuplicatedDiagnosticsOfAliasCheckers();
689 std::vector<int> Sizes;
691 std::pair<ClangTidyError *, llvm::StringMap<tooling::Replacements> *>>
693 for (
auto &Error : Errors) {
694 if (
const auto *
Fix =
getFixIt(Error, GetFixesFromNotes))
695 ErrorFixes.emplace_back(
696 &Error,
const_cast<llvm::StringMap<tooling::Replacements> *
>(
Fix));
698 for (
const auto &ErrorAndFix : ErrorFixes) {
700 for (
const auto &FileAndReplaces : *ErrorAndFix.second) {
701 for (
const auto &Replace : FileAndReplaces.second)
702 Size += Replace.getLength();
704 Sizes.push_back(Size);
708 llvm::StringMap<std::vector<Event>> FileEvents;
709 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
710 for (
const auto &FileAndReplace : *ErrorFixes[I].second) {
711 for (
const auto &Replace : FileAndReplace.second) {
712 const unsigned Begin = Replace.getOffset();
713 const unsigned End = Begin + Replace.getLength();
714 auto &Events = FileEvents[Replace.getFilePath()];
716 Events.emplace_back(Begin, End, Event::ET_Insert, I, Sizes[I]);
718 Events.emplace_back(Begin, End, Event::ET_Begin, I, Sizes[I]);
719 Events.emplace_back(Begin, End, Event::ET_End, I, Sizes[I]);
725 llvm::BitVector Apply(ErrorFixes.size(),
true);
726 for (
auto &FileAndEvents : FileEvents) {
727 std::vector<Event> &Events = FileAndEvents.second;
730 int OpenIntervals = 0;
731 for (
const auto &Event : Events) {
732 switch (
Event.Type) {
733 case Event::ET_Begin:
734 if (OpenIntervals++ != 0)
735 Apply[
Event.ErrorId] =
false;
737 case Event::ET_Insert:
738 if (OpenIntervals != 0)
739 Apply[
Event.ErrorId] =
false;
742 if (--OpenIntervals != 0)
743 Apply[
Event.ErrorId] =
false;
747 assert(OpenIntervals == 0 &&
"Amount of begin/end points doesn't match");
750 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
752 ErrorFixes[I].second->clear();
753 ErrorFixes[I].first->Notes.emplace_back(
754 "this fix will not be applied because it overlaps with another fix");
760struct LessClangTidyError {
761 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
762 const tooling::DiagnosticMessage &M1 = LHS.Message;
763 const tooling::DiagnosticMessage &M2 = RHS.Message;
765 return std::tie(M1.FilePath, M1.FileOffset, LHS.DiagnosticName,
767 std::tie(M2.FilePath, M2.FileOffset, RHS.DiagnosticName, M2.Message);
770struct EqualClangTidyError {
771 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
772 const LessClangTidyError Less;
773 return !Less(LHS, RHS) && !Less(RHS, LHS);
781 llvm::stable_sort(Errors, LessClangTidyError());
782 Errors.erase(llvm::unique(Errors, EqualClangTidyError()), Errors.end());
783 if (RemoveIncompatibleErrors)
784 removeIncompatibleErrors();
785 return std::move(Errors);
789struct LessClangTidyErrorWithoutDiagnosticName {
791 const tooling::DiagnosticMessage &M1 = LHS->Message;
792 const tooling::DiagnosticMessage &M2 = RHS->Message;
794 return std::tie(M1.FilePath, M1.FileOffset, M1.Message) <
795 std::tie(M2.FilePath, M2.FileOffset, M2.Message);
800void ClangTidyDiagnosticConsumer::removeDuplicatedDiagnosticsOfAliasCheckers() {
801 using UniqueErrorSet =
802 std::set<ClangTidyError *, LessClangTidyErrorWithoutDiagnosticName>;
803 UniqueErrorSet UniqueErrors;
805 auto IT = Errors.begin();
806 while (IT != Errors.end()) {
807 ClangTidyError &
Error = *IT;
808 const std::pair<UniqueErrorSet::iterator, bool> Inserted =
809 UniqueErrors.insert(&Error);
812 if (Inserted.second) {
815 ClangTidyError &ExistingError = **Inserted.first;
816 const llvm::StringMap<tooling::Replacements> &CandidateFix =
818 const llvm::StringMap<tooling::Replacements> &ExistingFix =
819 (*Inserted.first)->Message.Fix;
821 if (CandidateFix != ExistingFix) {
824 ExistingError.Message.Fix.clear();
825 ExistingError.Notes.emplace_back(
826 llvm::formatv(
"cannot apply fix-it because an alias checker has "
827 "suggested a different fix-it; please remove one of "
828 "the checkers ('{0}', '{1}') or "
829 "ensure they are both configured the same",
830 ExistingError.DiagnosticName,
Error.DiagnosticName)
834 if (
Error.IsWarningAsError)
835 ExistingError.IsWarningAsError =
true;
838 ExistingError.EnabledDiagnosticAliases.emplace_back(
Error.DiagnosticName);
839 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::ProBoundsAvoidUncheckedContainerAccessCheck 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).