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