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