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