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