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