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);
242 CheckFilter = std::make_unique<CachedGlobList>(
244 WarningAsErrorFilter = std::make_unique<CachedGlobList>(
246 static const std::vector<std::string> EmptyFileExtensions;
249 : EmptyFileExtensions,
250 HeaderFileExtensions))
254 : EmptyFileExtensions,
255 ImplementationFileExtensions))
260 DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
261 LangOpts = Context->getLangOpts();
265 return OptionsProvider->getGlobalOptions();
269 return CurrentOptions;
276 OptionsProvider->getOptions(File), 0);
282 ProfilePrefix = std::string(Prefix);
285std::optional<ClangTidyProfiling::StorageParams>
287 if (ProfilePrefix.empty())
294 assert(CheckFilter !=
nullptr);
295 return CheckFilter->contains(CheckName);
299 assert(WarningAsErrorFilter !=
nullptr);
300 return WarningAsErrorFilter->contains(CheckName);
304 const std::string ClangWarningOption = std::string(
305 DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID));
306 if (!ClangWarningOption.empty())
307 return "clang-diagnostic-" + ClangWarningOption;
308 const llvm::DenseMap<unsigned, std::string>::const_iterator I =
309 CheckNamesByDiagnosticID.find(DiagnosticID);
310 if (I != CheckNamesByDiagnosticID.end())
317 bool RemoveIncompatibleErrors,
bool GetFixesFromNotes,
318 bool EnableNolintBlocks)
319 : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine),
320 RemoveIncompatibleErrors(RemoveIncompatibleErrors),
321 GetFixesFromNotes(GetFixesFromNotes),
322 EnableNolintBlocks(EnableNolintBlocks) {}
324void ClangTidyDiagnosticConsumer::finalizeLastError() {
325 if (!Errors.empty()) {
327 if (Error.DiagnosticName ==
"clang-tidy-config") {
330 Error.DiagLevel != ClangTidyError::Error) {
333 }
else if (!LastErrorRelatesToUserCode) {
336 }
else if (!LastErrorPassesLineFilter) {
337 ++Context.Stats.ErrorsIgnoredLineFilter;
340 ++Context.Stats.ErrorsDisplayed;
343 LastErrorRelatesToUserCode =
false;
344 LastErrorPassesLineFilter =
false;
347namespace clang::tidy {
349const llvm::StringMap<tooling::Replacements> *
350getFixIt(
const tooling::Diagnostic &Diagnostic,
bool AnyFix) {
351 if (!Diagnostic.Message.Fix.empty())
352 return &Diagnostic.Message.Fix;
355 const llvm::StringMap<tooling::Replacements> *Result =
nullptr;
356 for (
const auto &Note : Diagnostic.Notes) {
357 if (!Note.Fix.empty()) {
370 const Preprocessor *PP) {
371 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
373 assert(!InSourceFile);
378 assert(InSourceFile);
379 InSourceFile =
false;
381 DiagnosticConsumer::EndSourceFile();
385 DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
388 assert(InSourceFile || Info.getLocation().isInvalid());
390 if (LastErrorWasIgnored && DiagLevel == DiagnosticsEngine::Note)
393 SmallVector<tooling::Diagnostic, 1> SuppressionErrors;
394 if (Context.shouldSuppressDiagnostic(DiagLevel, Info, SuppressionErrors,
395 EnableNolintBlocks)) {
396 ++Context.Stats.ErrorsIgnoredNOLINT;
398 LastErrorWasIgnored =
true;
399 for (
const auto &Error : SuppressionErrors)
404 LastErrorWasIgnored =
false;
406 DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
408 if (DiagLevel == DiagnosticsEngine::Note) {
409 assert(!Errors.empty() &&
410 "A diagnostic note can only be appended to a message.");
413 std::string CheckName = Context.getCheckName(Info.getID());
414 if (CheckName.empty()) {
418 case DiagnosticsEngine::Error:
419 case DiagnosticsEngine::Fatal:
420 CheckName =
"clang-diagnostic-error";
422 case DiagnosticsEngine::Warning:
423 CheckName =
"clang-diagnostic-warning";
425 case DiagnosticsEngine::Remark:
426 CheckName =
"clang-diagnostic-remark";
429 CheckName =
"clang-diagnostic-unknown";
434 ClangTidyError::Level Level = ClangTidyError::Warning;
435 if (DiagLevel == DiagnosticsEngine::Error ||
436 DiagLevel == DiagnosticsEngine::Fatal) {
439 Level = ClangTidyError::Error;
440 LastErrorRelatesToUserCode =
true;
441 LastErrorPassesLineFilter =
true;
442 }
else if (DiagLevel == DiagnosticsEngine::Remark) {
443 Level = ClangTidyError::Remark;
446 const bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning &&
447 Context.treatAsError(CheckName);
448 Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(),
452 if (ExternalDiagEngine) {
455 forwardDiagnostic(Info);
457 ClangTidyDiagnosticRenderer Converter(
458 Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
460 SmallString<100> Message;
461 Info.FormatDiagnostic(Message);
463 if (Info.hasSourceManager())
464 Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
465 else if (Context.DiagEngine->hasSourceManager())
466 Loc = FullSourceLoc(Info.getLocation(),
467 Context.DiagEngine->getSourceManager());
468 Converter.emitDiagnostic(Loc, DiagLevel, Message, Info.getRanges(),
469 Info.getFixItHints());
472 if (Info.hasSourceManager())
473 checkFilters(Info.getLocation(), Info.getSourceManager());
475 for (
const auto &Error : SuppressionErrors)
479bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
480 unsigned LineNumber)
const {
484 if (FileName.ends_with(Filter.Name)) {
485 if (Filter.LineRanges.empty())
489 return Range.first <= LineNumber && LineNumber <= Range.second;
496void ClangTidyDiagnosticConsumer::forwardDiagnostic(
const Diagnostic &Info) {
498 auto DiagLevelAndFormatString =
499 Context.getDiagLevelAndFormatString(
Info.getID(),
Info.getLocation());
500 const unsigned ExternalID =
501 ExternalDiagEngine->getDiagnosticIDs()->getCustomDiagID(
502 DiagLevelAndFormatString.first, DiagLevelAndFormatString.second);
505 auto Builder = ExternalDiagEngine->Report(
Info.getLocation(), ExternalID);
506 for (
const FixItHint &Hint :
Info.getFixItHints())
508 for (
auto Range :
Info.getRanges())
510 for (
unsigned Index = 0; Index <
Info.getNumArgs(); ++Index) {
511 const DiagnosticsEngine::ArgumentKind Kind =
Info.getArgKind(Index);
513 case clang::DiagnosticsEngine::ak_std_string:
514 Builder <<
Info.getArgStdStr(Index);
516 case clang::DiagnosticsEngine::ak_c_string:
517 Builder <<
Info.getArgCStr(Index);
519 case clang::DiagnosticsEngine::ak_sint:
520 Builder <<
Info.getArgSInt(Index);
522 case clang::DiagnosticsEngine::ak_uint:
523 Builder <<
Info.getArgUInt(Index);
525 case clang::DiagnosticsEngine::ak_tokenkind:
526 Builder << static_cast<tok::TokenKind>(
Info.getRawArg(Index));
528 case clang::DiagnosticsEngine::ak_identifierinfo:
529 Builder <<
Info.getArgIdentifier(Index);
531 case clang::DiagnosticsEngine::ak_qual:
532 Builder << Qualifiers::fromOpaqueValue(
Info.getRawArg(Index));
534 case clang::DiagnosticsEngine::ak_qualtype:
535 Builder << QualType::getFromOpaquePtr(
536 reinterpret_cast<void *
>(
Info.getRawArg(Index)));
538 case clang::DiagnosticsEngine::ak_declarationname:
539 Builder << DeclarationName::getFromOpaqueInteger(
Info.getRawArg(Index));
541 case clang::DiagnosticsEngine::ak_nameddecl:
542 Builder << reinterpret_cast<const NamedDecl *>(
Info.getRawArg(Index));
544 case clang::DiagnosticsEngine::ak_nestednamespec:
545 Builder << NestedNameSpecifier::getFromVoidPointer(
546 reinterpret_cast<void *
>(
Info.getRawArg(Index)));
548 case clang::DiagnosticsEngine::ak_declcontext:
549 Builder << reinterpret_cast<DeclContext *>(
Info.getRawArg(Index));
551 case clang::DiagnosticsEngine::ak_qualtype_pair:
554 case clang::DiagnosticsEngine::ak_attr:
555 Builder << reinterpret_cast<Attr *>(
Info.getRawArg(Index));
557 case clang::DiagnosticsEngine::ak_attr_info:
558 Builder << reinterpret_cast<AttributeCommonInfo *>(
Info.getRawArg(Index));
560 case clang::DiagnosticsEngine::ak_addrspace:
561 Builder << static_cast<LangAS>(
Info.getRawArg(Index));
563 case clang::DiagnosticsEngine::ak_expr:
564 Builder << reinterpret_cast<const Expr *>(
Info.getRawArg(Index));
569void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location,
570 const SourceManager &Sources) {
572 if (!Location.isValid()) {
573 LastErrorRelatesToUserCode =
true;
574 LastErrorPassesLineFilter =
true;
578 if (!Context.getOptions().SystemHeaders.value_or(
false) &&
579 (Sources.isInSystemHeader(Location) || Sources.isInSystemMacro(Location)))
585 const FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
586 OptionalFileEntryRef
File = Sources.getFileEntryRefForID(FID);
591 LastErrorRelatesToUserCode =
true;
592 LastErrorPassesLineFilter =
true;
596 const StringRef FileName(
File->getName());
597 LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
598 Sources.isInMainFile(Location) ||
599 (getHeaderFilter()->match(FileName) &&
600 !getExcludeHeaderFilter()->match(FileName));
602 const unsigned LineNumber = Sources.getExpansionLineNumber(Location);
603 LastErrorPassesLineFilter =
604 LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
607llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
609 HeaderFilter = std::make_unique<llvm::Regex>(
610 Context.getOptions().HeaderFilterRegex.value_or(
""));
611 return HeaderFilter.get();
614llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() {
615 if (!ExcludeHeaderFilter)
616 ExcludeHeaderFilter = std::make_unique<llvm::Regex>(
617 Context.getOptions().ExcludeHeaderFilterRegex.value_or(
""));
618 return ExcludeHeaderFilter.get();
621void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() {
638 Event(
unsigned Begin,
unsigned End, EventType Type,
unsigned ErrorId,
668 Priority = {Begin,
Type, -End, -ErrorSize, ErrorId};
671 Priority = {Begin,
Type, -End, ErrorSize, ErrorId};
674 Priority = {End,
Type, -Begin, ErrorSize, ErrorId};
679 bool operator<(
const Event &Other)
const {
680 return Priority < Other.Priority;
689 std::tuple<unsigned, EventType, int, int, unsigned> Priority;
693 std::vector<int> Sizes;
695 std::pair<ClangTidyError *, llvm::StringMap<tooling::Replacements> *>>
697 for (
auto &Error : Errors)
698 if (
const auto *
Fix =
getFixIt(Error, GetFixesFromNotes))
699 ErrorFixes.emplace_back(
700 &Error,
const_cast<llvm::StringMap<tooling::Replacements> *
>(
Fix));
701 for (
const auto &ErrorAndFix : ErrorFixes) {
703 for (
const auto &FileAndReplaces : *ErrorAndFix.second)
704 for (
const auto &Replace : FileAndReplaces.second)
705 Size += Replace.getLength();
706 Sizes.push_back(Size);
710 llvm::StringMap<std::vector<Event>> FileEvents;
711 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
712 for (
const auto &FileAndReplace : *ErrorFixes[I].second) {
713 for (
const auto &Replace : FileAndReplace.second) {
714 const unsigned Begin = Replace.getOffset();
715 const unsigned End = Begin + Replace.getLength();
716 auto &Events = FileEvents[Replace.getFilePath()];
718 Events.emplace_back(Begin, End, Event::ET_Insert, I, Sizes[I]);
720 Events.emplace_back(Begin, End, Event::ET_Begin, I, Sizes[I]);
721 Events.emplace_back(Begin, End, Event::ET_End, I, Sizes[I]);
727 llvm::BitVector Apply(ErrorFixes.size(),
true);
728 for (
auto &FileAndEvents : FileEvents) {
729 std::vector<Event> &Events = FileAndEvents.second;
732 int OpenIntervals = 0;
733 for (
const auto &Event : Events) {
734 switch (
Event.Type) {
735 case Event::ET_Begin:
736 if (OpenIntervals++ != 0)
737 Apply[
Event.ErrorId] =
false;
739 case Event::ET_Insert:
740 if (OpenIntervals != 0)
741 Apply[
Event.ErrorId] =
false;
744 if (--OpenIntervals != 0)
745 Apply[
Event.ErrorId] =
false;
749 assert(OpenIntervals == 0 &&
"Amount of begin/end points doesn't match");
752 for (
unsigned I = 0; I < ErrorFixes.size(); ++I) {
754 ErrorFixes[I].second->clear();
755 ErrorFixes[I].first->Notes.emplace_back(
756 "this fix will not be applied because it overlaps with another fix");
762struct LessClangTidyError {
763 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
764 const tooling::DiagnosticMessage &M1 = LHS.Message;
765 const tooling::DiagnosticMessage &M2 = RHS.Message;
770 return std::tie(M1.FilePath, M1.FileOffset, M1.Message,
771 LHS.DiagnosticName) <
772 std::tie(M2.FilePath, M2.FileOffset, M2.Message, RHS.DiagnosticName);
775struct EqualClangTidyError {
776 bool operator()(
const ClangTidyError &LHS,
const ClangTidyError &RHS)
const {
777 const LessClangTidyError Less;
778 return !Less(LHS, RHS) && !Less(RHS, LHS);
786 llvm::stable_sort(Errors, LessClangTidyError());
787 Errors.erase(llvm::unique(Errors, EqualClangTidyError()), Errors.end());
788 if (RemoveIncompatibleErrors) {
789 removeDuplicatedDiagnosticsOfAliasCheckers();
790 removeIncompatibleErrors();
792 return std::move(Errors);
795void ClangTidyDiagnosticConsumer::removeDuplicatedDiagnosticsOfAliasCheckers() {
796 if (Errors.size() <= 1)
799 static constexpr auto AreDuplicates = [](
const ClangTidyError &E1,
801 const tooling::DiagnosticMessage &M1 = E1.Message;
802 const tooling::DiagnosticMessage &M2 = E2.Message;
803 return std::tie(M1.FilePath, M1.FileOffset, M1.Message) ==
804 std::tie(M2.FilePath, M2.FileOffset, M2.Message);
807 auto LastUniqueErrorIt = Errors.begin();
811 if (!AreDuplicates(Error, ExistingError)) {
813 if (&*LastUniqueErrorIt != &Error)
814 *LastUniqueErrorIt = std::move(Error);
816 const llvm::StringMap<tooling::Replacements> &CandidateFix =
818 const llvm::StringMap<tooling::Replacements> &ExistingFix =
819 ExistingError.Message.Fix;
821 if (CandidateFix != ExistingFix) {
823 ExistingError.Message.Fix.clear();
824 ExistingError.Notes.emplace_back(
825 llvm::formatv(
"cannot apply fix-it because an alias checker has "
826 "suggested a different fix-it; please remove one of "
827 "the checkers ('{0}', '{1}') or "
828 "ensure they are both configured the same",
829 ExistingError.DiagnosticName, Error.DiagnosticName)
833 if (
Error.IsWarningAsError)
840 Errors.erase(std::next(LastUniqueErrorIt), Errors.end());
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< std::string > EnabledDiagnosticAliases
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).