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>
21using namespace clang;
22
23//===----------------------------------------------------------------------===//
24// Builtin Diagnostic information
25//===----------------------------------------------------------------------===//
26
27namespace {
28
29// Diagnostic classes.
30enum {
31  CLASS_NOTE       = 0x01,
32  CLASS_REMARK     = 0x02,
33  CLASS_WARNING    = 0x03,
34  CLASS_EXTENSION  = 0x04,
35  CLASS_ERROR      = 0x05
36};
37
38struct 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.");
80VALIDATE_DIAG_SIZE(COMMON)
81VALIDATE_DIAG_SIZE(DRIVER)
82VALIDATE_DIAG_SIZE(FRONTEND)
83VALIDATE_DIAG_SIZE(SERIALIZATION)
84VALIDATE_DIAG_SIZE(LEX)
85VALIDATE_DIAG_SIZE(PARSE)
86VALIDATE_DIAG_SIZE(AST)
87VALIDATE_DIAG_SIZE(COMMENT)
88VALIDATE_DIAG_SIZE(CROSSTU)
89VALIDATE_DIAG_SIZE(SEMA)
90VALIDATE_DIAG_SIZE(ANALYSIS)
91VALIDATE_DIAG_SIZE(REFACTORING)
92#undef VALIDATE_DIAG_SIZE
93#undef STRINGIFY_NAME
94
95} // namespace anonymous
96
97static 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
120static 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.
124static 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  }
145CATEGORY(DRIVER, COMMON)
146CATEGORY(FRONTEND, DRIVER)
147CATEGORY(SERIALIZATION, FRONTEND)
148CATEGORY(LEX, SERIALIZATION)
149CATEGORY(PARSE, LEX)
150CATEGORY(AST, PARSE)
151CATEGORY(COMMENT, AST)
152CATEGORY(CROSSTU, COMMENT)
153CATEGORY(SEMA, CROSSTU)
154CATEGORY(ANALYSIS, SEMA)
155CATEGORY(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
173static 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.
192unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
193  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
194    return Info->Category;
195  return 0;
196}
197
198namespace {
199  // The diagnostic category names.
200  struct StaticDiagCategoryRec {
201    const char *NameStr;
202    uint8_t NameLen;
203
204    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.
213DiagnosticMapping &
214DiagnosticsEngine::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
225static 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
234unsigned 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.
241StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
242  if (CategoryID >= getNumberOfCategories())
243   return StringRef();
244  return CategoryNameTable[CategoryID].getName();
245}
246
247
248
249DiagnosticIDs::SFINAEResponse
250DiagnosticIDs::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///
258static 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
268namespace 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.
278      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.
285      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
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
315DiagnosticIDs::DiagnosticIDs() {}
316
317DiagnosticIDs::~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.
325unsigned 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.
336bool 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.
343bool 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///
353bool 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
364bool 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.
373StringRef 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
380static 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.
399DiagnosticIDs::Level
400DiagnosticIDs::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.
419diag::Severity
420DiagnosticIDs::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
507namespace {
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.
514    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.
522static 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.
531StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
532  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
533    return OptionTable[Info->getOptionGroupIndex()].getName();
534  return StringRef();
535}
536
537std::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.
551static 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
579bool
580DiagnosticIDs::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
590void 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
597StringRef 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.
630bool 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
711void 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
724bool 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
746bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
747  unsigned cat = getCategoryNumberForDiag(DiagID);
748  return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
749}
750