DiagnosticIDs.cpp revision c0a575f9b791a25c94b1c3c832dd73ec564646bb
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
14#include "clang/AST/ASTDiagnostic.h"
15#include "clang/Analysis/AnalysisDiagnostic.h"
16#include "clang/Basic/DiagnosticIDs.h"
17#include "clang/Basic/DiagnosticCategories.h"
18#include "clang/Basic/SourceManager.h"
19#include "clang/Driver/DriverDiagnostic.h"
20#include "clang/Frontend/FrontendDiagnostic.h"
21#include "clang/Lex/LexDiagnostic.h"
22#include "clang/Parse/ParseDiagnostic.h"
23#include "clang/Sema/SemaDiagnostic.h"
24
25#include <map>
26using namespace clang;
27
28//===----------------------------------------------------------------------===//
29// Builtin Diagnostic information
30//===----------------------------------------------------------------------===//
31
32namespace {
33
34// Diagnostic classes.
35enum {
36  CLASS_NOTE       = 0x01,
37  CLASS_WARNING    = 0x02,
38  CLASS_EXTENSION  = 0x03,
39  CLASS_ERROR      = 0x04
40};
41
42struct StaticDiagInfoRec {
43  unsigned short DiagID;
44  unsigned Mapping : 3;
45  unsigned Class : 3;
46  unsigned SFINAE : 1;
47  unsigned AccessControl : 1;
48  unsigned Category : 5;
49
50  uint8_t  NameLen;
51  uint8_t  OptionGroupLen;
52
53  uint16_t DescriptionLen;
54  uint16_t BriefExplanationLen;
55  uint16_t FullExplanationLen;
56
57  const char *NameStr;
58  const char *OptionGroupStr;
59
60  const char *DescriptionStr;
61  const char *BriefExplanationStr;
62  const char *FullExplanationStr;
63
64  StringRef getName() const {
65    return StringRef(NameStr, NameLen);
66  }
67  StringRef getOptionGroup() const {
68    return StringRef(OptionGroupStr, OptionGroupLen);
69  }
70
71  StringRef getDescription() const {
72    return StringRef(DescriptionStr, DescriptionLen);
73  }
74  StringRef getBriefExplanation() const {
75    return StringRef(BriefExplanationStr, BriefExplanationLen);
76  }
77  StringRef getFullExplanation() const {
78    return StringRef(FullExplanationStr, FullExplanationLen);
79  }
80
81  bool operator<(const StaticDiagInfoRec &RHS) const {
82    return DiagID < RHS.DiagID;
83  }
84};
85
86struct StaticDiagNameIndexRec {
87  const char *NameStr;
88  unsigned short DiagID;
89  uint8_t NameLen;
90
91  StringRef getName() const {
92    return StringRef(NameStr, NameLen);
93  }
94
95  bool operator<(const StaticDiagNameIndexRec &RHS) const {
96    return getName() < RHS.getName();
97  }
98
99  bool operator==(const StaticDiagNameIndexRec &RHS) const {
100    return getName() == RHS.getName();
101  }
102};
103
104template <size_t SizeOfStr, typename FieldType>
105class StringSizerHelper {
106  char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
107public:
108  enum { Size = SizeOfStr };
109};
110
111} // namespace anonymous
112
113#define STR_SIZE(str, fieldTy) StringSizerHelper<sizeof(str)-1, fieldTy>::Size
114
115static const StaticDiagInfoRec StaticDiagInfo[] = {
116#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,               \
117             SFINAE,ACCESS,CATEGORY,BRIEF,FULL)                   \
118  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, \
119    STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t),           \
120    STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t),          \
121    STR_SIZE(FULL, uint16_t),                                     \
122    #ENUM, GROUP, DESC, BRIEF, FULL },
123#include "clang/Basic/DiagnosticCommonKinds.inc"
124#include "clang/Basic/DiagnosticDriverKinds.inc"
125#include "clang/Basic/DiagnosticFrontendKinds.inc"
126#include "clang/Basic/DiagnosticLexKinds.inc"
127#include "clang/Basic/DiagnosticParseKinds.inc"
128#include "clang/Basic/DiagnosticASTKinds.inc"
129#include "clang/Basic/DiagnosticSemaKinds.inc"
130#include "clang/Basic/DiagnosticAnalysisKinds.inc"
131#undef DIAG
132  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
133};
134
135static const unsigned StaticDiagInfoSize =
136  sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
137
138/// To be sorted before first use (since it's splitted among multiple files)
139static const StaticDiagNameIndexRec StaticDiagNameIndex[] = {
140#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
141#include "clang/Basic/DiagnosticIndexName.inc"
142#undef DIAG_NAME_INDEX
143  { 0, 0, 0 }
144};
145
146static const unsigned StaticDiagNameIndexSize =
147  sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
148
149/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
150/// or null if the ID is invalid.
151static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
152  // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
153#ifndef NDEBUG
154  static bool IsFirst = true;
155  if (IsFirst) {
156    for (unsigned i = 1; i != StaticDiagInfoSize; ++i) {
157      assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
158             "Diag ID conflict, the enums at the start of clang::diag (in "
159             "DiagnosticIDs.h) probably need to be increased");
160
161      assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] &&
162             "Improperly sorted diag info");
163    }
164    IsFirst = false;
165  }
166#endif
167
168  // Search the diagnostic table with a binary search.
169  StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 };
170
171  const StaticDiagInfoRec *Found =
172    std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
173  if (Found == StaticDiagInfo + StaticDiagInfoSize ||
174      Found->DiagID != DiagID)
175    return 0;
176
177  return Found;
178}
179
180static unsigned GetDefaultDiagMapping(unsigned DiagID) {
181  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
182    return Info->Mapping;
183  return diag::MAP_FATAL;
184}
185
186/// getWarningOptionForDiag - Return the lowest-level warning option that
187/// enables the specified diagnostic.  If there is no -Wfoo flag that controls
188/// the diagnostic, this returns null.
189StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
190  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
191    return Info->getOptionGroup();
192  return StringRef();
193}
194
195/// getCategoryNumberForDiag - Return the category number that a specified
196/// DiagID belongs to, or 0 if no category.
197unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
198  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
199    return Info->Category;
200  return 0;
201}
202
203namespace {
204  // The diagnostic category names.
205  struct StaticDiagCategoryRec {
206    const char *NameStr;
207    uint8_t NameLen;
208
209    StringRef getName() const {
210      return StringRef(NameStr, NameLen);
211    }
212  };
213}
214
215static const StaticDiagCategoryRec CategoryNameTable[] = {
216#define GET_CATEGORY_TABLE
217#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
218#include "clang/Basic/DiagnosticGroups.inc"
219#undef GET_CATEGORY_TABLE
220  { 0, 0 }
221};
222
223/// getNumberOfCategories - Return the number of categories
224unsigned DiagnosticIDs::getNumberOfCategories() {
225  return sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
226}
227
228/// getCategoryNameFromID - Given a category ID, return the name of the
229/// category, an empty string if CategoryID is zero, or null if CategoryID is
230/// invalid.
231StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
232  if (CategoryID >= getNumberOfCategories())
233   return StringRef();
234  return CategoryNameTable[CategoryID].getName();
235}
236
237
238
239DiagnosticIDs::SFINAEResponse
240DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
241  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
242    if (Info->AccessControl)
243      return SFINAE_AccessControl;
244
245    if (!Info->SFINAE)
246      return SFINAE_Report;
247
248    if (Info->Class == CLASS_ERROR)
249      return SFINAE_SubstitutionFailure;
250
251    // Suppress notes, warnings, and extensions;
252    return SFINAE_Suppress;
253  }
254
255  return SFINAE_Report;
256}
257
258/// getName - Given a diagnostic ID, return its name
259StringRef DiagnosticIDs::getName(unsigned DiagID) {
260  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
261    return Info->getName();
262  return StringRef();
263}
264
265/// getIdFromName - Given a diagnostic name, return its ID, or 0
266unsigned DiagnosticIDs::getIdFromName(StringRef Name) {
267  const StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
268    StaticDiagNameIndex + StaticDiagNameIndexSize;
269
270  if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; }
271
272  StaticDiagNameIndexRec Find = { Name.data(), 0, Name.size() };
273
274  const StaticDiagNameIndexRec *Found =
275    std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
276  if (Found == StaticDiagNameIndexEnd ||
277      Found->getName() != Name)
278    return diag::DIAG_UPPER_LIMIT;
279
280  return Found->DiagID;
281}
282
283/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
284/// of the issue
285StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
286  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
287    return Info->getBriefExplanation();
288  return StringRef();
289}
290
291/// getFullExplanation - Given a diagnostic ID, return a full explanation
292/// of the issue
293StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) {
294  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
295    return Info->getFullExplanation();
296  return StringRef();
297}
298
299/// getBuiltinDiagClass - Return the class field of the diagnostic.
300///
301static unsigned getBuiltinDiagClass(unsigned DiagID) {
302  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
303    return Info->Class;
304  return ~0U;
305}
306
307//===----------------------------------------------------------------------===//
308// Custom Diagnostic information
309//===----------------------------------------------------------------------===//
310
311namespace clang {
312  namespace diag {
313    class CustomDiagInfo {
314      typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
315      std::vector<DiagDesc> DiagInfo;
316      std::map<DiagDesc, unsigned> DiagIDs;
317    public:
318
319      /// getDescription - Return the description of the specified custom
320      /// diagnostic.
321      StringRef getDescription(unsigned DiagID) const {
322        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
323               "Invalid diagnosic ID");
324        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
325      }
326
327      /// getLevel - Return the level of the specified custom diagnostic.
328      DiagnosticIDs::Level getLevel(unsigned DiagID) const {
329        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
330               "Invalid diagnosic ID");
331        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
332      }
333
334      unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
335                                 DiagnosticIDs &Diags) {
336        DiagDesc D(L, Message);
337        // Check to see if it already exists.
338        std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
339        if (I != DiagIDs.end() && I->first == D)
340          return I->second;
341
342        // If not, assign a new ID.
343        unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
344        DiagIDs.insert(std::make_pair(D, ID));
345        DiagInfo.push_back(D);
346        return ID;
347      }
348    };
349
350  } // end diag namespace
351} // end clang namespace
352
353
354//===----------------------------------------------------------------------===//
355// Common Diagnostic implementation
356//===----------------------------------------------------------------------===//
357
358DiagnosticIDs::DiagnosticIDs() {
359  CustomDiagInfo = 0;
360}
361
362DiagnosticIDs::~DiagnosticIDs() {
363  delete CustomDiagInfo;
364}
365
366/// getCustomDiagID - Return an ID for a diagnostic with the specified message
367/// and level.  If this is the first request for this diagnosic, it is
368/// registered and created, otherwise the existing ID is returned.
369unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef Message) {
370  if (CustomDiagInfo == 0)
371    CustomDiagInfo = new diag::CustomDiagInfo();
372  return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
373}
374
375
376/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
377/// level of the specified diagnostic ID is a Warning or Extension.
378/// This only works on builtin diagnostics, not custom ones, and is not legal to
379/// call on NOTEs.
380bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
381  return DiagID < diag::DIAG_UPPER_LIMIT &&
382         getBuiltinDiagClass(DiagID) != CLASS_ERROR;
383}
384
385/// \brief Determine whether the given built-in diagnostic ID is a
386/// Note.
387bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
388  return DiagID < diag::DIAG_UPPER_LIMIT &&
389    getBuiltinDiagClass(DiagID) == CLASS_NOTE;
390}
391
392/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
393/// ID is for an extension of some sort.  This also returns EnabledByDefault,
394/// which is set to indicate whether the diagnostic is ignored by default (in
395/// which case -pedantic enables it) or treated as a warning/error by default.
396///
397bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
398                                        bool &EnabledByDefault) {
399  if (DiagID >= diag::DIAG_UPPER_LIMIT ||
400      getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
401    return false;
402
403  EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE;
404  return true;
405}
406
407/// getDescription - Given a diagnostic ID, return a description of the
408/// issue.
409StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
410  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
411    return Info->getDescription();
412  return CustomDiagInfo->getDescription(DiagID);
413}
414
415/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
416/// object, classify the specified diagnostic ID into a Level, consumable by
417/// the DiagnosticClient.
418DiagnosticIDs::Level
419DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
420                                  const Diagnostic &Diag,
421                                  diag::Mapping *mapping) const {
422  // Handle custom diagnostics, which cannot be mapped.
423  if (DiagID >= diag::DIAG_UPPER_LIMIT)
424    return CustomDiagInfo->getLevel(DiagID);
425
426  unsigned DiagClass = getBuiltinDiagClass(DiagID);
427  assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
428  return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag, mapping);
429}
430
431/// \brief Based on the way the client configured the Diagnostic
432/// object, classify the specified diagnostic ID into a Level, consumable by
433/// the DiagnosticClient.
434///
435/// \param Loc The source location we are interested in finding out the
436/// diagnostic state. Can be null in order to query the latest state.
437DiagnosticIDs::Level
438DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
439                                  SourceLocation Loc,
440                                  const Diagnostic &Diag,
441                                  diag::Mapping *mapping) const {
442  // Specific non-error diagnostics may be mapped to various levels from ignored
443  // to error.  Errors can only be mapped to fatal.
444  DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
445
446  Diagnostic::DiagStatePointsTy::iterator
447    Pos = Diag.GetDiagStatePointForLoc(Loc);
448  Diagnostic::DiagState *State = Pos->State;
449
450  // Get the mapping information, if unset, compute it lazily.
451  unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID,
452                                                       State);
453  if (MappingInfo == 0) {
454    MappingInfo = GetDefaultDiagMapping(DiagID);
455    Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
456  }
457
458  if (mapping)
459    *mapping = (diag::Mapping) (MappingInfo & 7);
460
461  bool ShouldEmitInSystemHeader = false;
462
463  switch (MappingInfo & 7) {
464  default: assert(0 && "Unknown mapping!");
465  case diag::MAP_IGNORE:
466    // Ignore this, unless this is an extension diagnostic and we're mapping
467    // them onto warnings or errors.
468    if (!isBuiltinExtensionDiag(DiagID) ||  // Not an extension
469        Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored
470        (MappingInfo & 8) != 0)             // User explicitly mapped it.
471      return DiagnosticIDs::Ignored;
472    Result = DiagnosticIDs::Warning;
473    if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error;
474    if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
475      Result = DiagnosticIDs::Fatal;
476    break;
477  case diag::MAP_ERROR:
478    Result = DiagnosticIDs::Error;
479    if (Diag.ErrorsAsFatal)
480      Result = DiagnosticIDs::Fatal;
481    break;
482  case diag::MAP_FATAL:
483    Result = DiagnosticIDs::Fatal;
484    break;
485  case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER:
486    ShouldEmitInSystemHeader = true;
487    // continue as MAP_WARNING.
488  case diag::MAP_WARNING:
489    // If warnings are globally mapped to ignore or error, do it.
490    if (Diag.IgnoreAllWarnings)
491      return DiagnosticIDs::Ignored;
492
493    Result = DiagnosticIDs::Warning;
494
495    // If this is an extension diagnostic and we're in -pedantic-error mode, and
496    // if the user didn't explicitly map it, upgrade to an error.
497    if (Diag.ExtBehavior == Diagnostic::Ext_Error &&
498        (MappingInfo & 8) == 0 &&
499        isBuiltinExtensionDiag(DiagID))
500      Result = DiagnosticIDs::Error;
501
502    if (Diag.WarningsAsErrors)
503      Result = DiagnosticIDs::Error;
504    if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
505      Result = DiagnosticIDs::Fatal;
506    break;
507
508  case diag::MAP_WARNING_NO_WERROR:
509    // Diagnostics specified with -Wno-error=foo should be set to warnings, but
510    // not be adjusted by -Werror or -pedantic-errors.
511    Result = DiagnosticIDs::Warning;
512
513    // If warnings are globally mapped to ignore or error, do it.
514    if (Diag.IgnoreAllWarnings)
515      return DiagnosticIDs::Ignored;
516
517    break;
518
519  case diag::MAP_ERROR_NO_WFATAL:
520    // Diagnostics specified as -Wno-fatal-error=foo should be errors, but
521    // unaffected by -Wfatal-errors.
522    Result = DiagnosticIDs::Error;
523    break;
524  }
525
526  // Okay, we're about to return this as a "diagnostic to emit" one last check:
527  // if this is any sort of extension warning, and if we're in an __extension__
528  // block, silence it.
529  if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
530    return DiagnosticIDs::Ignored;
531
532  // If we are in a system header, we ignore it.
533  // We also want to ignore extensions and warnings in -Werror and
534  // -pedantic-errors modes, which *map* warnings/extensions to errors.
535  if (Result >= DiagnosticIDs::Warning &&
536      DiagClass != CLASS_ERROR &&
537      // Custom diagnostics always are emitted in system headers.
538      DiagID < diag::DIAG_UPPER_LIMIT &&
539      !ShouldEmitInSystemHeader &&
540      Diag.SuppressSystemWarnings &&
541      Loc.isValid() &&
542      Diag.getSourceManager().isInSystemHeader(
543          Diag.getSourceManager().getExpansionLoc(Loc)))
544    return DiagnosticIDs::Ignored;
545
546  return Result;
547}
548
549namespace {
550  struct WarningOption {
551    // Be safe with the size of 'NameLen' because we don't statically check if
552    // the size will fit in the field; the struct size won't decrease with a
553    // shorter type anyway.
554    size_t NameLen;
555    const char *NameStr;
556    const short *Members;
557    const short *SubGroups;
558
559    StringRef getName() const {
560      return StringRef(NameStr, NameLen);
561    }
562  };
563}
564
565#define GET_DIAG_ARRAYS
566#include "clang/Basic/DiagnosticGroups.inc"
567#undef GET_DIAG_ARRAYS
568
569// Second the table of options, sorted by name for fast binary lookup.
570static const WarningOption OptionTable[] = {
571#define GET_DIAG_TABLE
572#include "clang/Basic/DiagnosticGroups.inc"
573#undef GET_DIAG_TABLE
574};
575static const size_t OptionTableSize =
576sizeof(OptionTable) / sizeof(OptionTable[0]);
577
578static bool WarningOptionCompare(const WarningOption &LHS,
579                                 const WarningOption &RHS) {
580  return LHS.getName() < RHS.getName();
581}
582
583static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
584                            SourceLocation Loc, Diagnostic &Diag) {
585  // Option exists, poke all the members of its diagnostic set.
586  if (const short *Member = Group->Members) {
587    for (; *Member != -1; ++Member)
588      Diag.setDiagnosticMapping(*Member, Mapping, Loc);
589  }
590
591  // Enable/disable all subgroups along with this one.
592  if (const short *SubGroups = Group->SubGroups) {
593    for (; *SubGroups != (short)-1; ++SubGroups)
594      MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag);
595  }
596}
597
598/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
599/// "unknown-pragmas" to have the specified mapping.  This returns true and
600/// ignores the request if "Group" was unknown, false otherwise.
601bool DiagnosticIDs::setDiagnosticGroupMapping(StringRef Group,
602                                              diag::Mapping Map,
603                                              SourceLocation Loc,
604                                              Diagnostic &Diag) const {
605  assert((Loc.isValid() ||
606          Diag.DiagStatePoints.empty() ||
607          Diag.DiagStatePoints.back().Loc.isInvalid()) &&
608         "Loc should be invalid only when the mapping comes from command-line");
609  assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() ||
610          Diag.DiagStatePoints.back().Loc.isInvalid() ||
611          !Diag.SourceMgr->isBeforeInTranslationUnit(Loc,
612                                            Diag.DiagStatePoints.back().Loc)) &&
613         "Source location of new mapping is before the previous one!");
614
615  WarningOption Key = { Group.size(), Group.data(), 0, 0 };
616  const WarningOption *Found =
617  std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
618                   WarningOptionCompare);
619  if (Found == OptionTable + OptionTableSize ||
620      Found->getName() != Group)
621    return true;  // Option not found.
622
623  MapGroupMembers(Found, Map, Loc, Diag);
624  return false;
625}
626
627/// ProcessDiag - This is the method used to report a diagnostic that is
628/// finally fully formed.
629bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
630  DiagnosticInfo Info(&Diag);
631
632  if (Diag.SuppressAllDiagnostics)
633    return false;
634
635  assert(Diag.getClient() && "DiagnosticClient not set!");
636
637  // Figure out the diagnostic level of this message.
638  DiagnosticIDs::Level DiagLevel;
639  unsigned DiagID = Info.getID();
640
641  if (DiagID >= diag::DIAG_UPPER_LIMIT) {
642    // Handle custom diagnostics, which cannot be mapped.
643    DiagLevel = CustomDiagInfo->getLevel(DiagID);
644  } else {
645    // Get the class of the diagnostic.  If this is a NOTE, map it onto whatever
646    // the diagnostic level was for the previous diagnostic so that it is
647    // filtered the same as the previous diagnostic.
648    unsigned DiagClass = getBuiltinDiagClass(DiagID);
649    if (DiagClass == CLASS_NOTE) {
650      DiagLevel = DiagnosticIDs::Note;
651    } else {
652      DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
653                                     Diag);
654    }
655  }
656
657  if (DiagLevel != DiagnosticIDs::Note) {
658    // Record that a fatal error occurred only when we see a second
659    // non-note diagnostic. This allows notes to be attached to the
660    // fatal error, but suppresses any diagnostics that follow those
661    // notes.
662    if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
663      Diag.FatalErrorOccurred = true;
664
665    Diag.LastDiagLevel = DiagLevel;
666  }
667
668  // Update counts for DiagnosticErrorTrap even if a fatal error occurred.
669  if (DiagLevel >= DiagnosticIDs::Error) {
670    ++Diag.TrapNumErrorsOccurred;
671    if (isUnrecoverable(DiagID))
672      ++Diag.TrapNumUnrecoverableErrorsOccurred;
673  }
674
675  // If a fatal error has already been emitted, silence all subsequent
676  // diagnostics.
677  if (Diag.FatalErrorOccurred) {
678    if (DiagLevel >= DiagnosticIDs::Error &&
679        Diag.Client->IncludeInDiagnosticCounts()) {
680      ++Diag.NumErrors;
681      ++Diag.NumErrorsSuppressed;
682    }
683
684    return false;
685  }
686
687  // If the client doesn't care about this message, don't issue it.  If this is
688  // a note and the last real diagnostic was ignored, ignore it too.
689  if (DiagLevel == DiagnosticIDs::Ignored ||
690      (DiagLevel == DiagnosticIDs::Note &&
691       Diag.LastDiagLevel == DiagnosticIDs::Ignored))
692    return false;
693
694  if (DiagLevel >= DiagnosticIDs::Error) {
695    if (isUnrecoverable(DiagID))
696      Diag.UnrecoverableErrorOccurred = true;
697
698    if (Diag.Client->IncludeInDiagnosticCounts()) {
699      Diag.ErrorOccurred = true;
700      ++Diag.NumErrors;
701    }
702
703    // If we've emitted a lot of errors, emit a fatal error after it to stop a
704    // flood of bogus errors.
705    if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit &&
706        DiagLevel == DiagnosticIDs::Error)
707      Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
708  }
709
710  // If we have any Fix-Its, make sure that all of the Fix-Its point into
711  // source locations that aren't macro expansions. If any point into macro
712  // expansions, remove all of the Fix-Its.
713  for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) {
714    const FixItHint &FixIt = Diag.FixItHints[I];
715    if (FixIt.RemoveRange.isInvalid() ||
716        FixIt.RemoveRange.getBegin().isMacroID() ||
717        FixIt.RemoveRange.getEnd().isMacroID()) {
718      Diag.NumFixItHints = 0;
719      break;
720    }
721  }
722
723  // Finally, report it.
724  Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info);
725  if (Diag.Client->IncludeInDiagnosticCounts()) {
726    if (DiagLevel == DiagnosticIDs::Warning)
727      ++Diag.NumWarnings;
728  }
729
730  Diag.CurDiagID = ~0U;
731
732  return true;
733}
734
735bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
736  if (DiagID >= diag::DIAG_UPPER_LIMIT) {
737    // Custom diagnostics.
738    return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
739  }
740
741  // Only errors may be unrecoverable.
742  if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
743    return false;
744
745  if (DiagID == diag::err_unavailable ||
746      DiagID == diag::err_unavailable_message)
747    return false;
748
749  // Currently we consider all ARC errors as recoverable.
750  if (getCategoryNumberForDiag(DiagID) ==
751        diag::DiagCat_Automatic_Reference_Counting_Issue)
752    return false;
753
754  return true;
755}
756