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