clang: lib/Basic/DiagnosticIDs.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/Support/ErrorHandling.h"
20#include "llvm/Support/Path.h"
21#include
22#include
23using namespace clang;
24
25
26
27
28
29namespace {
30
31struct StaticDiagInfoRec;
32
33
34
35
36struct StaticDiagInfoDescriptionStringTable {
37#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
38 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
39 char ENUM##_desc[sizeof(DESC)];
41#undef DIAG
42};
43
44const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
45#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
46 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
47 DESC,
49#undef DIAG
50};
51
52extern const StaticDiagInfoRec StaticDiagInfo[];
53
54
55
56const uint32_t StaticDiagInfoDescriptionOffsets[] = {
57#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
58 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
59 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
61#undef DIAG
62};
63
64
65enum DiagnosticClass {
66 CLASS_NOTE = 0x01,
67 CLASS_REMARK = 0x02,
68 CLASS_WARNING = 0x03,
69 CLASS_EXTENSION = 0x04,
70 CLASS_ERROR = 0x05
71};
72
73struct StaticDiagInfoRec {
74 uint16_t DiagID;
76 uint8_t DefaultSeverity : 3;
77 LLVM_PREFERRED_TYPE(DiagnosticClass)
78 uint8_t Class : 3;
80 uint8_t SFINAE : 2;
82 LLVM_PREFERRED_TYPE(bool)
83 uint8_t WarnNoWerror : 1;
84 LLVM_PREFERRED_TYPE(bool)
85 uint8_t WarnShowInSystemHeader : 1;
86 LLVM_PREFERRED_TYPE(bool)
87 uint8_t WarnShowInSystemMacro : 1;
88
89 uint16_t OptionGroupIndex : 15;
90 LLVM_PREFERRED_TYPE(bool)
91 uint16_t Deferrable : 1;
92
93 uint16_t DescriptionLen;
94
95 unsigned getOptionGroupIndex() const {
96 return OptionGroupIndex;
97 }
98
99 StringRef getDescription() const {
100 size_t MyIndex = this - &StaticDiagInfo[0];
101 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];
102 const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions);
103 return StringRef(&Table[StringOffset], DescriptionLen);
104 }
105
107 return Class == CLASS_REMARK ? diag::Flavor::Remark
108 : diag::Flavor::WarningOrError;
109 }
110
111 bool operator<(const StaticDiagInfoRec &RHS) const {
112 return DiagID < RHS.DiagID;
113 }
114};
115
116#define STRINGIFY_NAME(NAME) #NAME
117#define VALIDATE_DIAG_SIZE(NAME) \
118 static_assert( \
119 static_cast(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
120 static_cast(diag::DIAG_START_##NAME) + \
121 static_cast(diag::DIAG_SIZE_##NAME), \
122 STRINGIFY_NAME( \
123 DIAG_SIZE_##NAME) " is insufficient to contain all " \
124 "diagnostics, it may need to be made larger in " \
125 "DiagnosticIDs.h.");
139#undef VALIDATE_DIAG_SIZE
140#undef STRINGIFY_NAME
141
142const StaticDiagInfoRec StaticDiagInfo[] = {
143
144#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
145 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
146 { \
147 diag::ENUM, \
148 DEFAULT_SEVERITY, \
149 CLASS, \
150 DiagnosticIDs::SFINAE, \
151 CATEGORY, \
152 NOWERROR, \
153 SHOWINSYSHEADER, \
154 SHOWINSYSMACRO, \
155 GROUP, \
156 DEFERRABLE, \
157 STR_SIZE(DESC, uint16_t)},
158#include "clang/Basic/DiagnosticCommonKinds.inc"
159#include "clang/Basic/DiagnosticDriverKinds.inc"
160#include "clang/Basic/DiagnosticFrontendKinds.inc"
161#include "clang/Basic/DiagnosticSerializationKinds.inc"
162#include "clang/Basic/DiagnosticLexKinds.inc"
163#include "clang/Basic/DiagnosticParseKinds.inc"
164#include "clang/Basic/DiagnosticASTKinds.inc"
165#include "clang/Basic/DiagnosticCommentKinds.inc"
166#include "clang/Basic/DiagnosticCrossTUKinds.inc"
167#include "clang/Basic/DiagnosticSemaKinds.inc"
168#include "clang/Basic/DiagnosticAnalysisKinds.inc"
169#include "clang/Basic/DiagnosticRefactoringKinds.inc"
170#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
171
172#undef DIAG
173};
174
175}
176
178
179
180
181static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
182
183 using namespace diag;
184 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
185 return nullptr;
186
187
188
189
190
191
192
193
194
195 unsigned Offset = 0;
196 unsigned ID = DiagID - DIAG_START_COMMON - 1;
197#define CATEGORY(NAME, PREV) \
198 if (DiagID > DIAG_START_##NAME) { \
199 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
200 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
201 }
204CATEGORY(SERIALIZATION, FRONTEND)
212CATEGORY(REFACTORING, ANALYSIS)
213CATEGORY(INSTALLAPI, REFACTORING)
214#undef CATEGORY
215
216
218 return nullptr;
219
221
222 const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
223
224
225
226 if (Found->DiagID != DiagID)
227 return nullptr;
229}
230
234
235 if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
237
238 if (StaticInfo->WarnNoWerror) {
240 "Unexpected mapping with no-Werror bit!");
242 }
243 }
244
245 return Info;
246}
247
248
249
251 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
252 return Info->Category;
253 return 0;
254}
255
256namespace {
257
258 struct StaticDiagCategoryRec {
259 const char *NameStr;
261
262 StringRef getName() const {
263 return StringRef(NameStr, NameLen);
264 }
265 };
266}
267
269#define GET_CATEGORY_TABLE
270#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
271#include "clang/Basic/DiagnosticGroups.inc"
272#undef GET_CATEGORY_TABLE
273 { nullptr, 0 }
274};
275
276
279}
280
281
282
283
286 return StringRef();
288}
289
290
291
294 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
297}
298
300 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
301 return Info->Deferrable;
302 return false;
303}
304
305
306
308 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
309 return Info->Class;
310 return ~0U;
311}
312
313
314
315
316
318 namespace diag {
320 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
321 std::vector DiagInfo;
322 std::map<DiagDesc, unsigned> DiagIDs;
323 public:
324
325
326
329 "Invalid diagnostic ID");
331 }
332
333
336 "Invalid diagnostic ID");
338 }
339
342 DiagDesc D(L, std::string(Message));
343
344 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
345 if (I != DiagIDs.end() && I->first == D)
346 return I->second;
347
348
350 DiagIDs.insert(std::make_pair(D, ID));
351 DiagInfo.push_back(D);
352 return ID;
353 }
354 };
355
356 }
357}
358
359
360
361
362
363
365
367
368
369
370
371
372
373
375 if (!CustomDiagInfo)
377 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
378}
379
380
381
382
383
384
388}
389
390
391
395}
396
397
398
399
400
401
403 bool &EnabledByDefault) {
406 return false;
407
408 EnabledByDefault =
410 return true;
411}
412
415 return false;
416
418}
419
420
421
423 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
424 return Info->getDescription();
425 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
426 return CustomDiagInfo->getDescription(DiagID);
427}
428
430 switch (SV) {
441 }
442 llvm_unreachable("unexpected severity");
443}
444
445
446
447
449DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
451
453 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
454 return CustomDiagInfo->getLevel(DiagID);
455 }
456
459 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
460}
461
462
463
464
465
466
467
469DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
472
473
474
476
477
478 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
480
481
484
485
489
490
491
492
493 bool EnabledByDefault = false;
495 if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
497
498
499
500 if (IsExtensionDiag && !Mapping.isUser())
501 Result = std::max(Result, State->ExtBehavior);
502
503
506
507
508
509
510
511
512 if (State->IgnoreAllWarnings) {
517 }
518
519
523 }
524
525
526
530 }
531
532
534 DiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
536
537
538
539 if (.hasSourceManager())
541
542 const auto &SM = Diag.getSourceManager();
543
544 bool ShowInSystemHeader =
546
547
548
549
550 if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
551 SM.isInSystemHeader(SM.getExpansionLoc(Loc)))
553
554
555 bool ShowInSystemMacro =
557 if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&
560
561
562 if (!Mapping.isPragma() && Diag.isSuppressedViaMapping(DiagID, Loc))
564
566}
567
568#define GET_DIAG_ARRAYS
569#include "clang/Basic/DiagnosticGroups.inc"
570#undef GET_DIAG_ARRAYS
571
572namespace {
573 struct WarningOption {
574 uint16_t NameOffset;
575 uint16_t Members;
576 uint16_t SubGroups;
577 StringRef Documentation;
578
579
580 StringRef getName() const {
581 return StringRef(DiagGroupNames + NameOffset + 1,
582 DiagGroupNames[NameOffset]);
583 }
584 };
585}
586
587
589#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
590 {FlagNameOffset, Members, SubGroups, Docs},
591#include "clang/Basic/DiagnosticGroups.inc"
592#undef DIAG_ENTRY
593};
594
595
597 return OptionTable[static_cast<int>(Group)].Documentation;
598}
599
602}
603
604std::optionaldiag::Group
606 const auto *Found = llvm::partition_point(
607 OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });
609 return std::nullopt;
611}
612
614 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
615 return static_cast<diag::Group>(Info->getOptionGroupIndex());
616 return std::nullopt;
617}
618
619
620
621
625 return StringRef();
626}
627
629 std::vectorstd::string Res{"-W", "-Wno-"};
630 for (size_t I = 1; DiagGroupNames[I] != '\0';) {
631 std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
632 I += DiagGroupNames[I] + 1;
633 Res.push_back("-W" + Diag);
634 Res.push_back("-Wno-" + Diag);
635 }
636
637 return Res;
638}
639
640
641
643 const WarningOption *Group,
645
646
647 if (!Group->Members && !Group->SubGroups)
649
651
652
653 const int16_t *Member = DiagArrays + Group->Members;
655 if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
657 Diags.push_back(*Member);
658 }
659 }
660
661
662 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
663 for (; *SubGroups != (int16_t)-1; ++SubGroups)
665 Diags);
666
668}
669
670bool
674 return ::getDiagnosticsInGroup(
675 Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
676 return true;
677}
678
680 std::vectordiag::kind &Diags) {
682 if (StaticDiagInfo[i].getFlavor() == Flavor)
683 Diags.push_back(StaticDiagInfo[i].DiagID);
684}
685
687 StringRef Group) {
688 StringRef Best;
689 unsigned BestDistance = Group.size() + 1;
690 for (const WarningOption &O : OptionTable) {
691
692 if (!O.Members && !O.SubGroups)
693 continue;
694
695 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
696 if (Distance > BestDistance)
697 continue;
698
699
702 continue;
703
704 if (Distance == BestDistance) {
705
706 Best = "";
707 } else if (Distance < BestDistance) {
708
709 Best = O.getName();
710 BestDistance = Distance;
711 }
712 }
713
714 return Best;
715}
716
717
718
722
723 assert(Diag.getClient() && "DiagnosticClient not set!");
724
725
726 unsigned DiagID = Info.getID();
728 = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
729
730
731
733 ++Diag.TrapNumErrorsOccurred;
734 if (isUnrecoverable(DiagID))
735 ++Diag.TrapNumUnrecoverableErrorsOccurred;
736 }
737
738 if (Diag.SuppressAllDiagnostics)
739 return false;
740
742
743
744
745
747 Diag.FatalErrorOccurred = true;
748
749 Diag.LastDiagLevel = DiagLevel;
750 }
751
752
753
754 if (Diag.FatalErrorOccurred) {
756 Diag.Client->IncludeInDiagnosticCounts()) {
757 ++Diag.NumErrors;
758 }
759
760 return false;
761 }
762
763
764
768 return false;
769
771 if (isUnrecoverable(DiagID))
772 Diag.UnrecoverableErrorOccurred = true;
773
774
776 Diag.UncompilableErrorOccurred = true;
777
778 Diag.ErrorOccurred = true;
779 if (Diag.Client->IncludeInDiagnosticCounts()) {
780 ++Diag.NumErrors;
781 }
782
783
784
785 if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
787 Diag.Report(diag::fatal_too_many_errors);
788 return false;
789 }
790 }
791
792
793
794 if (Info.getID() == diag::fatal_too_many_errors)
795 Diag.FatalErrorOccurred = true;
796
797 EmitDiag(Diag, DiagBuilder, DiagLevel);
798 return true;
799}
800
803 Level DiagLevel) const {
806
808 if (Diag.Client->IncludeInDiagnosticCounts()) {
810 ++Diag.NumWarnings;
811 }
812}
813
814bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
816 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
817
819 }
820
821
823 return false;
824
825 if (DiagID == diag::err_unavailable ||
826 DiagID == diag::err_unavailable_message)
827 return false;
828
829
831 return false;
832
834 return false;
835
836 return true;
837}
838
842}
843
847}
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.