DiagnosticIDs.cpp revision f84109ee6aeffb09366bd70c8593ce1b7818b1ad
1//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the Diagnostic IDs-related interfaces. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/AST/ASTDiagnostic.h" 15#include "clang/Analysis/AnalysisDiagnostic.h" 16#include "clang/Basic/DiagnosticIDs.h" 17#include "clang/Basic/SourceManager.h" 18#include "clang/Driver/DriverDiagnostic.h" 19#include "clang/Frontend/FrontendDiagnostic.h" 20#include "clang/Lex/LexDiagnostic.h" 21#include "clang/Parse/ParseDiagnostic.h" 22#include "clang/Sema/SemaDiagnostic.h" 23 24#include <map> 25using namespace clang; 26 27//===----------------------------------------------------------------------===// 28// Builtin Diagnostic information 29//===----------------------------------------------------------------------===// 30 31namespace { 32 33// Diagnostic classes. 34enum { 35 CLASS_NOTE = 0x01, 36 CLASS_WARNING = 0x02, 37 CLASS_EXTENSION = 0x03, 38 CLASS_ERROR = 0x04 39}; 40 41struct StaticDiagInfoRec { 42 unsigned short DiagID; 43 unsigned Mapping : 3; 44 unsigned Class : 3; 45 bool SFINAE : 1; 46 unsigned Category : 5; 47 48 const char *Description; 49 const char *OptionGroup; 50 51 bool operator<(const StaticDiagInfoRec &RHS) const { 52 return DiagID < RHS.DiagID; 53 } 54}; 55 56} 57 58static const StaticDiagInfoRec StaticDiagInfo[] = { 59#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE, CATEGORY) \ 60 { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, CATEGORY, DESC, GROUP }, 61#include "clang/Basic/DiagnosticCommonKinds.inc" 62#include "clang/Basic/DiagnosticDriverKinds.inc" 63#include "clang/Basic/DiagnosticFrontendKinds.inc" 64#include "clang/Basic/DiagnosticLexKinds.inc" 65#include "clang/Basic/DiagnosticParseKinds.inc" 66#include "clang/Basic/DiagnosticASTKinds.inc" 67#include "clang/Basic/DiagnosticSemaKinds.inc" 68#include "clang/Basic/DiagnosticAnalysisKinds.inc" 69 { 0, 0, 0, 0, 0, 0, 0} 70}; 71#undef DIAG 72 73/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, 74/// or null if the ID is invalid. 75static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { 76 unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1; 77 78 // If assertions are enabled, verify that the StaticDiagInfo array is sorted. 79#ifndef NDEBUG 80 static bool IsFirst = true; 81 if (IsFirst) { 82 for (unsigned i = 1; i != NumDiagEntries; ++i) { 83 assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID && 84 "Diag ID conflict, the enums at the start of clang::diag (in " 85 "DiagnosticIDs.h) probably need to be increased"); 86 87 assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] && 88 "Improperly sorted diag info"); 89 } 90 IsFirst = false; 91 } 92#endif 93 94 // Search the diagnostic table with a binary search. 95 StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0 }; 96 97 const StaticDiagInfoRec *Found = 98 std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); 99 if (Found == StaticDiagInfo + NumDiagEntries || 100 Found->DiagID != DiagID) 101 return 0; 102 103 return Found; 104} 105 106static unsigned GetDefaultDiagMapping(unsigned DiagID) { 107 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) 108 return Info->Mapping; 109 return diag::MAP_FATAL; 110} 111 112/// getWarningOptionForDiag - Return the lowest-level warning option that 113/// enables the specified diagnostic. If there is no -Wfoo flag that controls 114/// the diagnostic, this returns null. 115const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { 116 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) 117 return Info->OptionGroup; 118 return 0; 119} 120 121/// getWarningOptionForDiag - Return the category number that a specified 122/// DiagID belongs to, or 0 if no category. 123unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) { 124 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) 125 return Info->Category; 126 return 0; 127} 128 129/// getCategoryNameFromID - Given a category ID, return the name of the 130/// category, an empty string if CategoryID is zero, or null if CategoryID is 131/// invalid. 132const char *DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { 133 // Second the table of options, sorted by name for fast binary lookup. 134 static const char *CategoryNameTable[] = { 135#define GET_CATEGORY_TABLE 136#define CATEGORY(X) X, 137#include "clang/Basic/DiagnosticGroups.inc" 138#undef GET_CATEGORY_TABLE 139 "<<END>>" 140 }; 141 static const size_t CategoryNameTableSize = 142 sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1; 143 144 if (CategoryID >= CategoryNameTableSize) return 0; 145 return CategoryNameTable[CategoryID]; 146} 147 148 149 150DiagnosticIDs::SFINAEResponse 151DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { 152 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) { 153 if (!Info->SFINAE) 154 return SFINAE_Report; 155 156 if (Info->Class == CLASS_ERROR) 157 return SFINAE_SubstitutionFailure; 158 159 // Suppress notes, warnings, and extensions; 160 return SFINAE_Suppress; 161 } 162 163 return SFINAE_Report; 164} 165 166/// getDiagClass - Return the class field of the diagnostic. 167/// 168static unsigned getBuiltinDiagClass(unsigned DiagID) { 169 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) 170 return Info->Class; 171 return ~0U; 172} 173 174//===----------------------------------------------------------------------===// 175// Custom Diagnostic information 176//===----------------------------------------------------------------------===// 177 178namespace clang { 179 namespace diag { 180 class CustomDiagInfo { 181 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc; 182 std::vector<DiagDesc> DiagInfo; 183 std::map<DiagDesc, unsigned> DiagIDs; 184 public: 185 186 /// getDescription - Return the description of the specified custom 187 /// diagnostic. 188 const char *getDescription(unsigned DiagID) const { 189 assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() && 190 "Invalid diagnosic ID"); 191 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str(); 192 } 193 194 /// getLevel - Return the level of the specified custom diagnostic. 195 DiagnosticIDs::Level getLevel(unsigned DiagID) const { 196 assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() && 197 "Invalid diagnosic ID"); 198 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; 199 } 200 201 unsigned getOrCreateDiagID(DiagnosticIDs::Level L, llvm::StringRef Message, 202 DiagnosticIDs &Diags) { 203 DiagDesc D(L, Message); 204 // Check to see if it already exists. 205 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D); 206 if (I != DiagIDs.end() && I->first == D) 207 return I->second; 208 209 // If not, assign a new ID. 210 unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT; 211 DiagIDs.insert(std::make_pair(D, ID)); 212 DiagInfo.push_back(D); 213 return ID; 214 } 215 }; 216 217 } // end diag namespace 218} // end clang namespace 219 220 221//===----------------------------------------------------------------------===// 222// Common Diagnostic implementation 223//===----------------------------------------------------------------------===// 224 225DiagnosticIDs::DiagnosticIDs() { 226 CustomDiagInfo = 0; 227} 228 229DiagnosticIDs::~DiagnosticIDs() { 230 delete CustomDiagInfo; 231} 232 233/// getCustomDiagID - Return an ID for a diagnostic with the specified message 234/// and level. If this is the first request for this diagnosic, it is 235/// registered and created, otherwise the existing ID is returned. 236unsigned DiagnosticIDs::getCustomDiagID(Level L, llvm::StringRef Message) { 237 if (CustomDiagInfo == 0) 238 CustomDiagInfo = new diag::CustomDiagInfo(); 239 return CustomDiagInfo->getOrCreateDiagID(L, Message, *this); 240} 241 242 243/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic 244/// level of the specified diagnostic ID is a Warning or Extension. 245/// This only works on builtin diagnostics, not custom ones, and is not legal to 246/// call on NOTEs. 247bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) { 248 return DiagID < diag::DIAG_UPPER_LIMIT && 249 getBuiltinDiagClass(DiagID) != CLASS_ERROR; 250} 251 252/// \brief Determine whether the given built-in diagnostic ID is a 253/// Note. 254bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) { 255 return DiagID < diag::DIAG_UPPER_LIMIT && 256 getBuiltinDiagClass(DiagID) == CLASS_NOTE; 257} 258 259/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic 260/// ID is for an extension of some sort. This also returns EnabledByDefault, 261/// which is set to indicate whether the diagnostic is ignored by default (in 262/// which case -pedantic enables it) or treated as a warning/error by default. 263/// 264bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID, 265 bool &EnabledByDefault) { 266 if (DiagID >= diag::DIAG_UPPER_LIMIT || 267 getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) 268 return false; 269 270 EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE; 271 return true; 272} 273 274/// getDescription - Given a diagnostic ID, return a description of the 275/// issue. 276const char *DiagnosticIDs::getDescription(unsigned DiagID) const { 277 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) 278 return Info->Description; 279 return CustomDiagInfo->getDescription(DiagID); 280} 281 282/// getDiagnosticLevel - Based on the way the client configured the Diagnostic 283/// object, classify the specified diagnostic ID into a Level, consumable by 284/// the DiagnosticClient. 285DiagnosticIDs::Level 286DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, 287 const Diagnostic &Diag) const { 288 // Handle custom diagnostics, which cannot be mapped. 289 if (DiagID >= diag::DIAG_UPPER_LIMIT) 290 return CustomDiagInfo->getLevel(DiagID); 291 292 unsigned DiagClass = getBuiltinDiagClass(DiagID); 293 assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!"); 294 return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag); 295} 296 297/// \brief Based on the way the client configured the Diagnostic 298/// object, classify the specified diagnostic ID into a Level, consumable by 299/// the DiagnosticClient. 300/// 301/// \param Loc The source location we are interested in finding out the 302/// diagnostic state. Can be null in order to query the latest state. 303DiagnosticIDs::Level 304DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, 305 SourceLocation Loc, 306 const Diagnostic &Diag) const { 307 // Specific non-error diagnostics may be mapped to various levels from ignored 308 // to error. Errors can only be mapped to fatal. 309 DiagnosticIDs::Level Result = DiagnosticIDs::Fatal; 310 311 Diagnostic::DiagStatePointsTy::iterator 312 Pos = Diag.GetDiagStatePointForLoc(Loc); 313 Diagnostic::DiagState *State = Pos->State; 314 315 // Get the mapping information, if unset, compute it lazily. 316 unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID, 317 State); 318 if (MappingInfo == 0) { 319 MappingInfo = GetDefaultDiagMapping(DiagID); 320 Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false); 321 } 322 323 switch (MappingInfo & 7) { 324 default: assert(0 && "Unknown mapping!"); 325 case diag::MAP_IGNORE: 326 // Ignore this, unless this is an extension diagnostic and we're mapping 327 // them onto warnings or errors. 328 if (!isBuiltinExtensionDiag(DiagID) || // Not an extension 329 Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored 330 (MappingInfo & 8) != 0) // User explicitly mapped it. 331 return DiagnosticIDs::Ignored; 332 Result = DiagnosticIDs::Warning; 333 if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error; 334 if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal) 335 Result = DiagnosticIDs::Fatal; 336 break; 337 case diag::MAP_ERROR: 338 Result = DiagnosticIDs::Error; 339 if (Diag.ErrorsAsFatal) 340 Result = DiagnosticIDs::Fatal; 341 break; 342 case diag::MAP_FATAL: 343 Result = DiagnosticIDs::Fatal; 344 break; 345 case diag::MAP_WARNING: 346 // If warnings are globally mapped to ignore or error, do it. 347 if (Diag.IgnoreAllWarnings) 348 return DiagnosticIDs::Ignored; 349 350 Result = DiagnosticIDs::Warning; 351 352 // If this is an extension diagnostic and we're in -pedantic-error mode, and 353 // if the user didn't explicitly map it, upgrade to an error. 354 if (Diag.ExtBehavior == Diagnostic::Ext_Error && 355 (MappingInfo & 8) == 0 && 356 isBuiltinExtensionDiag(DiagID)) 357 Result = DiagnosticIDs::Error; 358 359 if (Diag.WarningsAsErrors) 360 Result = DiagnosticIDs::Error; 361 if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal) 362 Result = DiagnosticIDs::Fatal; 363 break; 364 365 case diag::MAP_WARNING_NO_WERROR: 366 // Diagnostics specified with -Wno-error=foo should be set to warnings, but 367 // not be adjusted by -Werror or -pedantic-errors. 368 Result = DiagnosticIDs::Warning; 369 370 // If warnings are globally mapped to ignore or error, do it. 371 if (Diag.IgnoreAllWarnings) 372 return DiagnosticIDs::Ignored; 373 374 break; 375 376 case diag::MAP_ERROR_NO_WFATAL: 377 // Diagnostics specified as -Wno-fatal-error=foo should be errors, but 378 // unaffected by -Wfatal-errors. 379 Result = DiagnosticIDs::Error; 380 break; 381 } 382 383 // Okay, we're about to return this as a "diagnostic to emit" one last check: 384 // if this is any sort of extension warning, and if we're in an __extension__ 385 // block, silence it. 386 if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID)) 387 return DiagnosticIDs::Ignored; 388 389 return Result; 390} 391 392struct WarningOption { 393 const char *Name; 394 const short *Members; 395 const short *SubGroups; 396}; 397 398#define GET_DIAG_ARRAYS 399#include "clang/Basic/DiagnosticGroups.inc" 400#undef GET_DIAG_ARRAYS 401 402// Second the table of options, sorted by name for fast binary lookup. 403static const WarningOption OptionTable[] = { 404#define GET_DIAG_TABLE 405#include "clang/Basic/DiagnosticGroups.inc" 406#undef GET_DIAG_TABLE 407}; 408static const size_t OptionTableSize = 409sizeof(OptionTable) / sizeof(OptionTable[0]); 410 411static bool WarningOptionCompare(const WarningOption &LHS, 412 const WarningOption &RHS) { 413 return strcmp(LHS.Name, RHS.Name) < 0; 414} 415 416static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, 417 SourceLocation Loc, Diagnostic &Diag) { 418 // Option exists, poke all the members of its diagnostic set. 419 if (const short *Member = Group->Members) { 420 for (; *Member != -1; ++Member) 421 Diag.setDiagnosticMapping(*Member, Mapping, Loc); 422 } 423 424 // Enable/disable all subgroups along with this one. 425 if (const short *SubGroups = Group->SubGroups) { 426 for (; *SubGroups != (short)-1; ++SubGroups) 427 MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag); 428 } 429} 430 431/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. 432/// "unknown-pragmas" to have the specified mapping. This returns true and 433/// ignores the request if "Group" was unknown, false otherwise. 434bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group, 435 diag::Mapping Map, 436 SourceLocation Loc, 437 Diagnostic &Diag) const { 438 assert((Loc.isValid() || 439 Diag.DiagStatePoints.empty() || 440 Diag.DiagStatePoints.back().Loc.isInvalid()) && 441 "Loc should be invalid only when the mapping comes from command-line"); 442 assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() || 443 Diag.DiagStatePoints.back().Loc.isInvalid() || 444 !Diag.SourceMgr->isBeforeInTranslationUnit(Loc, 445 Diag.DiagStatePoints.back().Loc)) && 446 "Source location of new mapping is before the previous one!"); 447 448 WarningOption Key = { Group, 0, 0 }; 449 const WarningOption *Found = 450 std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key, 451 WarningOptionCompare); 452 if (Found == OptionTable + OptionTableSize || 453 strcmp(Found->Name, Group) != 0) 454 return true; // Option not found. 455 456 MapGroupMembers(Found, Map, Loc, Diag); 457 return false; 458} 459 460/// ProcessDiag - This is the method used to report a diagnostic that is 461/// finally fully formed. 462bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { 463 DiagnosticInfo Info(&Diag); 464 465 if (Diag.SuppressAllDiagnostics) 466 return false; 467 468 assert(Diag.getClient() && "DiagnosticClient not set!"); 469 470 // Figure out the diagnostic level of this message. 471 DiagnosticIDs::Level DiagLevel; 472 unsigned DiagID = Info.getID(); 473 474 // ShouldEmitInSystemHeader - True if this diagnostic should be produced even 475 // in a system header. 476 bool ShouldEmitInSystemHeader; 477 478 if (DiagID >= diag::DIAG_UPPER_LIMIT) { 479 // Handle custom diagnostics, which cannot be mapped. 480 DiagLevel = CustomDiagInfo->getLevel(DiagID); 481 482 // Custom diagnostics always are emitted in system headers. 483 ShouldEmitInSystemHeader = true; 484 } else { 485 // Get the class of the diagnostic. If this is a NOTE, map it onto whatever 486 // the diagnostic level was for the previous diagnostic so that it is 487 // filtered the same as the previous diagnostic. 488 unsigned DiagClass = getBuiltinDiagClass(DiagID); 489 if (DiagClass == CLASS_NOTE) { 490 DiagLevel = DiagnosticIDs::Note; 491 ShouldEmitInSystemHeader = false; // extra consideration is needed 492 } else { 493 // If this is not an error and we are in a system header, we ignore it. 494 // Check the original Diag ID here, because we also want to ignore 495 // extensions and warnings in -Werror and -pedantic-errors modes, which 496 // *map* warnings/extensions to errors. 497 ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR; 498 499 DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(), 500 Diag); 501 } 502 } 503 504 if (DiagLevel != DiagnosticIDs::Note) { 505 // Record that a fatal error occurred only when we see a second 506 // non-note diagnostic. This allows notes to be attached to the 507 // fatal error, but suppresses any diagnostics that follow those 508 // notes. 509 if (Diag.LastDiagLevel == DiagnosticIDs::Fatal) 510 Diag.FatalErrorOccurred = true; 511 512 Diag.LastDiagLevel = DiagLevel; 513 } 514 515 // If a fatal error has already been emitted, silence all subsequent 516 // diagnostics. 517 if (Diag.FatalErrorOccurred) { 518 if (DiagLevel >= DiagnosticIDs::Error && 519 Diag.Client->IncludeInDiagnosticCounts()) { 520 ++Diag.NumErrors; 521 ++Diag.NumErrorsSuppressed; 522 } 523 524 return false; 525 } 526 527 // If the client doesn't care about this message, don't issue it. If this is 528 // a note and the last real diagnostic was ignored, ignore it too. 529 if (DiagLevel == DiagnosticIDs::Ignored || 530 (DiagLevel == DiagnosticIDs::Note && 531 Diag.LastDiagLevel == DiagnosticIDs::Ignored)) 532 return false; 533 534 // If this diagnostic is in a system header and is not a clang error, suppress 535 // it. 536 if (Diag.SuppressSystemWarnings && !ShouldEmitInSystemHeader && 537 Info.getLocation().isValid() && 538 Diag.getSourceManager().isInSystemHeader( 539 Diag.getSourceManager().getInstantiationLoc(Info.getLocation())) && 540 (DiagLevel != DiagnosticIDs::Note || 541 Diag.LastDiagLevel == DiagnosticIDs::Ignored)) { 542 Diag.LastDiagLevel = DiagnosticIDs::Ignored; 543 return false; 544 } 545 546 if (DiagLevel >= DiagnosticIDs::Error) { 547 if (Diag.Client->IncludeInDiagnosticCounts()) { 548 Diag.ErrorOccurred = true; 549 ++Diag.NumErrors; 550 } 551 552 // If we've emitted a lot of errors, emit a fatal error after it to stop a 553 // flood of bogus errors. 554 if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit && 555 DiagLevel == DiagnosticIDs::Error) 556 Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors); 557 } 558 559 // Finally, report it. 560 Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info); 561 if (Diag.Client->IncludeInDiagnosticCounts()) { 562 if (DiagLevel == DiagnosticIDs::Warning) 563 ++Diag.NumWarnings; 564 } 565 566 Diag.CurDiagID = ~0U; 567 568 return true; 569} 570