clang 18.0.0git
DiagnosticIDs.cpp
Go to the documentation of this file.
1//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the Diagnostic IDs-related interfaces.
10//
11//===----------------------------------------------------------------------===//
12
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/Support/ErrorHandling.h"
20#include <map>
21#include <optional>
22using namespace clang;
23
24//===----------------------------------------------------------------------===//
25// Builtin Diagnostic information
26//===----------------------------------------------------------------------===//
27
28namespace {
29
30struct StaticDiagInfoRec;
31
32// Store the descriptions in a separate table to avoid pointers that need to
33// be relocated, and also decrease the amount of data needed on 64-bit
34// platforms. See "How To Write Shared Libraries" by Ulrich Drepper.
35struct StaticDiagInfoDescriptionStringTable {
36#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
37 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
38 char ENUM##_desc[sizeof(DESC)];
39 // clang-format off
40#include "clang/Basic/DiagnosticCommonKinds.inc"
41#include "clang/Basic/DiagnosticDriverKinds.inc"
42#include "clang/Basic/DiagnosticFrontendKinds.inc"
43#include "clang/Basic/DiagnosticSerializationKinds.inc"
44#include "clang/Basic/DiagnosticLexKinds.inc"
45#include "clang/Basic/DiagnosticParseKinds.inc"
46#include "clang/Basic/DiagnosticASTKinds.inc"
47#include "clang/Basic/DiagnosticCommentKinds.inc"
48#include "clang/Basic/DiagnosticCrossTUKinds.inc"
49#include "clang/Basic/DiagnosticSemaKinds.inc"
50#include "clang/Basic/DiagnosticAnalysisKinds.inc"
51#include "clang/Basic/DiagnosticRefactoringKinds.inc"
52 // clang-format on
53#undef DIAG
54};
55
56const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
57#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
58 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
59 DESC,
60// clang-format off
61#include "clang/Basic/DiagnosticCommonKinds.inc"
62#include "clang/Basic/DiagnosticDriverKinds.inc"
63#include "clang/Basic/DiagnosticFrontendKinds.inc"
64#include "clang/Basic/DiagnosticSerializationKinds.inc"
65#include "clang/Basic/DiagnosticLexKinds.inc"
66#include "clang/Basic/DiagnosticParseKinds.inc"
67#include "clang/Basic/DiagnosticASTKinds.inc"
68#include "clang/Basic/DiagnosticCommentKinds.inc"
69#include "clang/Basic/DiagnosticCrossTUKinds.inc"
70#include "clang/Basic/DiagnosticSemaKinds.inc"
71#include "clang/Basic/DiagnosticAnalysisKinds.inc"
72#include "clang/Basic/DiagnosticRefactoringKinds.inc"
73 // clang-format on
74#undef DIAG
75};
76
77extern const StaticDiagInfoRec StaticDiagInfo[];
78
79// Stored separately from StaticDiagInfoRec to pack better. Otherwise,
80// StaticDiagInfoRec would have extra padding on 64-bit platforms.
81const uint32_t StaticDiagInfoDescriptionOffsets[] = {
82#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
83 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
84 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
85// clang-format off
86#include "clang/Basic/DiagnosticCommonKinds.inc"
87#include "clang/Basic/DiagnosticDriverKinds.inc"
88#include "clang/Basic/DiagnosticFrontendKinds.inc"
89#include "clang/Basic/DiagnosticSerializationKinds.inc"
90#include "clang/Basic/DiagnosticLexKinds.inc"
91#include "clang/Basic/DiagnosticParseKinds.inc"
92#include "clang/Basic/DiagnosticASTKinds.inc"
93#include "clang/Basic/DiagnosticCommentKinds.inc"
94#include "clang/Basic/DiagnosticCrossTUKinds.inc"
95#include "clang/Basic/DiagnosticSemaKinds.inc"
96#include "clang/Basic/DiagnosticAnalysisKinds.inc"
97#include "clang/Basic/DiagnosticRefactoringKinds.inc"
98 // clang-format on
99#undef DIAG
100};
101
102// Diagnostic classes.
103enum {
104 CLASS_NOTE = 0x01,
105 CLASS_REMARK = 0x02,
106 CLASS_WARNING = 0x03,
107 CLASS_EXTENSION = 0x04,
108 CLASS_ERROR = 0x05
109};
110
111struct StaticDiagInfoRec {
112 uint16_t DiagID;
113 uint8_t DefaultSeverity : 3;
114 uint8_t Class : 3;
115 uint8_t SFINAE : 2;
116 uint8_t Category : 6;
117 uint8_t WarnNoWerror : 1;
118 uint8_t WarnShowInSystemHeader : 1;
119 uint8_t WarnShowInSystemMacro : 1;
120
121 uint16_t OptionGroupIndex : 15;
122 uint16_t Deferrable : 1;
123
124 uint16_t DescriptionLen;
125
126 unsigned getOptionGroupIndex() const {
127 return OptionGroupIndex;
128 }
129
130 StringRef getDescription() const {
131 size_t MyIndex = this - &StaticDiagInfo[0];
132 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];
133 const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions);
134 return StringRef(&Table[StringOffset], DescriptionLen);
135 }
136
137 diag::Flavor getFlavor() const {
138 return Class == CLASS_REMARK ? diag::Flavor::Remark
139 : diag::Flavor::WarningOrError;
140 }
141
142 bool operator<(const StaticDiagInfoRec &RHS) const {
143 return DiagID < RHS.DiagID;
144 }
145};
146
147#define STRINGIFY_NAME(NAME) #NAME
148#define VALIDATE_DIAG_SIZE(NAME) \
149 static_assert( \
150 static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
151 static_cast<unsigned>(diag::DIAG_START_##NAME) + \
152 static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
153 STRINGIFY_NAME( \
154 DIAG_SIZE_##NAME) " is insufficient to contain all " \
155 "diagnostics, it may need to be made larger in " \
156 "DiagnosticIDs.h.");
157VALIDATE_DIAG_SIZE(COMMON)
158VALIDATE_DIAG_SIZE(DRIVER)
159VALIDATE_DIAG_SIZE(FRONTEND)
160VALIDATE_DIAG_SIZE(SERIALIZATION)
165VALIDATE_DIAG_SIZE(CROSSTU)
167VALIDATE_DIAG_SIZE(ANALYSIS)
168VALIDATE_DIAG_SIZE(REFACTORING)
169#undef VALIDATE_DIAG_SIZE
170#undef STRINGIFY_NAME
171
172const StaticDiagInfoRec StaticDiagInfo[] = {
173// clang-format off
174#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
175 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
176 { \
177 diag::ENUM, \
178 DEFAULT_SEVERITY, \
179 CLASS, \
180 DiagnosticIDs::SFINAE, \
181 CATEGORY, \
182 NOWERROR, \
183 SHOWINSYSHEADER, \
184 SHOWINSYSMACRO, \
185 GROUP, \
186 DEFERRABLE, \
187 STR_SIZE(DESC, uint16_t)},
188#include "clang/Basic/DiagnosticCommonKinds.inc"
189#include "clang/Basic/DiagnosticDriverKinds.inc"
190#include "clang/Basic/DiagnosticFrontendKinds.inc"
191#include "clang/Basic/DiagnosticSerializationKinds.inc"
192#include "clang/Basic/DiagnosticLexKinds.inc"
193#include "clang/Basic/DiagnosticParseKinds.inc"
194#include "clang/Basic/DiagnosticASTKinds.inc"
195#include "clang/Basic/DiagnosticCommentKinds.inc"
196#include "clang/Basic/DiagnosticCrossTUKinds.inc"
197#include "clang/Basic/DiagnosticSemaKinds.inc"
198#include "clang/Basic/DiagnosticAnalysisKinds.inc"
199#include "clang/Basic/DiagnosticRefactoringKinds.inc"
200// clang-format on
201#undef DIAG
202};
203
204} // namespace
205
206static const unsigned StaticDiagInfoSize = std::size(StaticDiagInfo);
207
208/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
209/// or null if the ID is invalid.
210static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
211 // Out of bounds diag. Can't be in the table.
212 using namespace diag;
213 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
214 return nullptr;
215
216 // Compute the index of the requested diagnostic in the static table.
217 // 1. Add the number of diagnostics in each category preceding the
218 // diagnostic and of the category the diagnostic is in. This gives us
219 // the offset of the category in the table.
220 // 2. Subtract the number of IDs in each category from our ID. This gives us
221 // the offset of the diagnostic in the category.
222 // This is cheaper than a binary search on the table as it doesn't touch
223 // memory at all.
224 unsigned Offset = 0;
225 unsigned ID = DiagID - DIAG_START_COMMON - 1;
226#define CATEGORY(NAME, PREV) \
227 if (DiagID > DIAG_START_##NAME) { \
228 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
229 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
230 }
231CATEGORY(DRIVER, COMMON)
232CATEGORY(FRONTEND, DRIVER)
233CATEGORY(SERIALIZATION, FRONTEND)
234CATEGORY(LEX, SERIALIZATION)
235CATEGORY(PARSE, LEX)
236CATEGORY(AST, PARSE)
237CATEGORY(COMMENT, AST)
238CATEGORY(CROSSTU, COMMENT)
239CATEGORY(SEMA, CROSSTU)
240CATEGORY(ANALYSIS, SEMA)
241CATEGORY(REFACTORING, ANALYSIS)
242#undef CATEGORY
243
244 // Avoid out of bounds reads.
245 if (ID + Offset >= StaticDiagInfoSize)
246 return nullptr;
247
248 assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
249
250 const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
251 // If the diag id doesn't match we found a different diag, abort. This can
252 // happen when this function is called with an ID that points into a hole in
253 // the diagID space.
254 if (Found->DiagID != DiagID)
255 return nullptr;
256 return Found;
257}
258
261 diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
262
263 if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
264 Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
265
266 if (StaticInfo->WarnNoWerror) {
267 assert(Info.getSeverity() == diag::Severity::Warning &&
268 "Unexpected mapping with no-Werror bit!");
269 Info.setNoWarningAsError(true);
270 }
271 }
272
273 return Info;
274}
275
276/// getCategoryNumberForDiag - Return the category number that a specified
277/// DiagID belongs to, or 0 if no category.
279 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
280 return Info->Category;
281 return 0;
282}
283
284namespace {
285 // The diagnostic category names.
286 struct StaticDiagCategoryRec {
287 const char *NameStr;
288 uint8_t NameLen;
289
290 StringRef getName() const {
291 return StringRef(NameStr, NameLen);
292 }
293 };
294}
295
296static const StaticDiagCategoryRec CategoryNameTable[] = {
297#define GET_CATEGORY_TABLE
298#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
299#include "clang/Basic/DiagnosticGroups.inc"
300#undef GET_CATEGORY_TABLE
301 { nullptr, 0 }
302};
303
304/// getNumberOfCategories - Return the number of categories
306 return std::size(CategoryNameTable) - 1;
307}
308
309/// getCategoryNameFromID - Given a category ID, return the name of the
310/// category, an empty string if CategoryID is zero, or null if CategoryID is
311/// invalid.
312StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
313 if (CategoryID >= getNumberOfCategories())
314 return StringRef();
315 return CategoryNameTable[CategoryID].getName();
316}
317
318
319
322 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
323 return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
324 return SFINAE_Report;
325}
326
327bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
328 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
329 return Info->Deferrable;
330 return false;
331}
332
333/// getBuiltinDiagClass - Return the class field of the diagnostic.
334///
335static unsigned getBuiltinDiagClass(unsigned DiagID) {
336 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
337 return Info->Class;
338 return ~0U;
339}
340
341//===----------------------------------------------------------------------===//
342// Custom Diagnostic information
343//===----------------------------------------------------------------------===//
344
345namespace clang {
346 namespace diag {
348 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
349 std::vector<DiagDesc> DiagInfo;
350 std::map<DiagDesc, unsigned> DiagIDs;
351 public:
352
353 /// getDescription - Return the description of the specified custom
354 /// diagnostic.
355 StringRef getDescription(unsigned DiagID) const {
356 assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
357 "Invalid diagnostic ID");
358 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
359 }
360
361 /// getLevel - Return the level of the specified custom diagnostic.
362 DiagnosticIDs::Level getLevel(unsigned DiagID) const {
363 assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
364 "Invalid diagnostic ID");
365 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
366 }
367
368 unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
369 DiagnosticIDs &Diags) {
370 DiagDesc D(L, std::string(Message));
371 // Check to see if it already exists.
372 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
373 if (I != DiagIDs.end() && I->first == D)
374 return I->second;
375
376 // If not, assign a new ID.
377 unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
378 DiagIDs.insert(std::make_pair(D, ID));
379 DiagInfo.push_back(D);
380 return ID;
381 }
382 };
383
384 } // end diag namespace
385} // end clang namespace
386
387
388//===----------------------------------------------------------------------===//
389// Common Diagnostic implementation
390//===----------------------------------------------------------------------===//
391
393
395
396/// getCustomDiagID - Return an ID for a diagnostic with the specified message
397/// and level. If this is the first request for this diagnostic, it is
398/// registered and created, otherwise the existing ID is returned.
399///
400/// \param FormatString A fixed diagnostic format string that will be hashed and
401/// mapped to a unique DiagID.
402unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
403 if (!CustomDiagInfo)
404 CustomDiagInfo.reset(new diag::CustomDiagInfo());
405 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
406}
407
408
409/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
410/// level of the specified diagnostic ID is a Warning or Extension.
411/// This only works on builtin diagnostics, not custom ones, and is not legal to
412/// call on NOTEs.
414 return DiagID < diag::DIAG_UPPER_LIMIT &&
415 getBuiltinDiagClass(DiagID) != CLASS_ERROR;
416}
417
418/// Determine whether the given built-in diagnostic ID is a
419/// Note.
420bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
421 return DiagID < diag::DIAG_UPPER_LIMIT &&
422 getBuiltinDiagClass(DiagID) == CLASS_NOTE;
423}
424
425/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
426/// ID is for an extension of some sort. This also returns EnabledByDefault,
427/// which is set to indicate whether the diagnostic is ignored by default (in
428/// which case -pedantic enables it) or treated as a warning/error by default.
429///
431 bool &EnabledByDefault) {
432 if (DiagID >= diag::DIAG_UPPER_LIMIT ||
433 getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
434 return false;
435
436 EnabledByDefault =
438 return true;
439}
440
442 if (DiagID >= diag::DIAG_UPPER_LIMIT)
443 return false;
444
446}
447
448/// getDescription - Given a diagnostic ID, return a description of the
449/// issue.
450StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
451 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
452 return Info->getDescription();
453 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
454 return CustomDiagInfo->getDescription(DiagID);
455}
456
458 switch (SV) {
469 }
470 llvm_unreachable("unexpected severity");
471}
472
473/// getDiagnosticLevel - Based on the way the client configured the
474/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
475/// by consumable the DiagnosticClient.
477DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
478 const DiagnosticsEngine &Diag) const {
479 // Handle custom diagnostics, which cannot be mapped.
480 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
481 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
482 return CustomDiagInfo->getLevel(DiagID);
483 }
484
485 unsigned DiagClass = getBuiltinDiagClass(DiagID);
486 if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
487 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
488}
489
490/// Based on the way the client configured the Diagnostic
491/// object, classify the specified diagnostic ID into a Level, consumable by
492/// the DiagnosticClient.
493///
494/// \param Loc The source location we are interested in finding out the
495/// diagnostic state. Can be null in order to query the latest state.
497DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
498 const DiagnosticsEngine &Diag) const {
499 assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
500
501 // Specific non-error diagnostics may be mapped to various levels from ignored
502 // to error. Errors can only be mapped to fatal.
504
505 // Get the mapping information, or compute it lazily.
506 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
507 DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
508
509 // TODO: Can a null severity really get here?
510 if (Mapping.getSeverity() != diag::Severity())
511 Result = Mapping.getSeverity();
512
513 // Upgrade ignored diagnostics if -Weverything is enabled.
514 if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
515 !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
517
518 // Ignore -pedantic diagnostics inside __extension__ blocks.
519 // (The diagnostics controlled by -pedantic are the extension diagnostics
520 // that are not enabled by default.)
521 bool EnabledByDefault = false;
522 bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
523 if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
525
526 // For extension diagnostics that haven't been explicitly mapped, check if we
527 // should upgrade the diagnostic.
528 if (IsExtensionDiag && !Mapping.isUser())
529 Result = std::max(Result, State->ExtBehavior);
530
531 // At this point, ignored errors can no longer be upgraded.
533 return Result;
534
535 // Honor -w: this disables all messages which are not Error/Fatal by
536 // default (disregarding attempts to upgrade severity from Warning to Error),
537 // as well as disabling all messages which are currently mapped to Warning
538 // (whether by default or downgraded from Error via e.g. -Wno-error or #pragma
539 // diagnostic.)
540 if (State->IgnoreAllWarnings) {
545 }
546
547 // If -Werror is enabled, map warnings to errors unless explicitly disabled.
549 if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
551 }
552
553 // If -Wfatal-errors is enabled, map errors to fatal unless explicitly
554 // disabled.
556 if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
558 }
559
560 // If explicitly requested, map fatal errors to errors.
562 Diag.CurDiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
564
565 // Custom diagnostics always are emitted in system headers.
566 bool ShowInSystemHeader =
567 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
568
569 // If we are in a system header, we ignore it. We look at the diagnostic class
570 // because we also want to ignore extensions and warnings in -Werror and
571 // -pedantic-errors modes, which *map* warnings/extensions to errors.
572 if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
573 Diag.getSourceManager().isInSystemHeader(
574 Diag.getSourceManager().getExpansionLoc(Loc)))
576
577 // We also ignore warnings due to system macros
578 bool ShowInSystemMacro =
579 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro;
580 if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&
581 Diag.getSourceManager().isInSystemMacro(Loc))
583
584 return Result;
585}
586
587#define GET_DIAG_ARRAYS
588#include "clang/Basic/DiagnosticGroups.inc"
589#undef GET_DIAG_ARRAYS
590
591namespace {
592 struct WarningOption {
593 uint16_t NameOffset;
594 uint16_t Members;
595 uint16_t SubGroups;
596 StringRef Documentation;
597
598 // String is stored with a pascal-style length byte.
599 StringRef getName() const {
600 return StringRef(DiagGroupNames + NameOffset + 1,
601 DiagGroupNames[NameOffset]);
602 }
603 };
604}
605
606// Second the table of options, sorted by name for fast binary lookup.
607static const WarningOption OptionTable[] = {
608#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
609 {FlagNameOffset, Members, SubGroups, Docs},
610#include "clang/Basic/DiagnosticGroups.inc"
611#undef DIAG_ENTRY
612};
613
614/// Given a diagnostic group ID, return its documentation.
616 return OptionTable[static_cast<int>(Group)].Documentation;
617}
618
620 return OptionTable[static_cast<int>(Group)].getName();
621}
622
623std::optional<diag::Group>
625 const auto *Found = llvm::partition_point(
626 OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });
627 if (Found == std::end(OptionTable) || Found->getName() != Name)
628 return std::nullopt;
629 return static_cast<diag::Group>(Found - OptionTable);
630}
631
632std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
633 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
634 return static_cast<diag::Group>(Info->getOptionGroupIndex());
635 return std::nullopt;
636}
637
638/// getWarningOptionForDiag - Return the lowest-level warning option that
639/// enables the specified diagnostic. If there is no -Wfoo flag that controls
640/// the diagnostic, this returns null.
641StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
642 if (auto G = getGroupForDiag(DiagID))
643 return getWarningOptionForGroup(*G);
644 return StringRef();
645}
646
647std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
648 std::vector<std::string> Res{"-W", "-Wno-"};
649 for (size_t I = 1; DiagGroupNames[I] != '\0';) {
650 std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
651 I += DiagGroupNames[I] + 1;
652 Res.push_back("-W" + Diag);
653 Res.push_back("-Wno-" + Diag);
654 }
655
656 return Res;
657}
658
659/// Return \c true if any diagnostics were found in this group, even if they
660/// were filtered out due to having the wrong flavor.
662 const WarningOption *Group,
664 // An empty group is considered to be a warning group: we have empty groups
665 // for GCC compatibility, and GCC does not have remarks.
666 if (!Group->Members && !Group->SubGroups)
667 return Flavor == diag::Flavor::Remark;
668
669 bool NotFound = true;
670
671 // Add the members of the option diagnostic set.
672 const int16_t *Member = DiagArrays + Group->Members;
673 for (; *Member != -1; ++Member) {
674 if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
675 NotFound = false;
676 Diags.push_back(*Member);
677 }
678 }
679
680 // Add the members of the subgroups.
681 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
682 for (; *SubGroups != (int16_t)-1; ++SubGroups)
683 NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
684 Diags);
685
686 return NotFound;
687}
688
689bool
691 SmallVectorImpl<diag::kind> &Diags) const {
692 if (std::optional<diag::Group> G = getGroupForWarningOption(Group))
693 return ::getDiagnosticsInGroup(
694 Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
695 return true;
696}
697
699 std::vector<diag::kind> &Diags) {
700 for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
701 if (StaticDiagInfo[i].getFlavor() == Flavor)
702 Diags.push_back(StaticDiagInfo[i].DiagID);
703}
704
706 StringRef Group) {
707 StringRef Best;
708 unsigned BestDistance = Group.size() + 1; // Maximum threshold.
709 for (const WarningOption &O : OptionTable) {
710 // Don't suggest ignored warning flags.
711 if (!O.Members && !O.SubGroups)
712 continue;
713
714 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
715 if (Distance > BestDistance)
716 continue;
717
718 // Don't suggest groups that are not of this kind.
720 if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
721 continue;
722
723 if (Distance == BestDistance) {
724 // Two matches with the same distance, don't prefer one over the other.
725 Best = "";
726 } else if (Distance < BestDistance) {
727 // This is a better match.
728 Best = O.getName();
729 BestDistance = Distance;
730 }
731 }
732
733 return Best;
734}
735
736/// ProcessDiag - This is the method used to report a diagnostic that is
737/// finally fully formed.
738bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
739 Diagnostic Info(&Diag);
740
741 assert(Diag.getClient() && "DiagnosticClient not set!");
742
743 // Figure out the diagnostic level of this message.
744 unsigned DiagID = Info.getID();
745 DiagnosticIDs::Level DiagLevel
746 = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
747
748 // Update counts for DiagnosticErrorTrap even if a fatal error occurred
749 // or diagnostics are suppressed.
750 if (DiagLevel >= DiagnosticIDs::Error) {
751 ++Diag.TrapNumErrorsOccurred;
752 if (isUnrecoverable(DiagID))
753 ++Diag.TrapNumUnrecoverableErrorsOccurred;
754 }
755
756 if (Diag.SuppressAllDiagnostics)
757 return false;
758
759 if (DiagLevel != DiagnosticIDs::Note) {
760 // Record that a fatal error occurred only when we see a second
761 // non-note diagnostic. This allows notes to be attached to the
762 // fatal error, but suppresses any diagnostics that follow those
763 // notes.
764 if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
765 Diag.FatalErrorOccurred = true;
766
767 Diag.LastDiagLevel = DiagLevel;
768 }
769
770 // If a fatal error has already been emitted, silence all subsequent
771 // diagnostics.
772 if (Diag.FatalErrorOccurred) {
773 if (DiagLevel >= DiagnosticIDs::Error &&
774 Diag.Client->IncludeInDiagnosticCounts()) {
775 ++Diag.NumErrors;
776 }
777
778 return false;
779 }
780
781 // If the client doesn't care about this message, don't issue it. If this is
782 // a note and the last real diagnostic was ignored, ignore it too.
783 if (DiagLevel == DiagnosticIDs::Ignored ||
784 (DiagLevel == DiagnosticIDs::Note &&
785 Diag.LastDiagLevel == DiagnosticIDs::Ignored))
786 return false;
787
788 if (DiagLevel >= DiagnosticIDs::Error) {
789 if (isUnrecoverable(DiagID))
790 Diag.UnrecoverableErrorOccurred = true;
791
792 // Warnings which have been upgraded to errors do not prevent compilation.
793 if (isDefaultMappingAsError(DiagID))
794 Diag.UncompilableErrorOccurred = true;
795
796 Diag.ErrorOccurred = true;
797 if (Diag.Client->IncludeInDiagnosticCounts()) {
798 ++Diag.NumErrors;
799 }
800
801 // If we've emitted a lot of errors, emit a fatal error instead of it to
802 // stop a flood of bogus errors.
803 if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
804 DiagLevel == DiagnosticIDs::Error) {
805 Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
806 return false;
807 }
808 }
809
810 // Make sure we set FatalErrorOccurred to ensure that the notes from the
811 // diagnostic that caused `fatal_too_many_errors` won't be emitted.
812 if (Diag.CurDiagID == diag::fatal_too_many_errors)
813 Diag.FatalErrorOccurred = true;
814 // Finally, report it.
815 EmitDiag(Diag, DiagLevel);
816 return true;
817}
818
819void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
820 Diagnostic Info(&Diag);
821 assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
822
823 Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
824 if (Diag.Client->IncludeInDiagnosticCounts()) {
825 if (DiagLevel == DiagnosticIDs::Warning)
826 ++Diag.NumWarnings;
827 }
828
829 Diag.CurDiagID = ~0U;
830}
831
832bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
833 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
834 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
835 // Custom diagnostics.
836 return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
837 }
838
839 // Only errors may be unrecoverable.
840 if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
841 return false;
842
843 if (DiagID == diag::err_unavailable ||
844 DiagID == diag::err_unavailable_message)
845 return false;
846
847 // Currently we consider all ARC errors as recoverable.
848 if (isARCDiagnostic(DiagID))
849 return false;
850
851 return true;
852}
853
854bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
855 unsigned cat = getCategoryNumberForDiag(DiagID);
856 return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
857}
Includes all the separate Diagnostic headers & some related helpers.
#define COMMENT(CLASS, PARENT)
Definition: Comment.h:188
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.
int Category
Definition: Format.cpp:2939
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.
unsigned NameLen
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.
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) ...
Definition: Diagnostic.h:1566
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:195
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),...
Definition: DiagnosticIDs.h:83
@ 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.
Definition: DiagnosticIDs.h:94
@ Remark
A diagnostic that indicates normal progress through compilation.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
@ Result
The result type of a method or function.