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