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