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