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