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 static DiagnosticMapping GetDefaultDiagMapping(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 // 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()));
303 
304   // Initialize the entry if we added it.
305   if (Result.second)
306     Result.first->second = GetDefaultDiagMapping(Diag);
307 
308   return Result.first->second;
309 }
310 
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 }
317 };
318 
319 /// getNumberOfCategories - Return the number of categories
320 unsigned DiagnosticIDs::getNumberOfCategories() {
321   return std::size(CategoryNameTable) - 1;
322 }
323 
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();
331 }
332 
333 
334 
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;
340 }
341 
342 bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
343   if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
344     return Info->Deferrable;
345   return false;
346 }
347 
348 /// getBuiltinDiagClass - Return the class field of the diagnostic.
349 ///
350 static unsigned getBuiltinDiagClass(unsigned DiagID) {
351   if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
352     return Info->Class;
353   return ~0U;
354 }
355 
356 //===----------------------------------------------------------------------===//
357 // Custom Diagnostic information
358 //===----------------------------------------------------------------------===//
359 
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:
367 
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;
374       }
375 
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;
381       }
382 
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;
390 
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;
396       }
397     };
398 
399   } // end diag namespace
400 } // end clang namespace
401 
402 
403 //===----------------------------------------------------------------------===//
404 // Common Diagnostic implementation
405 //===----------------------------------------------------------------------===//
406 
407 DiagnosticIDs::DiagnosticIDs() {}
408 
409 DiagnosticIDs::~DiagnosticIDs() {}
410 
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.
414 ///
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);
421 }
422 
423 
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;
431 }
432 
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;
438 }
439 
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.
444 ///
445 bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
446                                         bool &EnabledByDefault) {
447   if (DiagID >= diag::DIAG_UPPER_LIMIT ||
448       getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
449     return false;
450 
451   EnabledByDefault =
452       GetDefaultDiagMapping(DiagID).getSeverity() != diag::Severity::Ignored;
453   return true;
454 }
455 
456 bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
457   if (DiagID >= diag::DIAG_UPPER_LIMIT)
458     return false;
459 
460   return GetDefaultDiagMapping(DiagID).getSeverity() >= diag::Severity::Error;
461 }
462 
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);
470 }
471 
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;
484   }
485   llvm_unreachable("unexpected severity");
486 }
487 
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);
498   }
499 
500   unsigned DiagClass = getBuiltinDiagClass(DiagID);
501   if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
502   return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
503 }
504 
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.
508 ///
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);
515 
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;
519 
520   // Get the mapping information, or compute it lazily.
521   DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
522   DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
523 
524   // TODO: Can a null severity really get here?
525   if (Mapping.getSeverity() != diag::Severity())
526     Result = Mapping.getSeverity();
527 
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;
532 
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;
540 
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);
545 
546   // At this point, ignored errors can no longer be upgraded.
547   if (Result == diag::Severity::Ignored)
548     return Result;
549 
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;
560   }
561 
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;
566   }
567 
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;
573   }
574 
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;
579 
580   // Custom diagnostics always are emitted in system headers.
581   bool ShowInSystemHeader =
582       !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
583 
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;
591 
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;
598 
599   return Result;
600 }
601 
602 #define GET_DIAG_ARRAYS
603 #include "clang/Basic/DiagnosticGroups.inc"
604 #undef GET_DIAG_ARRAYS
605 
606 namespace {
607   struct WarningOption {
608     uint16_t NameOffset;
609     uint16_t Members;
610     uint16_t SubGroups;
611     StringRef Documentation;
612 
613     // String is stored with a pascal-style length byte.
614     StringRef getName() const {
615       return StringRef(DiagGroupNames + NameOffset + 1,
616                        DiagGroupNames[NameOffset]);
617     }
618   };
619 }
620 
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
627 };
628 
629 /// Given a diagnostic group ID, return its documentation.
630 StringRef DiagnosticIDs::getWarningOptionDocumentation(diag::Group Group) {
631   return OptionTable[static_cast<int>(Group)].Documentation;
632 }
633 
634 StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) {
635   return OptionTable[static_cast<int>(Group)].getName();
636 }
637 
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);
645 }
646 
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;
651 }
652 
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();
660 }
661 
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);
669   }
670 
671   return Res;
672 }
673 
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;
683 
684   bool NotFound = true;
685 
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);
692     }
693   }
694 
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);
700 
701   return NotFound;
702 }
703 
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;
711 }
712 
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);
718 }
719 
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;
728 
729     unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
730     if (Distance > BestDistance)
731       continue;
732 
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;
737 
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;
745     }
746   }
747 
748   return Best;
749 }
750 
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);
755 
756   assert(Diag.getClient() && "DiagnosticClient not set!");
757 
758   // Figure out the diagnostic level of this message.
759   unsigned DiagID = Info.getID();
760   DiagnosticIDs::Level DiagLevel
761     = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
762 
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;
769   }
770 
771   if (Diag.SuppressAllDiagnostics)
772     return false;
773 
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;
781 
782     Diag.LastDiagLevel = DiagLevel;
783   }
784 
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;
791     }
792 
793     return false;
794   }
795 
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;
802 
803   if (DiagLevel >= DiagnosticIDs::Error) {
804     if (isUnrecoverable(DiagID))
805       Diag.UnrecoverableErrorOccurred = true;
806 
807     // Warnings which have been upgraded to errors do not prevent compilation.
808     if (isDefaultMappingAsError(DiagID))
809       Diag.UncompilableErrorOccurred = true;
810 
811     Diag.ErrorOccurred = true;
812     if (Diag.Client->IncludeInDiagnosticCounts()) {
813       ++Diag.NumErrors;
814     }
815 
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;
822     }
823   }
824 
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;
832 }
833 
834 void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
835   Diagnostic Info(&Diag);
836   assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
837 
838   Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
839   if (Diag.Client->IncludeInDiagnosticCounts()) {
840     if (DiagLevel == DiagnosticIDs::Warning)
841       ++Diag.NumWarnings;
842   }
843 
844   Diag.CurDiagID = ~0U;
845 }
846 
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;
852   }
853 
854   // Only errors may be unrecoverable.
855   if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
856     return false;
857 
858   if (DiagID == diag::err_unavailable ||
859       DiagID == diag::err_unavailable_message)
860     return false;
861 
862   // Currently we consider all ARC errors as recoverable.
863   if (isARCDiagnostic(DiagID))
864     return false;
865 
866   return true;
867 }
868 
869 bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
870   unsigned cat = getCategoryNumberForDiag(DiagID);
871   return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
872 }
873