17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringTable.h"
20#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/Path.h"
32struct StaticDiagInfoRec;
37struct StaticDiagInfoDescriptionStringTable {
38#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
39 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
40 char ENUM##_desc[sizeof(DESC)];
45const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
46#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
47 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
53extern const StaticDiagInfoRec StaticDiagInfo[];
57const uint32_t StaticDiagInfoDescriptionOffsets[] = {
58#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
59 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
60 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
70 CLASS_EXTENSION = 0x04,
74struct StaticDiagInfoRec {
77 uint8_t DefaultSeverity : 3;
78 LLVM_PREFERRED_TYPE(DiagnosticClass)
83 LLVM_PREFERRED_TYPE(
bool)
84 uint8_t WarnNoWerror : 1;
85 LLVM_PREFERRED_TYPE(
bool)
86 uint8_t WarnShowInSystemHeader : 1;
87 LLVM_PREFERRED_TYPE(
bool)
88 uint8_t WarnShowInSystemMacro : 1;
90 uint16_t OptionGroupIndex : 15;
91 LLVM_PREFERRED_TYPE(
bool)
92 uint16_t Deferrable : 1;
94 uint16_t DescriptionLen;
96 unsigned getOptionGroupIndex()
const {
97 return OptionGroupIndex;
100 StringRef getDescription()
const {
101 size_t MyIndex =
this - &StaticDiagInfo[0];
102 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];
103 const char* Table =
reinterpret_cast<const char*
>(&StaticDiagInfoDescriptions);
104 return StringRef(&Table[StringOffset], DescriptionLen);
108 return Class == CLASS_REMARK ? diag::Flavor::Remark
109 : diag::Flavor::WarningOrError;
112 bool operator<(
const StaticDiagInfoRec &RHS)
const {
113 return DiagID < RHS.DiagID;
117#define STRINGIFY_NAME(NAME) #NAME
118#define VALIDATE_DIAG_SIZE(NAME) \
120 static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
121 static_cast<unsigned>(diag::DIAG_START_##NAME) + \
122 static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
124 DIAG_SIZE_##NAME) " is insufficient to contain all " \
125 "diagnostics, it may need to be made larger in " \
140#undef VALIDATE_DIAG_SIZE
143const StaticDiagInfoRec StaticDiagInfo[] = {
145#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
146 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
151 DiagnosticIDs::SFINAE, \
158 STR_SIZE(DESC, uint16_t)},
159#include "clang/Basic/DiagnosticCommonKinds.inc"
160#include "clang/Basic/DiagnosticDriverKinds.inc"
161#include "clang/Basic/DiagnosticFrontendKinds.inc"
162#include "clang/Basic/DiagnosticSerializationKinds.inc"
163#include "clang/Basic/DiagnosticLexKinds.inc"
164#include "clang/Basic/DiagnosticParseKinds.inc"
165#include "clang/Basic/DiagnosticASTKinds.inc"
166#include "clang/Basic/DiagnosticCommentKinds.inc"
167#include "clang/Basic/DiagnosticCrossTUKinds.inc"
168#include "clang/Basic/DiagnosticSemaKinds.inc"
169#include "clang/Basic/DiagnosticAnalysisKinds.inc"
170#include "clang/Basic/DiagnosticRefactoringKinds.inc"
171#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
184 using namespace diag;
185 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
197 unsigned ID = DiagID - DIAG_START_COMMON - 1;
198#define CATEGORY(NAME, PREV) \
199 if (DiagID > DIAG_START_##NAME) { \
200 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
201 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
223 const StaticDiagInfoRec *
Found = &StaticDiagInfo[ID + Offset];
227 if (
Found->DiagID != DiagID)
236 if (
const StaticDiagInfoRec *StaticInfo =
GetDiagInfo(DiagID)) {
239 if (StaticInfo->WarnNoWerror) {
241 "Unexpected mapping with no-Werror bit!");
252 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
253 return Info->Category;
259 struct StaticDiagCategoryRec {
264 return StringRef(NameStr,
NameLen);
270#define GET_CATEGORY_TABLE
271#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
272#include "clang/Basic/DiagnosticGroups.inc"
273#undef GET_CATEGORY_TABLE
295 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
301 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
302 return Info->Deferrable;
309 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
321 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
322 std::vector<DiagDesc> DiagInfo;
323 std::map<DiagDesc, unsigned> DiagIDs;
330 "Invalid diagnostic ID");
337 "Invalid diagnostic ID");
343 DiagDesc
D(L, std::string(Message));
345 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(
D);
346 if (I != DiagIDs.end() && I->first ==
D)
351 DiagIDs.insert(std::make_pair(
D, ID));
352 DiagInfo.push_back(
D);
378 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *
this);
404 bool &EnabledByDefault) {
424 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
425 return Info->getDescription();
426 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
427 return CustomDiagInfo->getDescription(DiagID);
443 llvm_unreachable(
"unexpected severity");
454 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
455 return CustomDiagInfo->getLevel(DiagID);
479 DiagnosticsEngine::DiagState *State =
Diag.GetDiagStateForLoc(
Loc);
494 bool EnabledByDefault =
false;
496 if (
Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
501 if (IsExtensionDiag && !Mapping.
isUser())
513 if (State->IgnoreAllWarnings) {
535 DiagID != diag::fatal_too_many_errors &&
Diag.FatalsAsError)
540 if (!
Diag.hasSourceManager())
543 const auto &
SM =
Diag.getSourceManager();
545 bool ShowInSystemHeader =
551 if (State->SuppressSystemWarnings && !ShowInSystemHeader &&
Loc.
isValid() &&
552 SM.isInSystemHeader(
SM.getExpansionLoc(
Loc)))
556 bool ShowInSystemMacro =
558 if (State->SuppressSystemWarnings && !ShowInSystemMacro &&
Loc.
isValid() &&
559 SM.isInSystemMacro(
Loc))
569#define GET_DIAG_ARRAYS
570#include "clang/Basic/DiagnosticGroups.inc"
571#undef GET_DIAG_ARRAYS
574 struct WarningOption {
578 StringRef Documentation;
580 StringRef
getName()
const {
return DiagGroupNames[NameOffset]; }
586#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
587 {FlagNameOffset, Members, SubGroups, Docs},
588#include "clang/Basic/DiagnosticGroups.inc"
594 return OptionTable[
static_cast<int>(Group)].Documentation;
601std::optional<diag::Group>
603 const auto *
Found = llvm::partition_point(
604 OptionTable, [=](
const WarningOption &O) {
return O.getName() < Name; });
611 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
612 return static_cast<diag::Group>(Info->getOptionGroupIndex());
626 std::vector<std::string> Res{
"-W",
"-Wno-"};
627 for (StringRef Name : DiagGroupNames) {
631 Res.push_back((Twine(
"-W") + Name).str());
632 Res.push_back((Twine(
"-Wno-") + Name).str());
641 const WarningOption *Group,
645 if (!Group->Members && !Group->SubGroups)
651 const int16_t *
Member = DiagArrays + Group->Members;
660 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
661 for (; *SubGroups != (int16_t)-1; ++SubGroups)
672 return ::getDiagnosticsInGroup(
673 Flavor, &
OptionTable[
static_cast<unsigned>(*G)], Diags);
678 std::vector<diag::kind> &Diags) {
680 if (StaticDiagInfo[i].getFlavor() == Flavor)
681 Diags.push_back(StaticDiagInfo[i].DiagID);
687 unsigned BestDistance = Group.size() + 1;
690 if (!O.Members && !O.SubGroups)
693 unsigned Distance = O.getName().edit_distance(Group,
true, BestDistance);
694 if (Distance > BestDistance)
702 if (Distance == BestDistance) {
705 }
else if (Distance < BestDistance) {
708 BestDistance = Distance;
721 assert(
Diag.getClient() &&
"DiagnosticClient not set!");
724 unsigned DiagID = Info.getID();
726 = getDiagnosticLevel(DiagID, Info.getLocation(),
Diag);
731 ++
Diag.TrapNumErrorsOccurred;
732 if (isUnrecoverable(DiagID))
733 ++
Diag.TrapNumUnrecoverableErrorsOccurred;
736 if (
Diag.SuppressAllDiagnostics)
745 Diag.FatalErrorOccurred =
true;
747 Diag.LastDiagLevel = DiagLevel;
752 if (
Diag.FatalErrorOccurred) {
754 Diag.Client->IncludeInDiagnosticCounts()) {
769 if (isUnrecoverable(DiagID))
770 Diag.UnrecoverableErrorOccurred =
true;
774 Diag.UncompilableErrorOccurred =
true;
776 Diag.ErrorOccurred =
true;
777 if (
Diag.Client->IncludeInDiagnosticCounts()) {
783 if (
Diag.ErrorLimit &&
Diag.NumErrors >
Diag.ErrorLimit &&
785 Diag.Report(diag::fatal_too_many_errors);
792 if (Info.getID() == diag::fatal_too_many_errors)
793 Diag.FatalErrorOccurred =
true;
795 EmitDiag(
Diag, DiagBuilder, DiagLevel);
801 Level DiagLevel)
const {
806 if (
Diag.Client->IncludeInDiagnosticCounts()) {
812bool DiagnosticIDs::isUnrecoverable(
unsigned DiagID)
const {
814 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
823 if (DiagID == diag::err_unavailable ||
824 DiagID == diag::err_unavailable_message)
Includes all the separate Diagnostic headers & some related helpers.
static const StaticDiagInfoRec * GetDiagInfo(unsigned DiagID)
GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, or null if the ID is inval...
static DiagnosticIDs::Level toLevel(diag::Severity SV)
#define VALIDATE_DIAG_SIZE(NAME)
#define CATEGORY(NAME, PREV)
static const unsigned StaticDiagInfoSize
static unsigned getBuiltinDiagClass(unsigned DiagID)
getBuiltinDiagClass - Return the class field of the diagnostic.
static const WarningOption OptionTable[]
static bool getDiagnosticsInGroup(diag::Flavor Flavor, const WarningOption *Group, SmallVectorImpl< diag::kind > &Diags)
Return true if any diagnostics were found in this group, even if they were filtered out due to having...
static const StaticDiagCategoryRec CategoryNameTable[]
Defines the Diagnostic IDs-related interfaces.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static std::string getName(const CallEvent &Call)
Defines the SourceManager interface.
A little helper class used to produce diagnostics.
Used for handling and querying diagnostic IDs.
static bool isBuiltinExtensionDiag(unsigned DiagID)
Determine whether the given built-in diagnostic ID is for an extension of some sort.
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static unsigned getNumberOfCategories()
Return the number of diagnostic categories.
static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)
Get the diagnostic option with the closest edit distance to the given group name.
bool getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, SmallVectorImpl< diag::kind > &Diags) const
Get the set of all diagnostic IDs in the group with the given name.
static std::vector< std::string > getDiagnosticFlags()
Get the string of all diagnostic flags.
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID)
Determines whether the given built-in diagnostic ID is for an error that is suppressed if it occurs d...
static bool isDefaultMappingAsError(unsigned DiagID)
Return true if the specified diagnostic is mapped to errors by default.
static bool isBuiltinNote(unsigned DiagID)
Determine whether the given built-in diagnostic ID is a Note.
static bool isBuiltinWarningOrExtension(unsigned DiagID)
Return true if the unmapped diagnostic levelof the specified diagnostic ID is a Warning or Extension.
static bool isCodegenABICheckDiagnostic(unsigned DiagID)
Return true if a given diagnostic is a codegen-time ABI check.
StringRef getDescription(unsigned DiagID) const
Given a diagnostic ID, return a description of the issue.
SFINAEResponse
Enumeration describing how the emission of a diagnostic should be treated when it occurs during C++ t...
@ SFINAE_Report
The diagnostic should be reported.
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
static StringRef getWarningOptionDocumentation(diag::Group GroupID)
Given a diagnostic group ID, return its documentation.
static std::optional< diag::Group > getGroupForWarningOption(StringRef)
Given a group ID, returns the flag that toggles the group.
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
static std::optional< diag::Group > getGroupForDiag(unsigned DiagID)
Return the lowest-level group that contains the specified diagnostic.
static StringRef getWarningOptionForGroup(diag::Group)
Given a group ID, returns the flag that toggles the group.
static bool isARCDiagnostic(unsigned DiagID)
Return true if a given diagnostic falls into an ARC diagnostic category.
Level
The level of the diagnostic, after it has been through mapping.
static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)
Get the set of all diagnostic IDs.
static DiagnosticMapping getDefaultMapping(unsigned DiagID)
Get the default mapping for this diagnostic.
unsigned getCustomDiagID(Level L, StringRef FormatString)
Return an ID for a diagnostic with the specified format string and level.
static bool isDeferrable(unsigned DiagID)
Whether the diagnostic message can be deferred.
bool hasNoErrorAsFatal() const
void setNoWarningAsError(bool Value)
void setSeverity(diag::Severity Value)
diag::Severity getSeverity() const
static DiagnosticMapping Make(diag::Severity Severity, bool IsUser, bool IsPragma)
bool hasNoWarningAsError() const
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
Concrete class used by the front-end to report problems and issues.
Level
The level of the diagnostic, after it has been through mapping.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
StringRef getDescription(unsigned DiagID) const
getDescription - Return the description of the specified custom diagnostic.
unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, DiagnosticIDs &Diags)
DiagnosticIDs::Level getLevel(unsigned DiagID) const
getLevel - Return the level of the specified custom diagnostic.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
@ Warning
Present this diagnostic as a warning.
@ Fatal
Present this diagnostic as a fatal error.
@ Error
Present this diagnostic as an error.
@ Remark
Present this diagnostic as a remark.
@ Ignored
Do not present this diagnostic, ignore it.
Flavor
Flavors of diagnostics we can emit.
@ Remark
A diagnostic that indicates normal progress through compilation.
The JSON file list parser is used to communicate input to InstallAPI.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
@ Result
The result type of a method or function.
@ Class
The "class" keyword introduces the elaborated-type-specifier.