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