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/Basic/DiagnosticIDs.h"
15234353Sdim#include "clang/Basic/AllDiagnostics.h"
16224145Sdim#include "clang/Basic/DiagnosticCategories.h"
17218887Sdim#include "clang/Basic/SourceManager.h"
18226633Sdim#include "llvm/ADT/SmallVector.h"
19263508Sdim#include "llvm/ADT/STLExtras.h"
20226633Sdim#include "llvm/Support/ErrorHandling.h"
21218887Sdim#include <map>
22218887Sdimusing namespace clang;
23218887Sdim
24218887Sdim//===----------------------------------------------------------------------===//
25218887Sdim// Builtin Diagnostic information
26218887Sdim//===----------------------------------------------------------------------===//
27218887Sdim
28218887Sdimnamespace {
29218887Sdim
30218887Sdim// Diagnostic classes.
31218887Sdimenum {
32218887Sdim  CLASS_NOTE       = 0x01,
33218887Sdim  CLASS_WARNING    = 0x02,
34218887Sdim  CLASS_EXTENSION  = 0x03,
35218887Sdim  CLASS_ERROR      = 0x04
36218887Sdim};
37218887Sdim
38218887Sdimstruct StaticDiagInfoRec {
39263508Sdim  uint16_t DiagID;
40218887Sdim  unsigned Mapping : 3;
41218887Sdim  unsigned Class : 3;
42263508Sdim  unsigned SFINAE : 2;
43226633Sdim  unsigned WarnNoWerror : 1;
44226633Sdim  unsigned WarnShowInSystemHeader : 1;
45218887Sdim  unsigned Category : 5;
46218887Sdim
47234353Sdim  uint16_t OptionGroupIndex;
48221345Sdim
49223017Sdim  uint16_t DescriptionLen;
50223017Sdim  const char *DescriptionStr;
51223017Sdim
52234353Sdim  unsigned getOptionGroupIndex() const {
53234353Sdim    return OptionGroupIndex;
54223017Sdim  }
55223017Sdim
56226633Sdim  StringRef getDescription() const {
57226633Sdim    return StringRef(DescriptionStr, DescriptionLen);
58223017Sdim  }
59223017Sdim
60218887Sdim  bool operator<(const StaticDiagInfoRec &RHS) const {
61218887Sdim    return DiagID < RHS.DiagID;
62218887Sdim  }
63218887Sdim};
64218887Sdim
65223017Sdim} // namespace anonymous
66223017Sdim
67218887Sdimstatic const StaticDiagInfoRec StaticDiagInfo[] = {
68223017Sdim#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,               \
69263508Sdim             SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY)            \
70263508Sdim  { diag::ENUM, DEFAULT_MAPPING, CLASS,                           \
71263508Sdim    DiagnosticIDs::SFINAE,                                        \
72234353Sdim    NOWERROR, SHOWINSYSHEADER, CATEGORY, GROUP,                   \
73234353Sdim    STR_SIZE(DESC, uint16_t), DESC },
74218887Sdim#include "clang/Basic/DiagnosticCommonKinds.inc"
75218887Sdim#include "clang/Basic/DiagnosticDriverKinds.inc"
76218887Sdim#include "clang/Basic/DiagnosticFrontendKinds.inc"
77234353Sdim#include "clang/Basic/DiagnosticSerializationKinds.inc"
78218887Sdim#include "clang/Basic/DiagnosticLexKinds.inc"
79218887Sdim#include "clang/Basic/DiagnosticParseKinds.inc"
80218887Sdim#include "clang/Basic/DiagnosticASTKinds.inc"
81239462Sdim#include "clang/Basic/DiagnosticCommentKinds.inc"
82218887Sdim#include "clang/Basic/DiagnosticSemaKinds.inc"
83218887Sdim#include "clang/Basic/DiagnosticAnalysisKinds.inc"
84221345Sdim#undef DIAG
85218887Sdim};
86218887Sdim
87263508Sdimstatic const unsigned StaticDiagInfoSize = llvm::array_lengthof(StaticDiagInfo);
88221345Sdim
89218887Sdim/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
90218887Sdim/// or null if the ID is invalid.
91218887Sdimstatic const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
92218887Sdim  // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
93218887Sdim#ifndef NDEBUG
94263508Sdim  static bool IsFirst = true; // So the check is only performed on first call.
95218887Sdim  if (IsFirst) {
96221345Sdim    for (unsigned i = 1; i != StaticDiagInfoSize; ++i) {
97218887Sdim      assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
98218887Sdim             "Diag ID conflict, the enums at the start of clang::diag (in "
99218887Sdim             "DiagnosticIDs.h) probably need to be increased");
100218887Sdim
101218887Sdim      assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] &&
102218887Sdim             "Improperly sorted diag info");
103218887Sdim    }
104218887Sdim    IsFirst = false;
105218887Sdim  }
106218887Sdim#endif
107218887Sdim
108249423Sdim  // Out of bounds diag. Can't be in the table.
109249423Sdim  using namespace diag;
110263508Sdim  if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
111249423Sdim    return 0;
112218887Sdim
113249423Sdim  // Compute the index of the requested diagnostic in the static table.
114249423Sdim  // 1. Add the number of diagnostics in each category preceeding the
115249423Sdim  //    diagnostic and of the category the diagnostic is in. This gives us
116249423Sdim  //    the offset of the category in the table.
117249423Sdim  // 2. Subtract the number of IDs in each category from our ID. This gives us
118249423Sdim  //    the offset of the diagnostic in the category.
119249423Sdim  // This is cheaper than a binary search on the table as it doesn't touch
120249423Sdim  // memory at all.
121249423Sdim  unsigned Offset = 0;
122263508Sdim  unsigned ID = DiagID - DIAG_START_COMMON - 1;
123249423Sdim#define CATEGORY(NAME, PREV) \
124249423Sdim  if (DiagID > DIAG_START_##NAME) { \
125249423Sdim    Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
126249423Sdim    ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
127249423Sdim  }
128249423SdimCATEGORY(DRIVER, COMMON)
129249423SdimCATEGORY(FRONTEND, DRIVER)
130249423SdimCATEGORY(SERIALIZATION, FRONTEND)
131249423SdimCATEGORY(LEX, SERIALIZATION)
132249423SdimCATEGORY(PARSE, LEX)
133249423SdimCATEGORY(AST, PARSE)
134249423SdimCATEGORY(COMMENT, AST)
135249423SdimCATEGORY(SEMA, COMMENT)
136249423SdimCATEGORY(ANALYSIS, SEMA)
137249423Sdim#undef CATEGORY
138249423Sdim
139249423Sdim  // Avoid out of bounds reads.
140249423Sdim  if (ID + Offset >= StaticDiagInfoSize)
141218887Sdim    return 0;
142218887Sdim
143249423Sdim  assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
144249423Sdim
145249423Sdim  const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
146249423Sdim  // If the diag id doesn't match we found a different diag, abort. This can
147249423Sdim  // happen when this function is called with an ID that points into a hole in
148249423Sdim  // the diagID space.
149249423Sdim  if (Found->DiagID != DiagID)
150249423Sdim    return 0;
151218887Sdim  return Found;
152218887Sdim}
153218887Sdim
154226633Sdimstatic DiagnosticMappingInfo GetDefaultDiagMappingInfo(unsigned DiagID) {
155226633Sdim  DiagnosticMappingInfo Info = DiagnosticMappingInfo::Make(
156226633Sdim    diag::MAP_FATAL, /*IsUser=*/false, /*IsPragma=*/false);
157226633Sdim
158226633Sdim  if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
159226633Sdim    Info.setMapping((diag::Mapping) StaticInfo->Mapping);
160226633Sdim
161226633Sdim    if (StaticInfo->WarnNoWerror) {
162226633Sdim      assert(Info.getMapping() == diag::MAP_WARNING &&
163226633Sdim             "Unexpected mapping with no-Werror bit!");
164226633Sdim      Info.setNoWarningAsError(true);
165226633Sdim    }
166226633Sdim
167226633Sdim    if (StaticInfo->WarnShowInSystemHeader) {
168226633Sdim      assert(Info.getMapping() == diag::MAP_WARNING &&
169226633Sdim             "Unexpected mapping with show-in-system-header bit!");
170226633Sdim      Info.setShowInSystemHeader(true);
171226633Sdim    }
172226633Sdim  }
173226633Sdim
174226633Sdim  return Info;
175218887Sdim}
176218887Sdim
177221345Sdim/// getCategoryNumberForDiag - Return the category number that a specified
178218887Sdim/// DiagID belongs to, or 0 if no category.
179218887Sdimunsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
180218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
181218887Sdim    return Info->Category;
182218887Sdim  return 0;
183218887Sdim}
184218887Sdim
185224145Sdimnamespace {
186224145Sdim  // The diagnostic category names.
187224145Sdim  struct StaticDiagCategoryRec {
188224145Sdim    const char *NameStr;
189224145Sdim    uint8_t NameLen;
190223017Sdim
191226633Sdim    StringRef getName() const {
192226633Sdim      return StringRef(NameStr, NameLen);
193224145Sdim    }
194224145Sdim  };
195224145Sdim}
196223017Sdim
197226633Sdim// Unfortunately, the split between DiagnosticIDs and Diagnostic is not
198226633Sdim// particularly clean, but for now we just implement this method here so we can
199226633Sdim// access GetDefaultDiagMapping.
200226633SdimDiagnosticMappingInfo &DiagnosticsEngine::DiagState::getOrAddMappingInfo(
201226633Sdim  diag::kind Diag)
202226633Sdim{
203226633Sdim  std::pair<iterator, bool> Result = DiagMap.insert(
204226633Sdim    std::make_pair(Diag, DiagnosticMappingInfo()));
205226633Sdim
206226633Sdim  // Initialize the entry if we added it.
207226633Sdim  if (Result.second)
208226633Sdim    Result.first->second = GetDefaultDiagMappingInfo(Diag);
209226633Sdim
210226633Sdim  return Result.first->second;
211226633Sdim}
212226633Sdim
213224145Sdimstatic const StaticDiagCategoryRec CategoryNameTable[] = {
214218887Sdim#define GET_CATEGORY_TABLE
215224145Sdim#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
216218887Sdim#include "clang/Basic/DiagnosticGroups.inc"
217218887Sdim#undef GET_CATEGORY_TABLE
218223017Sdim  { 0, 0 }
219223017Sdim};
220223017Sdim
221223017Sdim/// getNumberOfCategories - Return the number of categories
222223017Sdimunsigned DiagnosticIDs::getNumberOfCategories() {
223263508Sdim  return llvm::array_lengthof(CategoryNameTable) - 1;
224218887Sdim}
225218887Sdim
226223017Sdim/// getCategoryNameFromID - Given a category ID, return the name of the
227223017Sdim/// category, an empty string if CategoryID is zero, or null if CategoryID is
228223017Sdim/// invalid.
229226633SdimStringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
230223017Sdim  if (CategoryID >= getNumberOfCategories())
231226633Sdim   return StringRef();
232223017Sdim  return CategoryNameTable[CategoryID].getName();
233223017Sdim}
234218887Sdim
235218887Sdim
236223017Sdim
237263508SdimDiagnosticIDs::SFINAEResponse
238218887SdimDiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
239263508Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
240263508Sdim    return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
241218887Sdim  return SFINAE_Report;
242218887Sdim}
243218887Sdim
244221345Sdim/// getBuiltinDiagClass - Return the class field of the diagnostic.
245218887Sdim///
246218887Sdimstatic unsigned getBuiltinDiagClass(unsigned DiagID) {
247218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
248218887Sdim    return Info->Class;
249218887Sdim  return ~0U;
250218887Sdim}
251218887Sdim
252218887Sdim//===----------------------------------------------------------------------===//
253218887Sdim// Custom Diagnostic information
254218887Sdim//===----------------------------------------------------------------------===//
255218887Sdim
256218887Sdimnamespace clang {
257218887Sdim  namespace diag {
258218887Sdim    class CustomDiagInfo {
259218887Sdim      typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
260218887Sdim      std::vector<DiagDesc> DiagInfo;
261218887Sdim      std::map<DiagDesc, unsigned> DiagIDs;
262218887Sdim    public:
263218887Sdim
264218887Sdim      /// getDescription - Return the description of the specified custom
265218887Sdim      /// diagnostic.
266226633Sdim      StringRef getDescription(unsigned DiagID) const {
267218887Sdim        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
268249423Sdim               "Invalid diagnostic ID");
269223017Sdim        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
270218887Sdim      }
271218887Sdim
272218887Sdim      /// getLevel - Return the level of the specified custom diagnostic.
273218887Sdim      DiagnosticIDs::Level getLevel(unsigned DiagID) const {
274218887Sdim        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
275249423Sdim               "Invalid diagnostic ID");
276218887Sdim        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
277218887Sdim      }
278218887Sdim
279226633Sdim      unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
280218887Sdim                                 DiagnosticIDs &Diags) {
281218887Sdim        DiagDesc D(L, Message);
282218887Sdim        // Check to see if it already exists.
283218887Sdim        std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
284218887Sdim        if (I != DiagIDs.end() && I->first == D)
285218887Sdim          return I->second;
286218887Sdim
287218887Sdim        // If not, assign a new ID.
288218887Sdim        unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
289218887Sdim        DiagIDs.insert(std::make_pair(D, ID));
290218887Sdim        DiagInfo.push_back(D);
291218887Sdim        return ID;
292218887Sdim      }
293218887Sdim    };
294218887Sdim
295218887Sdim  } // end diag namespace
296218887Sdim} // end clang namespace
297218887Sdim
298218887Sdim
299218887Sdim//===----------------------------------------------------------------------===//
300218887Sdim// Common Diagnostic implementation
301218887Sdim//===----------------------------------------------------------------------===//
302218887Sdim
303218887SdimDiagnosticIDs::DiagnosticIDs() {
304218887Sdim  CustomDiagInfo = 0;
305218887Sdim}
306218887Sdim
307218887SdimDiagnosticIDs::~DiagnosticIDs() {
308218887Sdim  delete CustomDiagInfo;
309218887Sdim}
310218887Sdim
311218887Sdim/// getCustomDiagID - Return an ID for a diagnostic with the specified message
312249423Sdim/// and level.  If this is the first request for this diagnostic, it is
313218887Sdim/// registered and created, otherwise the existing ID is returned.
314226633Sdimunsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef Message) {
315218887Sdim  if (CustomDiagInfo == 0)
316218887Sdim    CustomDiagInfo = new diag::CustomDiagInfo();
317218887Sdim  return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
318218887Sdim}
319218887Sdim
320218887Sdim
321218887Sdim/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
322218887Sdim/// level of the specified diagnostic ID is a Warning or Extension.
323218887Sdim/// This only works on builtin diagnostics, not custom ones, and is not legal to
324218887Sdim/// call on NOTEs.
325218887Sdimbool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
326218887Sdim  return DiagID < diag::DIAG_UPPER_LIMIT &&
327218887Sdim         getBuiltinDiagClass(DiagID) != CLASS_ERROR;
328218887Sdim}
329218887Sdim
330218887Sdim/// \brief Determine whether the given built-in diagnostic ID is a
331218887Sdim/// Note.
332218887Sdimbool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
333218887Sdim  return DiagID < diag::DIAG_UPPER_LIMIT &&
334218887Sdim    getBuiltinDiagClass(DiagID) == CLASS_NOTE;
335218887Sdim}
336218887Sdim
337218887Sdim/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
338218887Sdim/// ID is for an extension of some sort.  This also returns EnabledByDefault,
339218887Sdim/// which is set to indicate whether the diagnostic is ignored by default (in
340218887Sdim/// which case -pedantic enables it) or treated as a warning/error by default.
341218887Sdim///
342218887Sdimbool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
343218887Sdim                                        bool &EnabledByDefault) {
344218887Sdim  if (DiagID >= diag::DIAG_UPPER_LIMIT ||
345218887Sdim      getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
346218887Sdim    return false;
347218887Sdim
348226633Sdim  EnabledByDefault =
349226633Sdim    GetDefaultDiagMappingInfo(DiagID).getMapping() != diag::MAP_IGNORE;
350218887Sdim  return true;
351218887Sdim}
352218887Sdim
353226633Sdimbool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
354226633Sdim  if (DiagID >= diag::DIAG_UPPER_LIMIT)
355226633Sdim    return false;
356226633Sdim
357226633Sdim  return GetDefaultDiagMappingInfo(DiagID).getMapping() == diag::MAP_ERROR;
358226633Sdim}
359226633Sdim
360218887Sdim/// getDescription - Given a diagnostic ID, return a description of the
361218887Sdim/// issue.
362226633SdimStringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
363218887Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
364223017Sdim    return Info->getDescription();
365218887Sdim  return CustomDiagInfo->getDescription(DiagID);
366218887Sdim}
367218887Sdim
368226633Sdim/// getDiagnosticLevel - Based on the way the client configured the
369226633Sdim/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
370226633Sdim/// by consumable the DiagnosticClient.
371218887SdimDiagnosticIDs::Level
372218887SdimDiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
373226633Sdim                                  const DiagnosticsEngine &Diag) const {
374218887Sdim  // Handle custom diagnostics, which cannot be mapped.
375218887Sdim  if (DiagID >= diag::DIAG_UPPER_LIMIT)
376218887Sdim    return CustomDiagInfo->getLevel(DiagID);
377218887Sdim
378218887Sdim  unsigned DiagClass = getBuiltinDiagClass(DiagID);
379239462Sdim  if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
380226633Sdim  return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
381218887Sdim}
382218887Sdim
383218887Sdim/// \brief Based on the way the client configured the Diagnostic
384218887Sdim/// object, classify the specified diagnostic ID into a Level, consumable by
385218887Sdim/// the DiagnosticClient.
386218887Sdim///
387218887Sdim/// \param Loc The source location we are interested in finding out the
388218887Sdim/// diagnostic state. Can be null in order to query the latest state.
389218887SdimDiagnosticIDs::Level
390218887SdimDiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
391218887Sdim                                  SourceLocation Loc,
392226633Sdim                                  const DiagnosticsEngine &Diag) const {
393218887Sdim  // Specific non-error diagnostics may be mapped to various levels from ignored
394218887Sdim  // to error.  Errors can only be mapped to fatal.
395218887Sdim  DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
396218887Sdim
397226633Sdim  DiagnosticsEngine::DiagStatePointsTy::iterator
398218887Sdim    Pos = Diag.GetDiagStatePointForLoc(Loc);
399226633Sdim  DiagnosticsEngine::DiagState *State = Pos->State;
400218887Sdim
401226633Sdim  // Get the mapping information, or compute it lazily.
402226633Sdim  DiagnosticMappingInfo &MappingInfo = State->getOrAddMappingInfo(
403226633Sdim    (diag::kind)DiagID);
404218887Sdim
405226633Sdim  switch (MappingInfo.getMapping()) {
406218887Sdim  case diag::MAP_IGNORE:
407226633Sdim    Result = DiagnosticIDs::Ignored;
408226633Sdim    break;
409226633Sdim  case diag::MAP_WARNING:
410218887Sdim    Result = DiagnosticIDs::Warning;
411218887Sdim    break;
412218887Sdim  case diag::MAP_ERROR:
413218887Sdim    Result = DiagnosticIDs::Error;
414218887Sdim    break;
415218887Sdim  case diag::MAP_FATAL:
416218887Sdim    Result = DiagnosticIDs::Fatal;
417218887Sdim    break;
418226633Sdim  }
419218887Sdim
420226633Sdim  // Upgrade ignored diagnostics if -Weverything is enabled.
421226633Sdim  if (Diag.EnableAllWarnings && Result == DiagnosticIDs::Ignored &&
422226633Sdim      !MappingInfo.isUser())
423218887Sdim    Result = DiagnosticIDs::Warning;
424218887Sdim
425226633Sdim  // Ignore -pedantic diagnostics inside __extension__ blocks.
426226633Sdim  // (The diagnostics controlled by -pedantic are the extension diagnostics
427226633Sdim  // that are not enabled by default.)
428234353Sdim  bool EnabledByDefault = false;
429226633Sdim  bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
430226633Sdim  if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
431226633Sdim    return DiagnosticIDs::Ignored;
432218887Sdim
433226633Sdim  // For extension diagnostics that haven't been explicitly mapped, check if we
434226633Sdim  // should upgrade the diagnostic.
435226633Sdim  if (IsExtensionDiag && !MappingInfo.isUser()) {
436226633Sdim    switch (Diag.ExtBehavior) {
437226633Sdim    case DiagnosticsEngine::Ext_Ignore:
438226633Sdim      break;
439226633Sdim    case DiagnosticsEngine::Ext_Warn:
440226633Sdim      // Upgrade ignored diagnostics to warnings.
441226633Sdim      if (Result == DiagnosticIDs::Ignored)
442226633Sdim        Result = DiagnosticIDs::Warning;
443226633Sdim      break;
444226633Sdim    case DiagnosticsEngine::Ext_Error:
445226633Sdim      // Upgrade ignored or warning diagnostics to errors.
446226633Sdim      if (Result == DiagnosticIDs::Ignored || Result == DiagnosticIDs::Warning)
447226633Sdim        Result = DiagnosticIDs::Error;
448226633Sdim      break;
449226633Sdim    }
450226633Sdim  }
451218887Sdim
452226633Sdim  // At this point, ignored errors can no longer be upgraded.
453226633Sdim  if (Result == DiagnosticIDs::Ignored)
454226633Sdim    return Result;
455218887Sdim
456226633Sdim  // Honor -w, which is lower in priority than pedantic-errors, but higher than
457226633Sdim  // -Werror.
458226633Sdim  if (Result == DiagnosticIDs::Warning && Diag.IgnoreAllWarnings)
459226633Sdim    return DiagnosticIDs::Ignored;
460218887Sdim
461226633Sdim  // If -Werror is enabled, map warnings to errors unless explicitly disabled.
462226633Sdim  if (Result == DiagnosticIDs::Warning) {
463226633Sdim    if (Diag.WarningsAsErrors && !MappingInfo.hasNoWarningAsError())
464226633Sdim      Result = DiagnosticIDs::Error;
465226633Sdim  }
466218887Sdim
467226633Sdim  // If -Wfatal-errors is enabled, map errors to fatal unless explicity
468226633Sdim  // disabled.
469226633Sdim  if (Result == DiagnosticIDs::Error) {
470226633Sdim    if (Diag.ErrorsAsFatal && !MappingInfo.hasNoErrorAsFatal())
471226633Sdim      Result = DiagnosticIDs::Fatal;
472218887Sdim  }
473218887Sdim
474226633Sdim  // If we are in a system header, we ignore it. We look at the diagnostic class
475226633Sdim  // because we also want to ignore extensions and warnings in -Werror and
476221345Sdim  // -pedantic-errors modes, which *map* warnings/extensions to errors.
477221345Sdim  if (Result >= DiagnosticIDs::Warning &&
478221345Sdim      DiagClass != CLASS_ERROR &&
479221345Sdim      // Custom diagnostics always are emitted in system headers.
480221345Sdim      DiagID < diag::DIAG_UPPER_LIMIT &&
481226633Sdim      !MappingInfo.hasShowInSystemHeader() &&
482221345Sdim      Diag.SuppressSystemWarnings &&
483221345Sdim      Loc.isValid() &&
484221345Sdim      Diag.getSourceManager().isInSystemHeader(
485226633Sdim          Diag.getSourceManager().getExpansionLoc(Loc)))
486221345Sdim    return DiagnosticIDs::Ignored;
487221345Sdim
488218887Sdim  return Result;
489218887Sdim}
490218887Sdim
491218887Sdim#define GET_DIAG_ARRAYS
492218887Sdim#include "clang/Basic/DiagnosticGroups.inc"
493218887Sdim#undef GET_DIAG_ARRAYS
494218887Sdim
495263508Sdimnamespace {
496263508Sdim  struct WarningOption {
497263508Sdim    uint16_t NameOffset;
498263508Sdim    uint16_t Members;
499263508Sdim    uint16_t SubGroups;
500263508Sdim
501263508Sdim    // String is stored with a pascal-style length byte.
502263508Sdim    StringRef getName() const {
503263508Sdim      return StringRef(DiagGroupNames + NameOffset + 1,
504263508Sdim                       DiagGroupNames[NameOffset]);
505263508Sdim    }
506263508Sdim  };
507263508Sdim}
508263508Sdim
509218887Sdim// Second the table of options, sorted by name for fast binary lookup.
510218887Sdimstatic const WarningOption OptionTable[] = {
511218887Sdim#define GET_DIAG_TABLE
512218887Sdim#include "clang/Basic/DiagnosticGroups.inc"
513218887Sdim#undef GET_DIAG_TABLE
514218887Sdim};
515263508Sdimstatic const size_t OptionTableSize = llvm::array_lengthof(OptionTable);
516218887Sdim
517263508Sdimstatic bool WarningOptionCompare(const WarningOption &LHS, StringRef RHS) {
518263508Sdim  return LHS.getName() < RHS;
519218887Sdim}
520218887Sdim
521234353Sdim/// getWarningOptionForDiag - Return the lowest-level warning option that
522234353Sdim/// enables the specified diagnostic.  If there is no -Wfoo flag that controls
523234353Sdim/// the diagnostic, this returns null.
524234353SdimStringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
525234353Sdim  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
526234353Sdim    return OptionTable[Info->getOptionGroupIndex()].getName();
527234353Sdim  return StringRef();
528234353Sdim}
529234353Sdim
530263508Sdimstatic void getDiagnosticsInGroup(const WarningOption *Group,
531263508Sdim                                  SmallVectorImpl<diag::kind> &Diags) {
532226633Sdim  // Add the members of the option diagnostic set.
533263508Sdim  const int16_t *Member = DiagArrays + Group->Members;
534263508Sdim  for (; *Member != -1; ++Member)
535263508Sdim    Diags.push_back(*Member);
536218887Sdim
537226633Sdim  // Add the members of the subgroups.
538263508Sdim  const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
539263508Sdim  for (; *SubGroups != (int16_t)-1; ++SubGroups)
540263508Sdim    getDiagnosticsInGroup(&OptionTable[(short)*SubGroups], Diags);
541218887Sdim}
542218887Sdim
543226633Sdimbool DiagnosticIDs::getDiagnosticsInGroup(
544249423Sdim    StringRef Group,
545249423Sdim    SmallVectorImpl<diag::kind> &Diags) const {
546218887Sdim  const WarningOption *Found =
547263508Sdim  std::lower_bound(OptionTable, OptionTable + OptionTableSize, Group,
548218887Sdim                   WarningOptionCompare);
549218887Sdim  if (Found == OptionTable + OptionTableSize ||
550223017Sdim      Found->getName() != Group)
551226633Sdim    return true; // Option not found.
552218887Sdim
553263508Sdim  ::getDiagnosticsInGroup(Found, Diags);
554218887Sdim  return false;
555218887Sdim}
556218887Sdim
557234353Sdimvoid DiagnosticIDs::getAllDiagnostics(
558249423Sdim                               SmallVectorImpl<diag::kind> &Diags) const {
559234353Sdim  for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
560234353Sdim    Diags.push_back(StaticDiagInfo[i].DiagID);
561234353Sdim}
562234353Sdim
563234353SdimStringRef DiagnosticIDs::getNearestWarningOption(StringRef Group) {
564234353Sdim  StringRef Best;
565234353Sdim  unsigned BestDistance = Group.size() + 1; // Sanity threshold.
566234353Sdim  for (const WarningOption *i = OptionTable, *e = OptionTable + OptionTableSize;
567234353Sdim       i != e; ++i) {
568234353Sdim    // Don't suggest ignored warning flags.
569234353Sdim    if (!i->Members && !i->SubGroups)
570234353Sdim      continue;
571234353Sdim
572234353Sdim    unsigned Distance = i->getName().edit_distance(Group, true, BestDistance);
573234353Sdim    if (Distance == BestDistance) {
574234353Sdim      // Two matches with the same distance, don't prefer one over the other.
575234353Sdim      Best = "";
576234353Sdim    } else if (Distance < BestDistance) {
577234353Sdim      // This is a better match.
578234353Sdim      Best = i->getName();
579234353Sdim      BestDistance = Distance;
580234353Sdim    }
581234353Sdim  }
582234353Sdim
583234353Sdim  return Best;
584234353Sdim}
585234353Sdim
586218887Sdim/// ProcessDiag - This is the method used to report a diagnostic that is
587218887Sdim/// finally fully formed.
588226633Sdimbool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
589226633Sdim  Diagnostic Info(&Diag);
590218887Sdim
591218887Sdim  if (Diag.SuppressAllDiagnostics)
592218887Sdim    return false;
593218887Sdim
594218887Sdim  assert(Diag.getClient() && "DiagnosticClient not set!");
595218887Sdim
596218887Sdim  // Figure out the diagnostic level of this message.
597218887Sdim  unsigned DiagID = Info.getID();
598239462Sdim  DiagnosticIDs::Level DiagLevel
599239462Sdim    = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
600218887Sdim
601218887Sdim  if (DiagLevel != DiagnosticIDs::Note) {
602218887Sdim    // Record that a fatal error occurred only when we see a second
603218887Sdim    // non-note diagnostic. This allows notes to be attached to the
604218887Sdim    // fatal error, but suppresses any diagnostics that follow those
605218887Sdim    // notes.
606218887Sdim    if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
607218887Sdim      Diag.FatalErrorOccurred = true;
608218887Sdim
609218887Sdim    Diag.LastDiagLevel = DiagLevel;
610218887Sdim  }
611218887Sdim
612226633Sdim  // Update counts for DiagnosticErrorTrap even if a fatal error occurred.
613226633Sdim  if (DiagLevel >= DiagnosticIDs::Error) {
614226633Sdim    ++Diag.TrapNumErrorsOccurred;
615226633Sdim    if (isUnrecoverable(DiagID))
616226633Sdim      ++Diag.TrapNumUnrecoverableErrorsOccurred;
617226633Sdim  }
618226633Sdim
619218887Sdim  // If a fatal error has already been emitted, silence all subsequent
620218887Sdim  // diagnostics.
621218887Sdim  if (Diag.FatalErrorOccurred) {
622218887Sdim    if (DiagLevel >= DiagnosticIDs::Error &&
623218887Sdim        Diag.Client->IncludeInDiagnosticCounts()) {
624218887Sdim      ++Diag.NumErrors;
625218887Sdim      ++Diag.NumErrorsSuppressed;
626218887Sdim    }
627218887Sdim
628218887Sdim    return false;
629218887Sdim  }
630218887Sdim
631218887Sdim  // If the client doesn't care about this message, don't issue it.  If this is
632218887Sdim  // a note and the last real diagnostic was ignored, ignore it too.
633218887Sdim  if (DiagLevel == DiagnosticIDs::Ignored ||
634218887Sdim      (DiagLevel == DiagnosticIDs::Note &&
635218887Sdim       Diag.LastDiagLevel == DiagnosticIDs::Ignored))
636218887Sdim    return false;
637218887Sdim
638218887Sdim  if (DiagLevel >= DiagnosticIDs::Error) {
639226633Sdim    if (isUnrecoverable(DiagID))
640224145Sdim      Diag.UnrecoverableErrorOccurred = true;
641243830Sdim
642249423Sdim    // Warnings which have been upgraded to errors do not prevent compilation.
643249423Sdim    if (isDefaultMappingAsError(DiagID))
644249423Sdim      Diag.UncompilableErrorOccurred = true;
645249423Sdim
646243830Sdim    Diag.ErrorOccurred = true;
647218887Sdim    if (Diag.Client->IncludeInDiagnosticCounts()) {
648218887Sdim      ++Diag.NumErrors;
649218887Sdim    }
650218887Sdim
651226633Sdim    // If we've emitted a lot of errors, emit a fatal error instead of it to
652226633Sdim    // stop a flood of bogus errors.
653226633Sdim    if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
654226633Sdim        DiagLevel == DiagnosticIDs::Error) {
655218887Sdim      Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
656226633Sdim      return false;
657226633Sdim    }
658218887Sdim  }
659218887Sdim
660218887Sdim  // Finally, report it.
661239462Sdim  EmitDiag(Diag, DiagLevel);
662239462Sdim  return true;
663239462Sdim}
664239462Sdim
665239462Sdimvoid DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
666239462Sdim  Diagnostic Info(&Diag);
667239462Sdim  assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
668239462Sdim
669226633Sdim  Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
670218887Sdim  if (Diag.Client->IncludeInDiagnosticCounts()) {
671218887Sdim    if (DiagLevel == DiagnosticIDs::Warning)
672218887Sdim      ++Diag.NumWarnings;
673218887Sdim  }
674218887Sdim
675218887Sdim  Diag.CurDiagID = ~0U;
676218887Sdim}
677224145Sdim
678224145Sdimbool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
679224145Sdim  if (DiagID >= diag::DIAG_UPPER_LIMIT) {
680224145Sdim    // Custom diagnostics.
681224145Sdim    return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
682224145Sdim  }
683224145Sdim
684224145Sdim  // Only errors may be unrecoverable.
685224145Sdim  if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
686224145Sdim    return false;
687224145Sdim
688224145Sdim  if (DiagID == diag::err_unavailable ||
689224145Sdim      DiagID == diag::err_unavailable_message)
690224145Sdim    return false;
691224145Sdim
692224145Sdim  // Currently we consider all ARC errors as recoverable.
693234353Sdim  if (isARCDiagnostic(DiagID))
694224145Sdim    return false;
695224145Sdim
696224145Sdim  return true;
697224145Sdim}
698234353Sdim
699234353Sdimbool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
700234353Sdim  unsigned cat = getCategoryNumberForDiag(DiagID);
701234353Sdim  return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
702234353Sdim}
703