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