[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang / lib / Basic / DiagnosticIDs.cpp
blobe5667d57f8cff114c316a40526e4b116ce9e2924
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 DiagnosticMapping DiagnosticIDs::getDefaultMapping(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 static 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 }
304 /// getNumberOfCategories - Return the number of categories
305 unsigned DiagnosticIDs::getNumberOfCategories() {
306 return std::size(CategoryNameTable) - 1;
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.
312 StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
313 if (CategoryID >= getNumberOfCategories())
314 return StringRef();
315 return CategoryNameTable[CategoryID].getName();
320 DiagnosticIDs::SFINAEResponse
321 DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
322 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
323 return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
324 return SFINAE_Report;
327 bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
328 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
329 return Info->Deferrable;
330 return false;
333 /// getBuiltinDiagClass - Return the class field of the diagnostic.
335 static unsigned getBuiltinDiagClass(unsigned DiagID) {
336 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
337 return Info->Class;
338 return ~0U;
341 //===----------------------------------------------------------------------===//
342 // Custom Diagnostic information
343 //===----------------------------------------------------------------------===//
345 namespace clang {
346 namespace diag {
347 class CustomDiagInfo {
348 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
349 std::vector<DiagDesc> DiagInfo;
350 std::map<DiagDesc, unsigned> DiagIDs;
351 public:
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;
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;
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;
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;
384 } // end diag namespace
385 } // end clang namespace
388 //===----------------------------------------------------------------------===//
389 // Common Diagnostic implementation
390 //===----------------------------------------------------------------------===//
392 DiagnosticIDs::DiagnosticIDs() {}
394 DiagnosticIDs::~DiagnosticIDs() {}
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.
400 /// \param FormatString A fixed diagnostic format string that will be hashed and
401 /// mapped to a unique DiagID.
402 unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
403 if (!CustomDiagInfo)
404 CustomDiagInfo.reset(new diag::CustomDiagInfo());
405 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
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.
413 bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
414 return DiagID < diag::DIAG_UPPER_LIMIT &&
415 getBuiltinDiagClass(DiagID) != CLASS_ERROR;
418 /// Determine whether the given built-in diagnostic ID is a
419 /// Note.
420 bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
421 return DiagID < diag::DIAG_UPPER_LIMIT &&
422 getBuiltinDiagClass(DiagID) == CLASS_NOTE;
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.
430 bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
431 bool &EnabledByDefault) {
432 if (DiagID >= diag::DIAG_UPPER_LIMIT ||
433 getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
434 return false;
436 EnabledByDefault =
437 getDefaultMapping(DiagID).getSeverity() != diag::Severity::Ignored;
438 return true;
441 bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
442 if (DiagID >= diag::DIAG_UPPER_LIMIT)
443 return false;
445 return getDefaultMapping(DiagID).getSeverity() >= diag::Severity::Error;
448 /// getDescription - Given a diagnostic ID, return a description of the
449 /// issue.
450 StringRef 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);
457 static DiagnosticIDs::Level toLevel(diag::Severity SV) {
458 switch (SV) {
459 case diag::Severity::Ignored:
460 return DiagnosticIDs::Ignored;
461 case diag::Severity::Remark:
462 return DiagnosticIDs::Remark;
463 case diag::Severity::Warning:
464 return DiagnosticIDs::Warning;
465 case diag::Severity::Error:
466 return DiagnosticIDs::Error;
467 case diag::Severity::Fatal:
468 return DiagnosticIDs::Fatal;
470 llvm_unreachable("unexpected severity");
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.
476 DiagnosticIDs::Level
477 DiagnosticIDs::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);
485 unsigned DiagClass = getBuiltinDiagClass(DiagID);
486 if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
487 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
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.
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.
496 diag::Severity
497 DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
498 const DiagnosticsEngine &Diag) const {
499 assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
501 // Specific non-error diagnostics may be mapped to various levels from ignored
502 // to error. Errors can only be mapped to fatal.
503 diag::Severity Result = diag::Severity::Fatal;
505 // Get the mapping information, or compute it lazily.
506 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
507 DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
509 // TODO: Can a null severity really get here?
510 if (Mapping.getSeverity() != diag::Severity())
511 Result = Mapping.getSeverity();
513 // Upgrade ignored diagnostics if -Weverything is enabled.
514 if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
515 !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
516 Result = diag::Severity::Warning;
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)
524 return diag::Severity::Ignored;
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);
531 // At this point, ignored errors can no longer be upgraded.
532 if (Result == diag::Severity::Ignored)
533 return Result;
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) {
541 if (Result == diag::Severity::Warning ||
542 (Result >= diag::Severity::Error &&
543 !isDefaultMappingAsError((diag::kind)DiagID)))
544 return diag::Severity::Ignored;
547 // If -Werror is enabled, map warnings to errors unless explicitly disabled.
548 if (Result == diag::Severity::Warning) {
549 if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
550 Result = diag::Severity::Error;
553 // If -Wfatal-errors is enabled, map errors to fatal unless explicitly
554 // disabled.
555 if (Result == diag::Severity::Error) {
556 if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
557 Result = diag::Severity::Fatal;
560 // If explicitly requested, map fatal errors to errors.
561 if (Result == diag::Severity::Fatal &&
562 Diag.CurDiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
563 Result = diag::Severity::Error;
565 // Custom diagnostics always are emitted in system headers.
566 bool ShowInSystemHeader =
567 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
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)))
575 return diag::Severity::Ignored;
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))
582 return diag::Severity::Ignored;
584 return Result;
587 #define GET_DIAG_ARRAYS
588 #include "clang/Basic/DiagnosticGroups.inc"
589 #undef GET_DIAG_ARRAYS
591 namespace {
592 struct WarningOption {
593 uint16_t NameOffset;
594 uint16_t Members;
595 uint16_t SubGroups;
596 StringRef Documentation;
598 // String is stored with a pascal-style length byte.
599 StringRef getName() const {
600 return StringRef(DiagGroupNames + NameOffset + 1,
601 DiagGroupNames[NameOffset]);
606 // Second the table of options, sorted by name for fast binary lookup.
607 static 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
614 /// Given a diagnostic group ID, return its documentation.
615 StringRef DiagnosticIDs::getWarningOptionDocumentation(diag::Group Group) {
616 return OptionTable[static_cast<int>(Group)].Documentation;
619 StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) {
620 return OptionTable[static_cast<int>(Group)].getName();
623 std::optional<diag::Group>
624 DiagnosticIDs::getGroupForWarningOption(StringRef Name) {
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);
632 std::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;
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.
641 StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
642 if (auto G = getGroupForDiag(DiagID))
643 return getWarningOptionForGroup(*G);
644 return StringRef();
647 std::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);
656 return Res;
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.
661 static bool getDiagnosticsInGroup(diag::Flavor Flavor,
662 const WarningOption *Group,
663 SmallVectorImpl<diag::kind> &Diags) {
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;
669 bool NotFound = true;
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);
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);
686 return NotFound;
689 bool
690 DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
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;
698 void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
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);
705 StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
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;
714 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
715 if (Distance > BestDistance)
716 continue;
718 // Don't suggest groups that are not of this kind.
719 llvm::SmallVector<diag::kind, 8> Diags;
720 if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
721 continue;
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;
733 return Best;
736 /// ProcessDiag - This is the method used to report a diagnostic that is
737 /// finally fully formed.
738 bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
739 Diagnostic Info(&Diag);
741 assert(Diag.getClient() && "DiagnosticClient not set!");
743 // Figure out the diagnostic level of this message.
744 unsigned DiagID = Info.getID();
745 DiagnosticIDs::Level DiagLevel
746 = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
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;
756 if (Diag.SuppressAllDiagnostics)
757 return false;
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;
767 Diag.LastDiagLevel = DiagLevel;
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;
778 return false;
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;
788 if (DiagLevel >= DiagnosticIDs::Error) {
789 if (isUnrecoverable(DiagID))
790 Diag.UnrecoverableErrorOccurred = true;
792 // Warnings which have been upgraded to errors do not prevent compilation.
793 if (isDefaultMappingAsError(DiagID))
794 Diag.UncompilableErrorOccurred = true;
796 Diag.ErrorOccurred = true;
797 if (Diag.Client->IncludeInDiagnosticCounts()) {
798 ++Diag.NumErrors;
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;
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;
819 void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
820 Diagnostic Info(&Diag);
821 assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
823 Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
824 if (Diag.Client->IncludeInDiagnosticCounts()) {
825 if (DiagLevel == DiagnosticIDs::Warning)
826 ++Diag.NumWarnings;
829 Diag.CurDiagID = ~0U;
832 bool 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;
839 // Only errors may be unrecoverable.
840 if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
841 return false;
843 if (DiagID == diag::err_unavailable ||
844 DiagID == diag::err_unavailable_message)
845 return false;
847 // Currently we consider all ARC errors as recoverable.
848 if (isARCDiagnostic(DiagID))
849 return false;
851 return true;
854 bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
855 unsigned cat = getCategoryNumberForDiag(DiagID);
856 return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");