DiagnosticIDs.cpp revision 221345
1218887Sdim//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim//  This file implements the Diagnostic IDs-related interfaces.
11218887Sdim//
12218887Sdim//===----------------------------------------------------------------------===//
13218887Sdim
14218887Sdim#include "clang/AST/ASTDiagnostic.h"
15218887Sdim#include "clang/Analysis/AnalysisDiagnostic.h"
16218887Sdim#include "clang/Basic/DiagnosticIDs.h"
17218887Sdim#include "clang/Basic/SourceManager.h"
18218887Sdim#include "clang/Driver/DriverDiagnostic.h"
19218887Sdim#include "clang/Frontend/FrontendDiagnostic.h"
20218887Sdim#include "clang/Lex/LexDiagnostic.h"
21218887Sdim#include "clang/Parse/ParseDiagnostic.h"
22218887Sdim#include "clang/Sema/SemaDiagnostic.h"
23218887Sdim
24218887Sdim#include <map>
25218887Sdimusing namespace clang;
26218887Sdim
27218887Sdim//===----------------------------------------------------------------------===//
28218887Sdim// Builtin Diagnostic information
29218887Sdim//===----------------------------------------------------------------------===//
30218887Sdim
31218887Sdimnamespace {
32218887Sdim
33218887Sdim// Diagnostic classes.
34218887Sdimenum {
35218887Sdim  CLASS_NOTE       = 0x01,
36218887Sdim  CLASS_WARNING    = 0x02,
37218887Sdim  CLASS_EXTENSION  = 0x03,
38218887Sdim  CLASS_ERROR      = 0x04
39218887Sdim};
40218887Sdim
41218887Sdimstruct StaticDiagInfoRec {
42218887Sdim  unsigned short DiagID;
43218887Sdim  unsigned Mapping : 3;
44218887Sdim  unsigned Class : 3;
45218887Sdim  unsigned SFINAE : 1;
46218887Sdim  unsigned AccessControl : 1;
47218887Sdim  unsigned Category : 5;
48218887Sdim
49221345Sdim  const char *Name;
50221345Sdim
51218887Sdim  const char *Description;
52218887Sdim  const char *OptionGroup;
53218887Sdim
54221345Sdim  const char *BriefExplanation;
55221345Sdim  const char *FullExplanation;
56221345Sdim
57218887Sdim  bool operator<(const StaticDiagInfoRec &RHS) const {
58218887Sdim    return DiagID < RHS.DiagID;
59218887Sdim  }
60218887Sdim};
61218887Sdim
62221345Sdimstruct StaticDiagNameIndexRec {
63221345Sdim  const char *Name;
64221345Sdim  unsigned short DiagID;
65221345Sdim
66221345Sdim  bool operator<(const StaticDiagNameIndexRec &RHS) const {
67221345Sdim    assert(Name && RHS.Name && "Null Diagnostic Name");
68221345Sdim    return strcmp(Name, RHS.Name) == -1;
69221345Sdim  }
70221345Sdim
71221345Sdim  bool operator==(const StaticDiagNameIndexRec &RHS) const {
72221345Sdim    assert(Name && RHS.Name && "Null Diagnostic Name");
73221345Sdim    return strcmp(Name, RHS.Name) == 0;
74221345Sdim  }
75221345Sdim};
76221345Sdim
77218887Sdim}
78218887Sdim
79218887Sdimstatic const StaticDiagInfoRec StaticDiagInfo[] = {
80221345Sdim#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,     \
81221345Sdim             SFINAE,ACCESS,CATEGORY,BRIEF,FULL)         \
82221345Sdim  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE,         \
83221345Sdim   ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL },
84218887Sdim#include "clang/Basic/DiagnosticCommonKinds.inc"
85218887Sdim#include "clang/Basic/DiagnosticDriverKinds.inc"
86218887Sdim#include "clang/Basic/DiagnosticFrontendKinds.inc"
87218887Sdim#include "clang/Basic/DiagnosticLexKinds.inc"
88218887Sdim#include "clang/Basic/DiagnosticParseKinds.inc"
89218887Sdim#include "clang/Basic/DiagnosticASTKinds.inc"
90218887Sdim#include "clang/Basic/DiagnosticSemaKinds.inc"
91218887Sdim#include "clang/Basic/DiagnosticAnalysisKinds.inc"
92221345Sdim#undef DIAG
93221345Sdim  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
94218887Sdim};
95218887Sdim
96221345Sdimstatic const unsigned StaticDiagInfoSize =
97221345Sdim  sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
98221345Sdim
99221345Sdim/// To be sorted before first use (since it's splitted among multiple files)
100221345Sdimstatic StaticDiagNameIndexRec StaticDiagNameIndex[] = {
101221345Sdim#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM },
102221345Sdim#include "clang/Basic/DiagnosticIndexName.inc"
103221345Sdim#undef DIAG_NAME_INDEX
104221345Sdim  { 0, 0 }
105221345Sdim};
106221345Sdim
107221345Sdimstatic const unsigned StaticDiagNameIndexSize =
108221345Sdim  sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
109221345Sdim
110218887Sdim/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
111218887Sdim/// or null if the ID is invalid.
112218887Sdimstatic const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
113218887Sdim  // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
114218887Sdim#ifndef NDEBUG
115218887Sdim  static bool IsFirst = true;
116218887Sdim  if (IsFirst) {
117221345Sdim    for (unsigned i = 1; i != StaticDiagInfoSize; ++i) {
118218887Sdim      assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
119218887Sdim             "Diag ID conflict, the enums at the start of clang::diag (in "
120218887Sdim             "DiagnosticIDs.h) probably need to be increased");
121218887Sdim
122218887Sdim      assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] &&
123218887Sdim             "Improperly sorted diag info");
124218887Sdim    }
125218887Sdim    IsFirst = false;
126218887Sdim  }
127218887Sdim#endif
128218887Sdim
129218887Sdim  // Search the diagnostic table with a binary search.
130221345Sdim  StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
131218887Sdim
132218887Sdim  const StaticDiagInfoRec *Found =
133221345Sdim    std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
134221345Sdim  if (Found == StaticDiagInfo + StaticDiagInfoSize ||
135218887Sdim      Found->DiagID != DiagID)
136218887Sdim    return 0;
137218887Sdim
138218887Sdim  return Found;
139218887Sdim}
140218887Sdim
141218887Sdimstatic unsigned GetDefaultDiagMapping(unsigned DiagID) {
142218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
143218887Sdim    return Info->Mapping;
144218887Sdim  return diag::MAP_FATAL;
145218887Sdim}
146218887Sdim
147218887Sdim/// getWarningOptionForDiag - Return the lowest-level warning option that
148218887Sdim/// enables the specified diagnostic.  If there is no -Wfoo flag that controls
149218887Sdim/// the diagnostic, this returns null.
150218887Sdimconst char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
151218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
152218887Sdim    return Info->OptionGroup;
153218887Sdim  return 0;
154218887Sdim}
155218887Sdim
156221345Sdim/// getCategoryNumberForDiag - Return the category number that a specified
157218887Sdim/// DiagID belongs to, or 0 if no category.
158218887Sdimunsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
159218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
160218887Sdim    return Info->Category;
161218887Sdim  return 0;
162218887Sdim}
163218887Sdim
164218887Sdim/// getCategoryNameFromID - Given a category ID, return the name of the
165218887Sdim/// category, an empty string if CategoryID is zero, or null if CategoryID is
166218887Sdim/// invalid.
167218887Sdimconst char *DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
168218887Sdim  // Second the table of options, sorted by name for fast binary lookup.
169218887Sdim  static const char *CategoryNameTable[] = {
170218887Sdim#define GET_CATEGORY_TABLE
171218887Sdim#define CATEGORY(X) X,
172218887Sdim#include "clang/Basic/DiagnosticGroups.inc"
173218887Sdim#undef GET_CATEGORY_TABLE
174218887Sdim    "<<END>>"
175218887Sdim  };
176218887Sdim  static const size_t CategoryNameTableSize =
177218887Sdim    sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
178218887Sdim
179218887Sdim  if (CategoryID >= CategoryNameTableSize) return 0;
180218887Sdim  return CategoryNameTable[CategoryID];
181218887Sdim}
182218887Sdim
183218887Sdim
184218887Sdim
185218887SdimDiagnosticIDs::SFINAEResponse
186218887SdimDiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
187218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
188218887Sdim    if (Info->AccessControl)
189218887Sdim      return SFINAE_AccessControl;
190218887Sdim
191218887Sdim    if (!Info->SFINAE)
192218887Sdim      return SFINAE_Report;
193218887Sdim
194218887Sdim    if (Info->Class == CLASS_ERROR)
195218887Sdim      return SFINAE_SubstitutionFailure;
196218887Sdim
197218887Sdim    // Suppress notes, warnings, and extensions;
198218887Sdim    return SFINAE_Suppress;
199218887Sdim  }
200218887Sdim
201218887Sdim  return SFINAE_Report;
202218887Sdim}
203218887Sdim
204221345Sdim/// getName - Given a diagnostic ID, return its name
205221345Sdimconst char *DiagnosticIDs::getName(unsigned DiagID) {
206221345Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
207221345Sdim    return Info->Name;
208221345Sdim  return 0;
209221345Sdim}
210221345Sdim
211221345Sdim/// getIdFromName - Given a diagnostic name, return its ID, or 0
212221345Sdimunsigned DiagnosticIDs::getIdFromName(char const *Name) {
213221345Sdim  StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
214221345Sdim    StaticDiagNameIndex + StaticDiagNameIndexSize;
215221345Sdim
216221345Sdim  if (Name == 0) { return diag::DIAG_UPPER_LIMIT; }
217221345Sdim
218221345Sdim  StaticDiagNameIndexRec Find = { Name, 0 };
219221345Sdim
220221345Sdim  const StaticDiagNameIndexRec *Found =
221221345Sdim    std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
222221345Sdim  if (Found == StaticDiagNameIndexEnd ||
223221345Sdim      strcmp(Found->Name, Name) != 0)
224221345Sdim    return diag::DIAG_UPPER_LIMIT;
225221345Sdim
226221345Sdim  return Found->DiagID;
227221345Sdim}
228221345Sdim
229221345Sdim/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
230221345Sdim/// of the issue
231221345Sdimconst char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
232221345Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
233221345Sdim    return Info->BriefExplanation;
234221345Sdim  return 0;
235221345Sdim}
236221345Sdim
237221345Sdim/// getFullExplanation - Given a diagnostic ID, return a full explanation
238221345Sdim/// of the issue
239221345Sdimconst char *DiagnosticIDs::getFullExplanation(unsigned DiagID) {
240221345Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
241221345Sdim    return Info->FullExplanation;
242221345Sdim  return 0;
243221345Sdim}
244221345Sdim
245221345Sdim/// getBuiltinDiagClass - Return the class field of the diagnostic.
246218887Sdim///
247218887Sdimstatic unsigned getBuiltinDiagClass(unsigned DiagID) {
248218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
249218887Sdim    return Info->Class;
250218887Sdim  return ~0U;
251218887Sdim}
252218887Sdim
253218887Sdim//===----------------------------------------------------------------------===//
254218887Sdim// Custom Diagnostic information
255218887Sdim//===----------------------------------------------------------------------===//
256218887Sdim
257218887Sdimnamespace clang {
258218887Sdim  namespace diag {
259218887Sdim    class CustomDiagInfo {
260218887Sdim      typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
261218887Sdim      std::vector<DiagDesc> DiagInfo;
262218887Sdim      std::map<DiagDesc, unsigned> DiagIDs;
263218887Sdim    public:
264218887Sdim
265218887Sdim      /// getDescription - Return the description of the specified custom
266218887Sdim      /// diagnostic.
267218887Sdim      const char *getDescription(unsigned DiagID) const {
268218887Sdim        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
269218887Sdim               "Invalid diagnosic ID");
270218887Sdim        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str();
271218887Sdim      }
272218887Sdim
273218887Sdim      /// getLevel - Return the level of the specified custom diagnostic.
274218887Sdim      DiagnosticIDs::Level getLevel(unsigned DiagID) const {
275218887Sdim        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
276218887Sdim               "Invalid diagnosic ID");
277218887Sdim        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
278218887Sdim      }
279218887Sdim
280218887Sdim      unsigned getOrCreateDiagID(DiagnosticIDs::Level L, llvm::StringRef Message,
281218887Sdim                                 DiagnosticIDs &Diags) {
282218887Sdim        DiagDesc D(L, Message);
283218887Sdim        // Check to see if it already exists.
284218887Sdim        std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
285218887Sdim        if (I != DiagIDs.end() && I->first == D)
286218887Sdim          return I->second;
287218887Sdim
288218887Sdim        // If not, assign a new ID.
289218887Sdim        unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
290218887Sdim        DiagIDs.insert(std::make_pair(D, ID));
291218887Sdim        DiagInfo.push_back(D);
292218887Sdim        return ID;
293218887Sdim      }
294218887Sdim    };
295218887Sdim
296218887Sdim  } // end diag namespace
297218887Sdim} // end clang namespace
298218887Sdim
299218887Sdim
300218887Sdim//===----------------------------------------------------------------------===//
301218887Sdim// Common Diagnostic implementation
302218887Sdim//===----------------------------------------------------------------------===//
303218887Sdim
304218887SdimDiagnosticIDs::DiagnosticIDs() {
305218887Sdim  CustomDiagInfo = 0;
306218887Sdim}
307218887Sdim
308218887SdimDiagnosticIDs::~DiagnosticIDs() {
309218887Sdim  delete CustomDiagInfo;
310218887Sdim}
311218887Sdim
312218887Sdim/// getCustomDiagID - Return an ID for a diagnostic with the specified message
313218887Sdim/// and level.  If this is the first request for this diagnosic, it is
314218887Sdim/// registered and created, otherwise the existing ID is returned.
315218887Sdimunsigned DiagnosticIDs::getCustomDiagID(Level L, llvm::StringRef Message) {
316218887Sdim  if (CustomDiagInfo == 0)
317218887Sdim    CustomDiagInfo = new diag::CustomDiagInfo();
318218887Sdim  return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
319218887Sdim}
320218887Sdim
321218887Sdim
322218887Sdim/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
323218887Sdim/// level of the specified diagnostic ID is a Warning or Extension.
324218887Sdim/// This only works on builtin diagnostics, not custom ones, and is not legal to
325218887Sdim/// call on NOTEs.
326218887Sdimbool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
327218887Sdim  return DiagID < diag::DIAG_UPPER_LIMIT &&
328218887Sdim         getBuiltinDiagClass(DiagID) != CLASS_ERROR;
329218887Sdim}
330218887Sdim
331218887Sdim/// \brief Determine whether the given built-in diagnostic ID is a
332218887Sdim/// Note.
333218887Sdimbool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
334218887Sdim  return DiagID < diag::DIAG_UPPER_LIMIT &&
335218887Sdim    getBuiltinDiagClass(DiagID) == CLASS_NOTE;
336218887Sdim}
337218887Sdim
338218887Sdim/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
339218887Sdim/// ID is for an extension of some sort.  This also returns EnabledByDefault,
340218887Sdim/// which is set to indicate whether the diagnostic is ignored by default (in
341218887Sdim/// which case -pedantic enables it) or treated as a warning/error by default.
342218887Sdim///
343218887Sdimbool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
344218887Sdim                                        bool &EnabledByDefault) {
345218887Sdim  if (DiagID >= diag::DIAG_UPPER_LIMIT ||
346218887Sdim      getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
347218887Sdim    return false;
348218887Sdim
349218887Sdim  EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE;
350218887Sdim  return true;
351218887Sdim}
352218887Sdim
353218887Sdim/// getDescription - Given a diagnostic ID, return a description of the
354218887Sdim/// issue.
355218887Sdimconst char *DiagnosticIDs::getDescription(unsigned DiagID) const {
356218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
357218887Sdim    return Info->Description;
358218887Sdim  return CustomDiagInfo->getDescription(DiagID);
359218887Sdim}
360218887Sdim
361218887Sdim/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
362218887Sdim/// object, classify the specified diagnostic ID into a Level, consumable by
363218887Sdim/// the DiagnosticClient.
364218887SdimDiagnosticIDs::Level
365218887SdimDiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
366219077Sdim                                  const Diagnostic &Diag,
367219077Sdim                                  diag::Mapping *mapping) const {
368218887Sdim  // Handle custom diagnostics, which cannot be mapped.
369218887Sdim  if (DiagID >= diag::DIAG_UPPER_LIMIT)
370218887Sdim    return CustomDiagInfo->getLevel(DiagID);
371218887Sdim
372218887Sdim  unsigned DiagClass = getBuiltinDiagClass(DiagID);
373218887Sdim  assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
374219077Sdim  return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag, mapping);
375218887Sdim}
376218887Sdim
377218887Sdim/// \brief Based on the way the client configured the Diagnostic
378218887Sdim/// object, classify the specified diagnostic ID into a Level, consumable by
379218887Sdim/// the DiagnosticClient.
380218887Sdim///
381218887Sdim/// \param Loc The source location we are interested in finding out the
382218887Sdim/// diagnostic state. Can be null in order to query the latest state.
383218887SdimDiagnosticIDs::Level
384218887SdimDiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
385218887Sdim                                  SourceLocation Loc,
386219077Sdim                                  const Diagnostic &Diag,
387219077Sdim                                  diag::Mapping *mapping) const {
388218887Sdim  // Specific non-error diagnostics may be mapped to various levels from ignored
389218887Sdim  // to error.  Errors can only be mapped to fatal.
390218887Sdim  DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
391218887Sdim
392218887Sdim  Diagnostic::DiagStatePointsTy::iterator
393218887Sdim    Pos = Diag.GetDiagStatePointForLoc(Loc);
394218887Sdim  Diagnostic::DiagState *State = Pos->State;
395218887Sdim
396218887Sdim  // Get the mapping information, if unset, compute it lazily.
397218887Sdim  unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID,
398218887Sdim                                                       State);
399218887Sdim  if (MappingInfo == 0) {
400218887Sdim    MappingInfo = GetDefaultDiagMapping(DiagID);
401218887Sdim    Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
402218887Sdim  }
403219077Sdim
404219077Sdim  if (mapping)
405219077Sdim    *mapping = (diag::Mapping) (MappingInfo & 7);
406218887Sdim
407221345Sdim  bool ShouldEmitInSystemHeader = false;
408221345Sdim
409218887Sdim  switch (MappingInfo & 7) {
410218887Sdim  default: assert(0 && "Unknown mapping!");
411218887Sdim  case diag::MAP_IGNORE:
412218887Sdim    // Ignore this, unless this is an extension diagnostic and we're mapping
413218887Sdim    // them onto warnings or errors.
414218887Sdim    if (!isBuiltinExtensionDiag(DiagID) ||  // Not an extension
415218887Sdim        Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored
416218887Sdim        (MappingInfo & 8) != 0)             // User explicitly mapped it.
417218887Sdim      return DiagnosticIDs::Ignored;
418218887Sdim    Result = DiagnosticIDs::Warning;
419218887Sdim    if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error;
420218887Sdim    if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
421218887Sdim      Result = DiagnosticIDs::Fatal;
422218887Sdim    break;
423218887Sdim  case diag::MAP_ERROR:
424218887Sdim    Result = DiagnosticIDs::Error;
425218887Sdim    if (Diag.ErrorsAsFatal)
426218887Sdim      Result = DiagnosticIDs::Fatal;
427218887Sdim    break;
428218887Sdim  case diag::MAP_FATAL:
429218887Sdim    Result = DiagnosticIDs::Fatal;
430218887Sdim    break;
431221345Sdim  case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER:
432221345Sdim    ShouldEmitInSystemHeader = true;
433221345Sdim    // continue as MAP_WARNING.
434218887Sdim  case diag::MAP_WARNING:
435218887Sdim    // If warnings are globally mapped to ignore or error, do it.
436218887Sdim    if (Diag.IgnoreAllWarnings)
437218887Sdim      return DiagnosticIDs::Ignored;
438218887Sdim
439218887Sdim    Result = DiagnosticIDs::Warning;
440218887Sdim
441218887Sdim    // If this is an extension diagnostic and we're in -pedantic-error mode, and
442218887Sdim    // if the user didn't explicitly map it, upgrade to an error.
443218887Sdim    if (Diag.ExtBehavior == Diagnostic::Ext_Error &&
444218887Sdim        (MappingInfo & 8) == 0 &&
445218887Sdim        isBuiltinExtensionDiag(DiagID))
446218887Sdim      Result = DiagnosticIDs::Error;
447218887Sdim
448218887Sdim    if (Diag.WarningsAsErrors)
449218887Sdim      Result = DiagnosticIDs::Error;
450218887Sdim    if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
451218887Sdim      Result = DiagnosticIDs::Fatal;
452218887Sdim    break;
453218887Sdim
454218887Sdim  case diag::MAP_WARNING_NO_WERROR:
455218887Sdim    // Diagnostics specified with -Wno-error=foo should be set to warnings, but
456218887Sdim    // not be adjusted by -Werror or -pedantic-errors.
457218887Sdim    Result = DiagnosticIDs::Warning;
458218887Sdim
459218887Sdim    // If warnings are globally mapped to ignore or error, do it.
460218887Sdim    if (Diag.IgnoreAllWarnings)
461218887Sdim      return DiagnosticIDs::Ignored;
462218887Sdim
463218887Sdim    break;
464218887Sdim
465218887Sdim  case diag::MAP_ERROR_NO_WFATAL:
466218887Sdim    // Diagnostics specified as -Wno-fatal-error=foo should be errors, but
467218887Sdim    // unaffected by -Wfatal-errors.
468218887Sdim    Result = DiagnosticIDs::Error;
469218887Sdim    break;
470218887Sdim  }
471218887Sdim
472218887Sdim  // Okay, we're about to return this as a "diagnostic to emit" one last check:
473218887Sdim  // if this is any sort of extension warning, and if we're in an __extension__
474218887Sdim  // block, silence it.
475218887Sdim  if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
476218887Sdim    return DiagnosticIDs::Ignored;
477218887Sdim
478221345Sdim  // If we are in a system header, we ignore it.
479221345Sdim  // We also want to ignore extensions and warnings in -Werror and
480221345Sdim  // -pedantic-errors modes, which *map* warnings/extensions to errors.
481221345Sdim  if (Result >= DiagnosticIDs::Warning &&
482221345Sdim      DiagClass != CLASS_ERROR &&
483221345Sdim      // Custom diagnostics always are emitted in system headers.
484221345Sdim      DiagID < diag::DIAG_UPPER_LIMIT &&
485221345Sdim      !ShouldEmitInSystemHeader &&
486221345Sdim      Diag.SuppressSystemWarnings &&
487221345Sdim      Loc.isValid() &&
488221345Sdim      Diag.getSourceManager().isInSystemHeader(
489221345Sdim          Diag.getSourceManager().getInstantiationLoc(Loc)))
490221345Sdim    return DiagnosticIDs::Ignored;
491221345Sdim
492218887Sdim  return Result;
493218887Sdim}
494218887Sdim
495218887Sdimstruct WarningOption {
496218887Sdim  const char  *Name;
497218887Sdim  const short *Members;
498218887Sdim  const short *SubGroups;
499218887Sdim};
500218887Sdim
501218887Sdim#define GET_DIAG_ARRAYS
502218887Sdim#include "clang/Basic/DiagnosticGroups.inc"
503218887Sdim#undef GET_DIAG_ARRAYS
504218887Sdim
505218887Sdim// Second the table of options, sorted by name for fast binary lookup.
506218887Sdimstatic const WarningOption OptionTable[] = {
507218887Sdim#define GET_DIAG_TABLE
508218887Sdim#include "clang/Basic/DiagnosticGroups.inc"
509218887Sdim#undef GET_DIAG_TABLE
510218887Sdim};
511218887Sdimstatic const size_t OptionTableSize =
512218887Sdimsizeof(OptionTable) / sizeof(OptionTable[0]);
513218887Sdim
514218887Sdimstatic bool WarningOptionCompare(const WarningOption &LHS,
515218887Sdim                                 const WarningOption &RHS) {
516218887Sdim  return strcmp(LHS.Name, RHS.Name) < 0;
517218887Sdim}
518218887Sdim
519218887Sdimstatic void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
520218887Sdim                            SourceLocation Loc, Diagnostic &Diag) {
521218887Sdim  // Option exists, poke all the members of its diagnostic set.
522218887Sdim  if (const short *Member = Group->Members) {
523218887Sdim    for (; *Member != -1; ++Member)
524218887Sdim      Diag.setDiagnosticMapping(*Member, Mapping, Loc);
525218887Sdim  }
526218887Sdim
527218887Sdim  // Enable/disable all subgroups along with this one.
528218887Sdim  if (const short *SubGroups = Group->SubGroups) {
529218887Sdim    for (; *SubGroups != (short)-1; ++SubGroups)
530218887Sdim      MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag);
531218887Sdim  }
532218887Sdim}
533218887Sdim
534218887Sdim/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
535218887Sdim/// "unknown-pragmas" to have the specified mapping.  This returns true and
536218887Sdim/// ignores the request if "Group" was unknown, false otherwise.
537218887Sdimbool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
538218887Sdim                                           diag::Mapping Map,
539218887Sdim                                           SourceLocation Loc,
540218887Sdim                                           Diagnostic &Diag) const {
541218887Sdim  assert((Loc.isValid() ||
542218887Sdim          Diag.DiagStatePoints.empty() ||
543218887Sdim          Diag.DiagStatePoints.back().Loc.isInvalid()) &&
544218887Sdim         "Loc should be invalid only when the mapping comes from command-line");
545218887Sdim  assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() ||
546218887Sdim          Diag.DiagStatePoints.back().Loc.isInvalid() ||
547218887Sdim          !Diag.SourceMgr->isBeforeInTranslationUnit(Loc,
548218887Sdim                                            Diag.DiagStatePoints.back().Loc)) &&
549218887Sdim         "Source location of new mapping is before the previous one!");
550218887Sdim
551218887Sdim  WarningOption Key = { Group, 0, 0 };
552218887Sdim  const WarningOption *Found =
553218887Sdim  std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
554218887Sdim                   WarningOptionCompare);
555218887Sdim  if (Found == OptionTable + OptionTableSize ||
556218887Sdim      strcmp(Found->Name, Group) != 0)
557218887Sdim    return true;  // Option not found.
558218887Sdim
559218887Sdim  MapGroupMembers(Found, Map, Loc, Diag);
560218887Sdim  return false;
561218887Sdim}
562218887Sdim
563218887Sdim/// ProcessDiag - This is the method used to report a diagnostic that is
564218887Sdim/// finally fully formed.
565218887Sdimbool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
566218887Sdim  DiagnosticInfo Info(&Diag);
567218887Sdim
568218887Sdim  if (Diag.SuppressAllDiagnostics)
569218887Sdim    return false;
570218887Sdim
571218887Sdim  assert(Diag.getClient() && "DiagnosticClient not set!");
572218887Sdim
573218887Sdim  // Figure out the diagnostic level of this message.
574218887Sdim  DiagnosticIDs::Level DiagLevel;
575218887Sdim  unsigned DiagID = Info.getID();
576218887Sdim
577218887Sdim  if (DiagID >= diag::DIAG_UPPER_LIMIT) {
578218887Sdim    // Handle custom diagnostics, which cannot be mapped.
579218887Sdim    DiagLevel = CustomDiagInfo->getLevel(DiagID);
580218887Sdim  } else {
581218887Sdim    // Get the class of the diagnostic.  If this is a NOTE, map it onto whatever
582218887Sdim    // the diagnostic level was for the previous diagnostic so that it is
583218887Sdim    // filtered the same as the previous diagnostic.
584218887Sdim    unsigned DiagClass = getBuiltinDiagClass(DiagID);
585218887Sdim    if (DiagClass == CLASS_NOTE) {
586218887Sdim      DiagLevel = DiagnosticIDs::Note;
587218887Sdim    } else {
588218887Sdim      DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
589218887Sdim                                     Diag);
590218887Sdim    }
591218887Sdim  }
592218887Sdim
593218887Sdim  if (DiagLevel != DiagnosticIDs::Note) {
594218887Sdim    // Record that a fatal error occurred only when we see a second
595218887Sdim    // non-note diagnostic. This allows notes to be attached to the
596218887Sdim    // fatal error, but suppresses any diagnostics that follow those
597218887Sdim    // notes.
598218887Sdim    if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
599218887Sdim      Diag.FatalErrorOccurred = true;
600218887Sdim
601218887Sdim    Diag.LastDiagLevel = DiagLevel;
602218887Sdim  }
603218887Sdim
604218887Sdim  // If a fatal error has already been emitted, silence all subsequent
605218887Sdim  // diagnostics.
606218887Sdim  if (Diag.FatalErrorOccurred) {
607218887Sdim    if (DiagLevel >= DiagnosticIDs::Error &&
608218887Sdim        Diag.Client->IncludeInDiagnosticCounts()) {
609218887Sdim      ++Diag.NumErrors;
610218887Sdim      ++Diag.NumErrorsSuppressed;
611218887Sdim    }
612218887Sdim
613218887Sdim    return false;
614218887Sdim  }
615218887Sdim
616218887Sdim  // If the client doesn't care about this message, don't issue it.  If this is
617218887Sdim  // a note and the last real diagnostic was ignored, ignore it too.
618218887Sdim  if (DiagLevel == DiagnosticIDs::Ignored ||
619218887Sdim      (DiagLevel == DiagnosticIDs::Note &&
620218887Sdim       Diag.LastDiagLevel == DiagnosticIDs::Ignored))
621218887Sdim    return false;
622218887Sdim
623218887Sdim  if (DiagLevel >= DiagnosticIDs::Error) {
624218887Sdim    if (Diag.Client->IncludeInDiagnosticCounts()) {
625218887Sdim      Diag.ErrorOccurred = true;
626218887Sdim      ++Diag.NumErrors;
627218887Sdim    }
628218887Sdim
629218887Sdim    // If we've emitted a lot of errors, emit a fatal error after it to stop a
630218887Sdim    // flood of bogus errors.
631218887Sdim    if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit &&
632218887Sdim        DiagLevel == DiagnosticIDs::Error)
633218887Sdim      Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
634218887Sdim  }
635218887Sdim
636218887Sdim  // If we have any Fix-Its, make sure that all of the Fix-Its point into
637218887Sdim  // source locations that aren't macro instantiations. If any point into
638218887Sdim  // macro instantiations, remove all of the Fix-Its.
639218887Sdim  for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) {
640218887Sdim    const FixItHint &FixIt = Diag.FixItHints[I];
641218887Sdim    if (FixIt.RemoveRange.isInvalid() ||
642218887Sdim        FixIt.RemoveRange.getBegin().isMacroID() ||
643218887Sdim        FixIt.RemoveRange.getEnd().isMacroID()) {
644218887Sdim      Diag.NumFixItHints = 0;
645218887Sdim      break;
646218887Sdim    }
647218887Sdim  }
648218887Sdim
649218887Sdim  // Finally, report it.
650218887Sdim  Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info);
651218887Sdim  if (Diag.Client->IncludeInDiagnosticCounts()) {
652218887Sdim    if (DiagLevel == DiagnosticIDs::Warning)
653218887Sdim      ++Diag.NumWarnings;
654218887Sdim  }
655218887Sdim
656218887Sdim  Diag.CurDiagID = ~0U;
657218887Sdim
658218887Sdim  return true;
659218887Sdim}
660