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 : OptionsProvider(std::
move(OptionsProvider)),
166 AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers),
167 EnableModuleHeadersParsing(EnableModuleHeadersParsing) {
176 StringRef CheckName, SourceLocation Loc, StringRef Description,
177 DiagnosticIDs::Level Level ) {
178 assert(Loc.isValid());
179 unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
180 Level, (Description +
" [" + CheckName +
"]").str());
181 CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
182 return DiagEngine->Report(Loc, ID);
186 StringRef CheckName, StringRef Description,
187 DiagnosticIDs::Level Level ) {
188 unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
189 Level, (Description +
" [" + CheckName +
"]").str());
190 CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
191 return DiagEngine->Report(ID);
195 SourceManager &SM = DiagEngine->getSourceManager();
196 FileManager &FM = SM.getFileManager();
197 FileEntryRef File = llvm::cantFail(FM.getFileRef(Error.Message.FilePath));
198 FileID ID = SM.getOrCreateFileID(File, SrcMgr::C_User);
199 SourceLocation FileStartLoc = SM.getLocForStartOfFile(ID);
200 SourceLocation Loc = FileStartLoc.getLocWithOffset(
201 static_cast<SourceLocation::IntTy
>(Error.Message.FileOffset));
202 return diag(Error.DiagnosticName, Loc, Error.Message.Message,
203 static_cast<DiagnosticIDs::Level
>(Error.DiagLevel));
208 DiagnosticIDs::Level Level ) {
209 return diag(
"clang-tidy-config", Message, Level);
213 DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info,
214 SmallVectorImpl<tooling::Diagnostic> &NoLintErrors,
bool AllowIO,
215 bool EnableNoLintBlocks) {
217 return NoLintHandler.shouldSuppress(DiagLevel, Info, CheckName, NoLintErrors,
218 AllowIO, EnableNoLintBlocks);
222 DiagEngine->setSourceManager(SourceMgr);
227 FileExtensions.clear();
228 for (StringRef Suffix : AllFileExtensions) {
229 StringRef Extension = Suffix.trim();
230 if (!llvm::all_of(Extension, isAlphanumeric))
232 FileExtensions.insert(Extension);
238 CurrentFile = std::string(File);
241 WarningAsErrorFilter =
244 HeaderFileExtensions))
247 ImplementationFileExtensions))
252 DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
253 LangOpts = Context->getLangOpts();
257 return OptionsProvider->getGlobalOptions();
261 return CurrentOptions;
268 OptionsProvider->getOptions(File), 0);
274 ProfilePrefix = std::string(Prefix);
277std::optional<ClangTidyProfiling::StorageParams>
279 if (ProfilePrefix.empty())
286 assert(CheckFilter !=
nullptr);
287 return CheckFilter->contains(CheckName);
291 assert(WarningAsErrorFilter !=
nullptr);
292 return WarningAsErrorFilter->contains(CheckName);
296 std::string ClangWarningOption = std::string(
297 DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID));
298 if (!ClangWarningOption.empty())
299 return "clang-diagnostic-" + ClangWarningOption;
300 llvm::DenseMap<unsigned, std::string>::const_iterator I =
301 CheckNamesByDiagnosticID.find(DiagnosticID);
302 if (I != CheckNamesByDiagnosticID.end())
309 bool RemoveIncompatibleErrors,
bool GetFixesFromNotes,
310 bool EnableNolintBlocks)
311 : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine),
312 RemoveIncompatibleErrors(RemoveIncompatibleErrors),
313 GetFixesFromNotes(GetFixesFromNotes),
314 EnableNolintBlocks(EnableNolintBlocks) {}
316void ClangTidyDiagnosticConsumer::finalizeLastError() {
317 if (!Errors.empty()) {
319 if (Error.DiagnosticName ==
"clang-tidy-config") {
322 Error.DiagLevel != ClangTidyError::Error) {
325 }
else if (!LastErrorRelatesToUserCode) {
328 }
else if (!LastErrorPassesLineFilter) {
329 ++Context.Stats.ErrorsIgnoredLineFilter;
332 ++Context.Stats.ErrorsDisplayed;
335 LastErrorRelatesToUserCode =
false;
336 LastErrorPassesLineFilter =
false;
339namespace clang::tidy {
341const llvm::StringMap<tooling::Replacements> *
342getFixIt(
const tooling::Diagnostic &Diagnostic,
bool AnyFix) {
343 if (!Diagnostic.Message.Fix.empty())
344 return &Diagnostic.Message.Fix;
347 const llvm::StringMap<tooling::Replacements> *Result =
nullptr;
348 for (
const auto &Note : Diagnostic.Notes) {
349 if (!Note.Fix.empty()) {
362 const Preprocessor *PP) {
363 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
365 assert(!InSourceFile);
370 assert(InSourceFile);
371 InSourceFile =
false;
373 DiagnosticConsumer::EndSourceFile();
377 DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
380 assert(InSourceFile || Info.getLocation().isInvalid());
382 if (LastErrorWasIgnored && DiagLevel == DiagnosticsEngine::Note)
385 SmallVector<tooling::Diagnostic, 1> SuppressionErrors;
386 if (Context.shouldSuppressDiagnostic(DiagLevel, Info, SuppressionErrors,
387 EnableNolintBlocks)) {
388 ++Context.Stats.ErrorsIgnoredNOLINT;
390 LastErrorWasIgnored =
true;
391 for (
const auto &Error : SuppressionErrors)
396 LastErrorWasIgnored =
false;
398 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
400 if (DiagLevel == DiagnosticsEngine::Note) {
401 assert(!Errors.empty() &&
402 "A diagnostic note can only be appended to a message.");
405 std::string CheckName = Context.getCheckName(Info.getID());
406 if (CheckName.empty()) {
410 case DiagnosticsEngine::Error:
411 case DiagnosticsEngine::Fatal:
412 CheckName =
"clang-diagnostic-error";
414 case DiagnosticsEngine::Warning:
415 CheckName =
"clang-diagnostic-warning";
417 case DiagnosticsEngine::Remark:
418 CheckName =
"clang-diagnostic-remark";
421 CheckName =
"clang-diagnostic-unknown";
426 ClangTidyError::Level Level = ClangTidyError::Warning;
427 if (DiagLevel == DiagnosticsEngine::Error ||
428 DiagLevel == DiagnosticsEngine::Fatal) {
431 Level = ClangTidyError::Error;
432 LastErrorRelatesToUserCode =
true;
433 LastErrorPassesLineFilter =
true;
434 }
else if (DiagLevel == DiagnosticsEngine::Remark) {
435 Level = ClangTidyError::Remark;
438 bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning &&
439 Context.treatAsError(CheckName);
440 Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(),
444 if (ExternalDiagEngine) {
447 forwardDiagnostic(Info);
449 ClangTidyDiagnosticRenderer Converter(
450 Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
452 SmallString<100> Message;
453 Info.FormatDiagnostic(Message);
455 if (Info.hasSourceManager())
456 Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
457 else if (Context.DiagEngine->hasSourceManager())
458 Loc = FullSourceLoc(Info.getLocation(),
459 Context.DiagEngine->getSourceManager());
460 Converter.emitDiagnostic(Loc, DiagLevel, Message, Info.getRanges(),
461 Info.getFixItHints());
464 if (Info.hasSourceManager())
465 checkFilters(Info.getLocation(), Info.getSourceManager());
467 for (
const auto &Error : SuppressionErrors)
471bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
472 unsigned LineNumber)
const {
476 if (FileName.ends_with(Filter.Name)) {
477 if (Filter.LineRanges.empty())
480 if (Range.first <= LineNumber && LineNumber <= Range.second)
489void ClangTidyDiagnosticConsumer::forwardDiagnostic(
const Diagnostic &Info) {
491 auto DiagLevelAndFormatString =
492 Context.getDiagLevelAndFormatString(
Info.getID(),
Info.getLocation());
493 unsigned ExternalID = ExternalDiagEngine->getDiagnosticIDs()->getCustomDiagID(
494 DiagLevelAndFormatString.first, DiagLevelAndFormatString.second);
497 auto Builder = ExternalDiagEngine->Report(
Info.getLocation(), ExternalID);
498 for (
const FixItHint &Hint :
Info.getFixItHints())
500 for (
auto Range :
Info.getRanges())
502 for (
unsigned Index = 0; Index <
Info.getNumArgs(); ++Index) {
503 DiagnosticsEngine::ArgumentKind Kind =
Info.getArgKind(Index);
505 case clang::DiagnosticsEngine::ak_std_string:
506 Builder <<
Info.getArgStdStr(Index);
508 case clang::DiagnosticsEngine::ak_c_string:
509 Builder <<
Info.getArgCStr(Index);
511 case clang::DiagnosticsEngine::ak_sint:
512 Builder <<
Info.getArgSInt(Index);
514 case clang::DiagnosticsEngine::ak_uint:
515 Builder <<
Info.getArgUInt(Index);
517 case clang::DiagnosticsEngine::ak_tokenkind:
518 Builder << static_cast<tok::TokenKind>(
Info.getRawArg(Index));
520 case clang::DiagnosticsEngine::ak_identifierinfo:
521 Builder <<
Info.getArgIdentifier(Index);
523 case clang::DiagnosticsEngine::ak_qual:
524 Builder << Qualifiers::fromOpaqueValue(
Info.getRawArg(Index));
526 case clang::DiagnosticsEngine::ak_qualtype:
527 Builder << QualType::getFromOpaquePtr((
void *)
Info.getRawArg(Index));
529 case clang::DiagnosticsEngine::ak_declarationname:
530 Builder << DeclarationName::getFromOpaqueInteger(
Info.getRawArg(Index));
532 case clang::DiagnosticsEngine::ak_nameddecl:
533 Builder << reinterpret_cast<const NamedDecl *>(
Info.getRawArg(Index));
535 case clang::DiagnosticsEngine::ak_nestednamespec:
536 Builder << NestedNameSpecifier::getFromVoidPointer(
537 reinterpret_cast<void *
>(
Info.getRawArg(Index)));
539 case clang::DiagnosticsEngine::ak_declcontext:
540 Builder << reinterpret_cast<DeclContext *>(
Info.getRawArg(Index));
542 case clang::DiagnosticsEngine::ak_qualtype_pair:
545 case clang::DiagnosticsEngine::ak_attr:
546 Builder << reinterpret_cast<Attr *>(
Info.getRawArg(Index));
548 case clang::DiagnosticsEngine::ak_attr_info:
549 Builder << reinterpret_cast<AttributeCommonInfo *>(
Info.getRawArg(Index));
551 case clang::DiagnosticsEngine::ak_addrspace:
552 Builder << static_cast<LangAS>(
Info.getRawArg(Index));
554 case clang::DiagnosticsEngine::ak_expr:
555 Builder << reinterpret_cast<const Expr *>(
Info.getRawArg(Index));
560void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location,
561 const SourceManager &Sources) {
563 if (!Location.isValid()) {
564 LastErrorRelatesToUserCode =
true;
565 LastErrorPassesLineFilter =
true;
569 if (!*Context.getOptions().SystemHeaders &&
570 (Sources.isInSystemHeader(Location) || Sources.isInSystemMacro(Location)))
576 FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
577 OptionalFileEntryRef
File = Sources.getFileEntryRefForID(FID);
582 LastErrorRelatesToUserCode =
true;
583 LastErrorPassesLineFilter =
true;
587 StringRef FileName(
File->getName());
588 LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
589 Sources.isInMainFile(Location) ||
590 (getHeaderFilter()->match(FileName) &&
591 !getExcludeHeaderFilter()->match(FileName));
593 unsigned LineNumber = Sources.getExpansionLineNumber(Location);
594 LastErrorPassesLineFilter =
595 LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
598llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
601 std::make_unique<llvm::Regex>(*Context.getOptions().HeaderFilterRegex);
602 return HeaderFilter.get();
605llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() {
606 if (!ExcludeHeaderFilter)
607 ExcludeHeaderFilter = std::make_unique<llvm::Regex>(
608 *Context.getOptions().ExcludeHeaderFilterRegex);
609 return ExcludeHeaderFilter.get();
612void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() {
629 Event(
unsigned Begin,
unsigned End, EventType Type,
unsigned ErrorId,
659 Priority = std::make_tuple(Begin, Type, -End, -ErrorSize, ErrorId);
662 Priority = std::make_tuple(Begin, Type, -End, ErrorSize, ErrorId);
665 Priority = std::make_tuple(End, Type, -Begin, ErrorSize, ErrorId);
670 bool operator<(
const Event &Other)
const {
671 return Priority < Other.Priority;
680 std::tuple<unsigned, EventType, int, int, unsigned> Priority;
683 removeDuplicatedDiagnosticsOfAliasCheckers();
686 std::vector<int> Sizes;
688 std::pair<ClangTidyError *, llvm::StringMap<tooling::Replacements> *>>
690 for (
auto &Error : Errors) {
691 if (
const auto *
Fix =
getFixIt(Error, GetFixesFromNotes))
692 ErrorFixes.emplace_back(
693 &Error,
const_cast<llvm::StringMap<tooling::Replacements> *
>(
Fix));
695 for (
const auto &ErrorAndFix : ErrorFixes) {
697 for (
const auto &FileAndReplaces : *ErrorAndFix.second) {
698 for (
const auto &Replace : FileAndReplaces.second)
699 Size += Replace.getLength();
701 Sizes.push_back(Size);
705 llvm::StringMap<std::vector<Event>> FileEvents;
706 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
707 for (
const auto &FileAndReplace : *ErrorFixes[I].second) {
708 for (
const auto &Replace : FileAndReplace.second) {
709 unsigned Begin = Replace.getOffset();
710 unsigned End = Begin + Replace.getLength();
711 auto &Events = FileEvents[Replace.getFilePath()];
713 Events.emplace_back(Begin, End, Event::ET_Insert, I, Sizes[I]);
715 Events.emplace_back(Begin, End, Event::ET_Begin, I, Sizes[I]);
716 Events.emplace_back(Begin, End, Event::ET_End, I, Sizes[I]);
722 llvm::BitVector Apply(ErrorFixes.size(),
true);
723 for (
auto &FileAndEvents : FileEvents) {
724 std::vector<Event> &Events = FileAndEvents.second;
727 int OpenIntervals = 0;
728 for (
const auto &Event : Events) {
729 switch (
Event.Type) {
730 case Event::ET_Begin:
731 if (OpenIntervals++ != 0)
732 Apply[
Event.ErrorId] =
false;
734 case Event::ET_Insert:
735 if (OpenIntervals != 0)
736 Apply[
Event.ErrorId] =
false;
739 if (--OpenIntervals != 0)
740 Apply[
Event.ErrorId] =
false;
744 assert(OpenIntervals == 0 &&
"Amount of begin/end points doesn't match");
747 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
749 ErrorFixes[I].second->clear();
750 ErrorFixes[I].first->Notes.emplace_back(
751 "this fix will not be applied because it overlaps with another fix");
757struct LessClangTidyError {
758 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
759 const tooling::DiagnosticMessage &M1 = LHS.Message;
760 const tooling::DiagnosticMessage &M2 = RHS.Message;
762 return std::tie(M1.FilePath, M1.FileOffset, LHS.DiagnosticName,
764 std::tie(M2.FilePath, M2.FileOffset, RHS.DiagnosticName, M2.Message);
767struct EqualClangTidyError {
768 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
769 LessClangTidyError Less;
770 return !Less(LHS, RHS) && !Less(RHS, LHS);
778 llvm::stable_sort(Errors, LessClangTidyError());
779 Errors.erase(llvm::unique(Errors, EqualClangTidyError()), Errors.end());
780 if (RemoveIncompatibleErrors)
781 removeIncompatibleErrors();
782 return std::move(Errors);
786struct LessClangTidyErrorWithoutDiagnosticName {
788 const tooling::DiagnosticMessage &M1 = LHS->Message;
789 const tooling::DiagnosticMessage &M2 = RHS->Message;
791 return std::tie(M1.FilePath, M1.FileOffset, M1.Message) <
792 std::tie(M2.FilePath, M2.FileOffset, M2.Message);
797void ClangTidyDiagnosticConsumer::removeDuplicatedDiagnosticsOfAliasCheckers() {
798 using UniqueErrorSet =
799 std::set<ClangTidyError *, LessClangTidyErrorWithoutDiagnosticName>;
800 UniqueErrorSet UniqueErrors;
802 auto IT = Errors.begin();
803 while (IT != Errors.end()) {
804 ClangTidyError &
Error = *IT;
805 std::pair<UniqueErrorSet::iterator, bool> Inserted =
806 UniqueErrors.insert(&Error);
809 if (Inserted.second) {
812 ClangTidyError &ExistingError = **Inserted.first;
813 const llvm::StringMap<tooling::Replacements> &CandidateFix =
815 const llvm::StringMap<tooling::Replacements> &ExistingFix =
816 (*Inserted.first)->Message.Fix;
818 if (CandidateFix != ExistingFix) {
821 ExistingError.Message.Fix.clear();
822 ExistingError.Notes.emplace_back(
823 llvm::formatv(
"cannot apply fix-it because an alias checker has "
824 "suggested a different fix-it; please remove one of "
825 "the checkers ('{0}', '{1}') or "
826 "ensure they are both configured the same",
827 ExistingError.DiagnosticName,
Error.DiagnosticName)
831 if (
Error.IsWarningAsError)
832 ExistingError.IsWarningAsError =
true;
835 ExistingError.EnabledDiagnosticAliases.emplace_back(
Error.DiagnosticName);
836 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.
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.
ClangTidyContext(std::unique_ptr< ClangTidyOptionsProvider > OptionsProvider, bool AllowEnablingAnalyzerAlphaCheckers=false, bool EnableModuleHeadersParsing=false)
Initializes ClangTidyContext instance.
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).