[AMDGPU][AsmParser][NFC] Get rid of custom default operand handlers.
[llvm-project.git] / clang / lib / Basic / DiagnosticIDs.cpp
blobac08e98a278db76df9e548f6f0467ef51ce1bd06
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.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Basic/DiagnosticIDs.h"
14 #include "clang/Basic/AllDiagnostics.h"
15 #include "clang/Basic/DiagnosticCategories.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include <map>
21 #include <optional>
22 using namespace clang;
24 //===----------------------------------------------------------------------===//
25 // Builtin Diagnostic information
26 //===----------------------------------------------------------------------===//
28 namespace {
30 struct StaticDiagInfoRec;
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.
35 struct 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
56 const 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
77 extern const StaticDiagInfoRec StaticDiagInfo[];
79 // Stored separately from StaticDiagInfoRec to pack better. Otherwise,
80 // StaticDiagInfoRec would have extra padding on 64-bit platforms.
81 const 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
102 // Diagnostic classes.
103 enum {
104 CLASS_NOTE = 0x01,
105 CLASS_REMARK = 0x02,
106 CLASS_WARNING = 0x03,
107 CLASS_EXTENSION = 0x04,
108 CLASS_ERROR = 0x05
111 struct 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;
121 uint16_t OptionGroupIndex : 15;
122 uint16_t Deferrable : 1;
124 uint16_t DescriptionLen;
126 unsigned getOptionGroupIndex() const {
127 return OptionGroupIndex;
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);
137 diag::Flavor getFlavor() const {
138 return Class == CLASS_REMARK ? diag::Flavor::Remark
139 : diag::Flavor::WarningOrError;
142 bool operator<(const StaticDiagInfoRec &RHS) const {
143 return DiagID < RHS.DiagID;
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.");
157 VALIDATE_DIAG_SIZE(COMMON)
158 VALIDATE_DIAG_SIZE(DRIVER)
159 VALIDATE_DIAG_SIZE(FRONTEND)
160 VALIDATE_DIAG_SIZE(SERIALIZATION)
161 VALIDATE_DIAG_SIZE(LEX)
162 VALIDATE_DIAG_SIZE(PARSE)
163 VALIDATE_DIAG_SIZE(AST)
164 VALIDATE_DIAG_SIZE(COMMENT)
165 VALIDATE_DIAG_SIZE(CROSSTU)
166 VALIDATE_DIAG_SIZE(SEMA)
167 VALIDATE_DIAG_SIZE(ANALYSIS)
168 VALIDATE_DIAG_SIZE(REFACTORING)
169 #undef VALIDATE_DIAG_SIZE
170 #undef STRINGIFY_NAME
172 const StaticDiagInfoRec StaticDiagInfo[] = {
173 // clang-format off
174 #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
175 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
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
204 } // namespace
206 static const unsigned StaticDiagInfoSize = std::size(StaticDiagInfo);
208 /// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
209 /// or null if the ID is invalid.
210 static 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;
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; \
231 CATEGORY(DRIVER, COMMON)
232 CATEGORY(FRONTEND, DRIVER)
233 CATEGORY(SERIALIZATION, FRONTEND)
234 CATEGORY(LEX, SERIALIZATION)
235 CATEGORY(PARSE, LEX)
236 CATEGORY(AST, PARSE)
237 CATEGORY(COMMENT, AST)
238 CATEGORY(CROSSTU, COMMENT)
239 CATEGORY(SEMA, CROSSTU)
240 CATEGORY(ANALYSIS, SEMA)
241 CATEGORY(REFACTORING, ANALYSIS)
242 #undef CATEGORY
244 // Avoid out of bounds reads.
245 if (ID + Offset >= StaticDiagInfoSize)
246 return nullptr;
248 assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
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;
259 static DiagnosticMapping GetDefaultDiagMapping(unsigned DiagID) {
260 DiagnosticMapping Info = DiagnosticMapping::Make(
261 diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
263 if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
264 Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
266 if (StaticInfo->WarnNoWerror) {
267 assert(Info.getSeverity() == diag::Severity::Warning &&
268 "Unexpected mapping with no-Werror bit!");
269 Info.setNoWarningAsError(true);
273 return Info;
276 /// getCategoryNumberForDiag - Return the category number that a specified
277 /// DiagID belongs to, or 0 if no category.
278 unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
279 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
280 return Info->Category;
281 return 0;
284 namespace {
285 // The diagnostic category names.
286 struct StaticDiagCategoryRec {
287 const char *NameStr;
288 uint8_t NameLen;
290 StringRef getName() const {
291 return StringRef(NameStr, NameLen);
296 // Unfortunately, the split between DiagnosticIDs and Diagnostic is not
297 // particularly clean, but for now we just implement this method here so we can
298 // access GetDefaultDiagMapping.
299 DiagnosticMapping &
300 DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
301 std::pair<iterator, bool> Result =
302 DiagMap.insert(std::make_pair(Diag, DiagnosticMapping()));
304 // Initialize the entry if we added it.
305 if (Result.second)
306 Result.first->second = GetDefaultDiagMapping(Diag);
308 return Result.first->second;
311 static const StaticDiagCategoryRec CategoryNameTable[] = {
312 #define GET_CATEGORY_TABLE
313 #define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
314 #include "clang/Basic/DiagnosticGroups.inc"
315 #undef GET_CATEGORY_TABLE
316 { nullptr, 0 }
319 /// getNumberOfCategories - Return the number of categories
320 unsigned DiagnosticIDs::getNumberOfCategories() {
321 return std::size(CategoryNameTable) - 1;
324 /// getCategoryNameFromID - Given a category ID, return the name of the
325 /// category, an empty string if CategoryID is zero, or null if CategoryID is
326 /// invalid.
327 StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
328 if (CategoryID >= getNumberOfCategories())
329 return StringRef();
330 return CategoryNameTable[CategoryID].getName();
335 DiagnosticIDs::SFINAEResponse
336 DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
337 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
338 return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
339 return SFINAE_Report;
342 bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
343 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
344 return Info->Deferrable;
345 return false;
348 /// getBuiltinDiagClass - Return the class field of the diagnostic.
350 static unsigned getBuiltinDiagClass(unsigned DiagID) {
351 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
352 return Info->Class;
353 return ~0U;
356 //===----------------------------------------------------------------------===//
357 // Custom Diagnostic information
358 //===----------------------------------------------------------------------===//
360 namespace clang {
361 namespace diag {
362 class CustomDiagInfo {
363 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
364 std::vector<DiagDesc> DiagInfo;
365 std::map<DiagDesc, unsigned> DiagIDs;
366 public:
368 /// getDescription - Return the description of the specified custom
369 /// diagnostic.
370 StringRef getDescription(unsigned DiagID) const {
371 assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
372 "Invalid diagnostic ID");
373 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
376 /// getLevel - Return the level of the specified custom diagnostic.
377 DiagnosticIDs::Level getLevel(unsigned DiagID) const {
378 assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
379 "Invalid diagnostic ID");
380 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
383 unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
384 DiagnosticIDs &Diags) {
385 DiagDesc D(L, std::string(Message));
386 // Check to see if it already exists.
387 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
388 if (I != DiagIDs.end() && I->first == D)
389 return I->second;
391 // If not, assign a new ID.
392 unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
393 DiagIDs.insert(std::make_pair(D, ID));
394 DiagInfo.push_back(D);
395 return ID;
399 } // end diag namespace
400 } // end clang namespace
403 //===----------------------------------------------------------------------===//
404 // Common Diagnostic implementation
405 //===----------------------------------------------------------------------===//
407 DiagnosticIDs::DiagnosticIDs() {}
409 DiagnosticIDs::~DiagnosticIDs() {}
411 /// getCustomDiagID - Return an ID for a diagnostic with the specified message
412 /// and level. If this is the first request for this diagnostic, it is
413 /// registered and created, otherwise the existing ID is returned.
415 /// \param FormatString A fixed diagnostic format string that will be hashed and
416 /// mapped to a unique DiagID.
417 unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
418 if (!CustomDiagInfo)
419 CustomDiagInfo.reset(new diag::CustomDiagInfo());
420 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
424 /// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
425 /// level of the specified diagnostic ID is a Warning or Extension.
426 /// This only works on builtin diagnostics, not custom ones, and is not legal to
427 /// call on NOTEs.
428 bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
429 return DiagID < diag::DIAG_UPPER_LIMIT &&
430 getBuiltinDiagClass(DiagID) != CLASS_ERROR;
433 /// Determine whether the given built-in diagnostic ID is a
434 /// Note.
435 bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
436 return DiagID < diag::DIAG_UPPER_LIMIT &&
437 getBuiltinDiagClass(DiagID) == CLASS_NOTE;
440 /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
441 /// ID is for an extension of some sort. This also returns EnabledByDefault,
442 /// which is set to indicate whether the diagnostic is ignored by default (in
443 /// which case -pedantic enables it) or treated as a warning/error by default.
445 bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
446 bool &EnabledByDefault) {
447 if (DiagID >= diag::DIAG_UPPER_LIMIT ||
448 getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
449 return false;
451 EnabledByDefault =
452 GetDefaultDiagMapping(DiagID).getSeverity() != diag::Severity::Ignored;
453 return true;
456 bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
457 if (DiagID >= diag::DIAG_UPPER_LIMIT)
458 return false;
460 return GetDefaultDiagMapping(DiagID).getSeverity() >= diag::Severity::Error;
463 /// getDescription - Given a diagnostic ID, return a description of the
464 /// issue.
465 StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
466 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
467 return Info->getDescription();
468 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
469 return CustomDiagInfo->getDescription(DiagID);
472 static DiagnosticIDs::Level toLevel(diag::Severity SV) {
473 switch (SV) {
474 case diag::Severity::Ignored:
475 return DiagnosticIDs::Ignored;
476 case diag::Severity::Remark:
477 return DiagnosticIDs::Remark;
478 case diag::Severity::Warning:
479 return DiagnosticIDs::Warning;
480 case diag::Severity::Error:
481 return DiagnosticIDs::Error;
482 case diag::Severity::Fatal:
483 return DiagnosticIDs::Fatal;
485 llvm_unreachable("unexpected severity");
488 /// getDiagnosticLevel - Based on the way the client configured the
489 /// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
490 /// by consumable the DiagnosticClient.
491 DiagnosticIDs::Level
492 DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
493 const DiagnosticsEngine &Diag) const {
494 // Handle custom diagnostics, which cannot be mapped.
495 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
496 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
497 return CustomDiagInfo->getLevel(DiagID);
500 unsigned DiagClass = getBuiltinDiagClass(DiagID);
501 if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
502 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
505 /// Based on the way the client configured the Diagnostic
506 /// object, classify the specified diagnostic ID into a Level, consumable by
507 /// the DiagnosticClient.
509 /// \param Loc The source location we are interested in finding out the
510 /// diagnostic state. Can be null in order to query the latest state.
511 diag::Severity
512 DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
513 const DiagnosticsEngine &Diag) const {
514 assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
516 // Specific non-error diagnostics may be mapped to various levels from ignored
517 // to error. Errors can only be mapped to fatal.
518 diag::Severity Result = diag::Severity::Fatal;
520 // Get the mapping information, or compute it lazily.
521 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
522 DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
524 // TODO: Can a null severity really get here?
525 if (Mapping.getSeverity() != diag::Severity())
526 Result = Mapping.getSeverity();
528 // Upgrade ignored diagnostics if -Weverything is enabled.
529 if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
530 !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
531 Result = diag::Severity::Warning;
533 // Ignore -pedantic diagnostics inside __extension__ blocks.
534 // (The diagnostics controlled by -pedantic are the extension diagnostics
535 // that are not enabled by default.)
536 bool EnabledByDefault = false;
537 bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
538 if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
539 return diag::Severity::Ignored;
541 // For extension diagnostics that haven't been explicitly mapped, check if we
542 // should upgrade the diagnostic.
543 if (IsExtensionDiag && !Mapping.isUser())
544 Result = std::max(Result, State->ExtBehavior);
546 // At this point, ignored errors can no longer be upgraded.
547 if (Result == diag::Severity::Ignored)
548 return Result;
550 // Honor -w: this disables all messages which are not Error/Fatal by
551 // default (disregarding attempts to upgrade severity from Warning to Error),
552 // as well as disabling all messages which are currently mapped to Warning
553 // (whether by default or downgraded from Error via e.g. -Wno-error or #pragma
554 // diagnostic.)
555 if (State->IgnoreAllWarnings) {
556 if (Result == diag::Severity::Warning ||
557 (Result >= diag::Severity::Error &&
558 !isDefaultMappingAsError((diag::kind)DiagID)))
559 return diag::Severity::Ignored;
562 // If -Werror is enabled, map warnings to errors unless explicitly disabled.
563 if (Result == diag::Severity::Warning) {
564 if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
565 Result = diag::Severity::Error;
568 // If -Wfatal-errors is enabled, map errors to fatal unless explicitly
569 // disabled.
570 if (Result == diag::Severity::Error) {
571 if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
572 Result = diag::Severity::Fatal;
575 // If explicitly requested, map fatal errors to errors.
576 if (Result == diag::Severity::Fatal &&
577 Diag.CurDiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
578 Result = diag::Severity::Error;
580 // Custom diagnostics always are emitted in system headers.
581 bool ShowInSystemHeader =
582 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
584 // If we are in a system header, we ignore it. We look at the diagnostic class
585 // because we also want to ignore extensions and warnings in -Werror and
586 // -pedantic-errors modes, which *map* warnings/extensions to errors.
587 if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
588 Diag.getSourceManager().isInSystemHeader(
589 Diag.getSourceManager().getExpansionLoc(Loc)))
590 return diag::Severity::Ignored;
592 // We also ignore warnings due to system macros
593 bool ShowInSystemMacro =
594 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro;
595 if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&
596 Diag.getSourceManager().isInSystemMacro(Loc))
597 return diag::Severity::Ignored;
599 return Result;
602 #define GET_DIAG_ARRAYS
603 #include "clang/Basic/DiagnosticGroups.inc"
604 #undef GET_DIAG_ARRAYS
606 namespace {
607 struct WarningOption {
608 uint16_t NameOffset;
609 uint16_t Members;
610 uint16_t SubGroups;
611 StringRef Documentation;
613 // String is stored with a pascal-style length byte.
614 StringRef getName() const {
615 return StringRef(DiagGroupNames + NameOffset + 1,
616 DiagGroupNames[NameOffset]);
621 // Second the table of options, sorted by name for fast binary lookup.
622 static const WarningOption OptionTable[] = {
623 #define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
624 {FlagNameOffset, Members, SubGroups, Docs},
625 #include "clang/Basic/DiagnosticGroups.inc"
626 #undef DIAG_ENTRY
629 /// Given a diagnostic group ID, return its documentation.
630 StringRef DiagnosticIDs::getWarningOptionDocumentation(diag::Group Group) {
631 return OptionTable[static_cast<int>(Group)].Documentation;
634 StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) {
635 return OptionTable[static_cast<int>(Group)].getName();
638 std::optional<diag::Group>
639 DiagnosticIDs::getGroupForWarningOption(StringRef Name) {
640 const auto *Found = llvm::partition_point(
641 OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });
642 if (Found == std::end(OptionTable) || Found->getName() != Name)
643 return std::nullopt;
644 return static_cast<diag::Group>(Found - OptionTable);
647 std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
648 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
649 return static_cast<diag::Group>(Info->getOptionGroupIndex());
650 return std::nullopt;
653 /// getWarningOptionForDiag - Return the lowest-level warning option that
654 /// enables the specified diagnostic. If there is no -Wfoo flag that controls
655 /// the diagnostic, this returns null.
656 StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
657 if (auto G = getGroupForDiag(DiagID))
658 return getWarningOptionForGroup(*G);
659 return StringRef();
662 std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
663 std::vector<std::string> Res{"-W", "-Wno-"};
664 for (size_t I = 1; DiagGroupNames[I] != '\0';) {
665 std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
666 I += DiagGroupNames[I] + 1;
667 Res.push_back("-W" + Diag);
668 Res.push_back("-Wno-" + Diag);
671 return Res;
674 /// Return \c true if any diagnostics were found in this group, even if they
675 /// were filtered out due to having the wrong flavor.
676 static bool getDiagnosticsInGroup(diag::Flavor Flavor,
677 const WarningOption *Group,
678 SmallVectorImpl<diag::kind> &Diags) {
679 // An empty group is considered to be a warning group: we have empty groups
680 // for GCC compatibility, and GCC does not have remarks.
681 if (!Group->Members && !Group->SubGroups)
682 return Flavor == diag::Flavor::Remark;
684 bool NotFound = true;
686 // Add the members of the option diagnostic set.
687 const int16_t *Member = DiagArrays + Group->Members;
688 for (; *Member != -1; ++Member) {
689 if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
690 NotFound = false;
691 Diags.push_back(*Member);
695 // Add the members of the subgroups.
696 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
697 for (; *SubGroups != (int16_t)-1; ++SubGroups)
698 NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
699 Diags);
701 return NotFound;
704 bool
705 DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
706 SmallVectorImpl<diag::kind> &Diags) const {
707 if (std::optional<diag::Group> G = getGroupForWarningOption(Group))
708 return ::getDiagnosticsInGroup(
709 Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
710 return true;
713 void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
714 std::vector<diag::kind> &Diags) {
715 for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
716 if (StaticDiagInfo[i].getFlavor() == Flavor)
717 Diags.push_back(StaticDiagInfo[i].DiagID);
720 StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
721 StringRef Group) {
722 StringRef Best;
723 unsigned BestDistance = Group.size() + 1; // Maximum threshold.
724 for (const WarningOption &O : OptionTable) {
725 // Don't suggest ignored warning flags.
726 if (!O.Members && !O.SubGroups)
727 continue;
729 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
730 if (Distance > BestDistance)
731 continue;
733 // Don't suggest groups that are not of this kind.
734 llvm::SmallVector<diag::kind, 8> Diags;
735 if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
736 continue;
738 if (Distance == BestDistance) {
739 // Two matches with the same distance, don't prefer one over the other.
740 Best = "";
741 } else if (Distance < BestDistance) {
742 // This is a better match.
743 Best = O.getName();
744 BestDistance = Distance;
748 return Best;
751 /// ProcessDiag - This is the method used to report a diagnostic that is
752 /// finally fully formed.
753 bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
754 Diagnostic Info(&Diag);
756 assert(Diag.getClient() && "DiagnosticClient not set!");
758 // Figure out the diagnostic level of this message.
759 unsigned DiagID = Info.getID();
760 DiagnosticIDs::Level DiagLevel
761 = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
763 // Update counts for DiagnosticErrorTrap even if a fatal error occurred
764 // or diagnostics are suppressed.
765 if (DiagLevel >= DiagnosticIDs::Error) {
766 ++Diag.TrapNumErrorsOccurred;
767 if (isUnrecoverable(DiagID))
768 ++Diag.TrapNumUnrecoverableErrorsOccurred;
771 if (Diag.SuppressAllDiagnostics)
772 return false;
774 if (DiagLevel != DiagnosticIDs::Note) {
775 // Record that a fatal error occurred only when we see a second
776 // non-note diagnostic. This allows notes to be attached to the
777 // fatal error, but suppresses any diagnostics that follow those
778 // notes.
779 if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
780 Diag.FatalErrorOccurred = true;
782 Diag.LastDiagLevel = DiagLevel;
785 // If a fatal error has already been emitted, silence all subsequent
786 // diagnostics.
787 if (Diag.FatalErrorOccurred) {
788 if (DiagLevel >= DiagnosticIDs::Error &&
789 Diag.Client->IncludeInDiagnosticCounts()) {
790 ++Diag.NumErrors;
793 return false;
796 // If the client doesn't care about this message, don't issue it. If this is
797 // a note and the last real diagnostic was ignored, ignore it too.
798 if (DiagLevel == DiagnosticIDs::Ignored ||
799 (DiagLevel == DiagnosticIDs::Note &&
800 Diag.LastDiagLevel == DiagnosticIDs::Ignored))
801 return false;
803 if (DiagLevel >= DiagnosticIDs::Error) {
804 if (isUnrecoverable(DiagID))
805 Diag.UnrecoverableErrorOccurred = true;
807 // Warnings which have been upgraded to errors do not prevent compilation.
808 if (isDefaultMappingAsError(DiagID))
809 Diag.UncompilableErrorOccurred = true;
811 Diag.ErrorOccurred = true;
812 if (Diag.Client->IncludeInDiagnosticCounts()) {
813 ++Diag.NumErrors;
816 // If we've emitted a lot of errors, emit a fatal error instead of it to
817 // stop a flood of bogus errors.
818 if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
819 DiagLevel == DiagnosticIDs::Error) {
820 Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
821 return false;
825 // Make sure we set FatalErrorOccurred to ensure that the notes from the
826 // diagnostic that caused `fatal_too_many_errors` won't be emitted.
827 if (Diag.CurDiagID == diag::fatal_too_many_errors)
828 Diag.FatalErrorOccurred = true;
829 // Finally, report it.
830 EmitDiag(Diag, DiagLevel);
831 return true;
834 void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
835 Diagnostic Info(&Diag);
836 assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
838 Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
839 if (Diag.Client->IncludeInDiagnosticCounts()) {
840 if (DiagLevel == DiagnosticIDs::Warning)
841 ++Diag.NumWarnings;
844 Diag.CurDiagID = ~0U;
847 bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
848 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
849 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
850 // Custom diagnostics.
851 return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
854 // Only errors may be unrecoverable.
855 if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
856 return false;
858 if (DiagID == diag::err_unavailable ||
859 DiagID == diag::err_unavailable_message)
860 return false;
862 // Currently we consider all ARC errors as recoverable.
863 if (isARCDiagnostic(DiagID))
864 return false;
866 return true;
869 bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
870 unsigned cat = getCategoryNumberForDiag(DiagID);
871 return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");