Diagnostic.h revision e89b6b272f9f3b15afa56a701a4d7a6b1001ed34
1//===--- Diagnostic.h - C Language Family Diagnostic Handling ---*- C++ -*-===// 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 defines the Diagnostic-related interfaces. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_CLANG_DIAGNOSTIC_H 15#define LLVM_CLANG_DIAGNOSTIC_H 16 17#include "clang/Basic/SourceLocation.h" 18#include <string> 19#include <cassert> 20 21namespace llvm { 22 template <typename T> class SmallVectorImpl; 23} 24 25namespace clang { 26 class DiagnosticClient; 27 class SourceRange; 28 class DiagnosticBuilder; 29 class IdentifierInfo; 30 31 // Import the diagnostic enums themselves. 32 namespace diag { 33 // Start position for diagnostics. 34 enum { 35 DIAG_START_DRIVER = 300, 36 DIAG_START_FRONTEND = DIAG_START_DRIVER + 100, 37 DIAG_START_LEX = DIAG_START_FRONTEND + 100, 38 DIAG_START_PARSE = DIAG_START_LEX + 300, 39 DIAG_START_AST = DIAG_START_PARSE + 300, 40 DIAG_START_SEMA = DIAG_START_AST + 100, 41 DIAG_START_ANALYSIS = DIAG_START_SEMA + 1000, 42 DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 43 }; 44 45 class CustomDiagInfo; 46 47 /// diag::kind - All of the diagnostics that can be emitted by the frontend. 48 typedef unsigned kind; 49 50 // Get typedefs for common diagnostics. 51 enum { 52#define DIAG(ENUM,FLAGS,DESC) ENUM, 53#include "clang/Basic/DiagnosticCommonKinds.def" 54 NUM_BUILTIN_COMMON_DIAGNOSTICS 55#undef DIAG 56 }; 57 58 /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs 59 /// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR 60 /// (emit as an error), or MAP_DEFAULT (handle the default way). It allows 61 /// clients to map errors to MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop 62 /// emitting diagnostics after this one). 63 enum Mapping { 64 MAP_DEFAULT = 0, //< Do not map this diagnostic. 65 MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it. 66 MAP_WARNING = 2, //< Map this diagnostic to a warning. 67 MAP_ERROR = 3, //< Map this diagnostic to an error. 68 MAP_FATAL = 4 //< Map this diagnostic to a fatal error. 69 }; 70 } 71 72/// \brief Annotates a diagnostic with some code that should be 73/// inserted, removed, or replaced to fix the problem. 74/// 75/// This kind of hint should be used when we are certain that the 76/// introduction, removal, or modification of a particular (small!) 77/// amount of code will correct a compilation error. The compiler 78/// should also provide full recovery from such errors, such that 79/// suppressing the diagnostic output can still result in successful 80/// compilation. 81class CodeModificationHint { 82public: 83 /// \brief Tokens that should be removed to correct the error. 84 SourceRange RemoveRange; 85 86 /// \brief The location at which we should insert code to correct 87 /// the error. 88 SourceLocation InsertionLoc; 89 90 /// \brief The actual code to insert at the insertion location, as a 91 /// string. 92 std::string CodeToInsert; 93 94 /// \brief Empty code modification hint, indicating that no code 95 /// modification is known. 96 CodeModificationHint() : RemoveRange(), InsertionLoc() { } 97 98 /// \brief Create a code modification hint that inserts the given 99 /// code string at a specific location. 100 static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc, 101 const std::string &Code) { 102 CodeModificationHint Hint; 103 Hint.InsertionLoc = InsertionLoc; 104 Hint.CodeToInsert = Code; 105 return Hint; 106 } 107 108 /// \brief Create a code modification hint that removes the given 109 /// source range. 110 static CodeModificationHint CreateRemoval(SourceRange RemoveRange) { 111 CodeModificationHint Hint; 112 Hint.RemoveRange = RemoveRange; 113 return Hint; 114 } 115 116 /// \brief Create a code modification hint that replaces the given 117 /// source range with the given code string. 118 static CodeModificationHint CreateReplacement(SourceRange RemoveRange, 119 const std::string &Code) { 120 CodeModificationHint Hint; 121 Hint.RemoveRange = RemoveRange; 122 Hint.InsertionLoc = RemoveRange.getBegin(); 123 Hint.CodeToInsert = Code; 124 return Hint; 125 } 126}; 127 128/// \brief A hook function that will be invoked after we have 129/// completed processing of the current diagnostic. 130/// 131/// Hook functions are typically used to emit further diagnostics 132/// (typically notes) that give more information about this 133/// diagnostic. 134struct PostDiagnosticHook { 135 /// \brief The type of the hook function itself. 136 /// 137 /// DiagID is the ID of the diagnostic to which the hook was 138 /// attached, and Cookie is a user-specified value that can be used 139 /// to store extra data for the hook. 140 typedef void (*HookTy)(unsigned DiagID, void *Cookie); 141 142 PostDiagnosticHook() {} 143 144 PostDiagnosticHook(HookTy Hook, void *Cookie) : Hook(Hook), Cookie(Cookie) { 145 assert(Hook && "No hook provided!"); 146 } 147 148 /// \brief The hook function. 149 HookTy Hook; 150 151 /// \brief The cookie that will be passed along to the hook function. 152 void *Cookie; 153}; 154 155/// Diagnostic - This concrete class is used by the front-end to report 156/// problems and issues. It massages the diagnostics (e.g. handling things like 157/// "report warnings as errors" and passes them off to the DiagnosticClient for 158/// reporting to the user. 159class Diagnostic { 160public: 161 /// Level - The level of the diagnostic, after it has been through mapping. 162 enum Level { 163 Ignored, Note, Warning, Error, Fatal 164 }; 165 166 enum ArgumentKind { 167 ak_std_string, // std::string 168 ak_c_string, // const char * 169 ak_sint, // int 170 ak_uint, // unsigned 171 ak_identifierinfo, // IdentifierInfo 172 ak_qualtype, // QualType 173 ak_declarationname, // DeclarationName 174 ak_nameddecl // NamedDecl * 175 }; 176 177private: 178 bool IgnoreAllWarnings; // Ignore all warnings: -w 179 bool WarningsAsErrors; // Treat warnings like errors: 180 bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic. 181 bool ErrorOnExtensions; // Error on extensions: -pedantic-errors. 182 bool SuppressSystemWarnings;// Suppress warnings in system headers. 183 DiagnosticClient *Client; 184 185 /// DiagMappings - Mapping information for diagnostics. Mapping info is 186 /// packed into four bits per diagnostic. 187 unsigned char DiagMappings[diag::DIAG_UPPER_LIMIT/2]; 188 189 /// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or 190 /// fatal error is emitted, and is sticky. 191 bool ErrorOccurred; 192 bool FatalErrorOccurred; 193 194 /// LastDiagLevel - This is the level of the last diagnostic emitted. This is 195 /// used to emit continuation diagnostics with the same level as the 196 /// diagnostic that they follow. 197 Diagnostic::Level LastDiagLevel; 198 199 unsigned NumDiagnostics; // Number of diagnostics reported 200 unsigned NumErrors; // Number of diagnostics that are errors 201 202 /// CustomDiagInfo - Information for uniquing and looking up custom diags. 203 diag::CustomDiagInfo *CustomDiagInfo; 204 205 /// ArgToStringFn - A function pointer that converts an opaque diagnostic 206 /// argument to a strings. This takes the modifiers and argument that was 207 /// present in the diagnostic. 208 /// This is a hack to avoid a layering violation between libbasic and libsema. 209 typedef void (*ArgToStringFnTy)(ArgumentKind Kind, intptr_t Val, 210 const char *Modifier, unsigned ModifierLen, 211 const char *Argument, unsigned ArgumentLen, 212 llvm::SmallVectorImpl<char> &Output, 213 void *Cookie); 214 void *ArgToStringCookie; 215 ArgToStringFnTy ArgToStringFn; 216public: 217 explicit Diagnostic(DiagnosticClient *client = 0); 218 ~Diagnostic(); 219 220 //===--------------------------------------------------------------------===// 221 // Diagnostic characterization methods, used by a client to customize how 222 // 223 224 DiagnosticClient *getClient() { return Client; }; 225 const DiagnosticClient *getClient() const { return Client; }; 226 227 void setClient(DiagnosticClient* client) { Client = client; } 228 229 /// setIgnoreAllWarnings - When set to true, any unmapped warnings are 230 /// ignored. If this and WarningsAsErrors are both set, then this one wins. 231 void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } 232 bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } 233 234 /// setWarningsAsErrors - When set to true, any warnings reported are issued 235 /// as errors. 236 void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } 237 bool getWarningsAsErrors() const { return WarningsAsErrors; } 238 239 /// setWarnOnExtensions - When set to true, issue warnings on GCC extensions, 240 /// the equivalent of GCC's -pedantic. 241 void setWarnOnExtensions(bool Val) { WarnOnExtensions = Val; } 242 bool getWarnOnExtensions() const { return WarnOnExtensions; } 243 244 /// setErrorOnExtensions - When set to true issue errors for GCC extensions 245 /// instead of warnings. This is the equivalent to GCC's -pedantic-errors. 246 void setErrorOnExtensions(bool Val) { ErrorOnExtensions = Val; } 247 bool getErrorOnExtensions() const { return ErrorOnExtensions; } 248 249 /// setSuppressSystemWarnings - When set to true mask warnings that 250 /// come from system headers. 251 void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } 252 bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } 253 254 /// setDiagnosticMapping - This allows the client to specify that certain 255 /// warnings are ignored. Only WARNINGs and EXTENSIONs can be mapped. 256 void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) { 257 assert(Diag < diag::DIAG_UPPER_LIMIT && 258 "Can only map builtin diagnostics"); 259 assert((isBuiltinWarningOrExtension(Diag) || Map == diag::MAP_FATAL) && 260 "Cannot map errors!"); 261 unsigned char &Slot = DiagMappings[Diag/2]; 262 unsigned Bits = (Diag & 1)*4; 263 Slot &= ~(7 << Bits); 264 Slot |= Map << Bits; 265 } 266 267 /// getDiagnosticMapping - Return the mapping currently set for the specified 268 /// diagnostic. 269 diag::Mapping getDiagnosticMapping(diag::kind Diag) const { 270 return (diag::Mapping)((DiagMappings[Diag/2] >> (Diag & 1)*4) & 7); 271 } 272 273 bool hasErrorOccurred() const { return ErrorOccurred; } 274 bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } 275 276 unsigned getNumErrors() const { return NumErrors; } 277 unsigned getNumDiagnostics() const { return NumDiagnostics; } 278 279 /// getCustomDiagID - Return an ID for a diagnostic with the specified message 280 /// and level. If this is the first request for this diagnosic, it is 281 /// registered and created, otherwise the existing ID is returned. 282 unsigned getCustomDiagID(Level L, const char *Message); 283 284 285 /// ConvertArgToString - This method converts a diagnostic argument (as an 286 /// intptr_t) into the string that represents it. 287 void ConvertArgToString(ArgumentKind Kind, intptr_t Val, 288 const char *Modifier, unsigned ModLen, 289 const char *Argument, unsigned ArgLen, 290 llvm::SmallVectorImpl<char> &Output) const { 291 ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output, 292 ArgToStringCookie); 293 } 294 295 void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { 296 ArgToStringFn = Fn; 297 ArgToStringCookie = Cookie; 298 } 299 300 //===--------------------------------------------------------------------===// 301 // Diagnostic classification and reporting interfaces. 302 // 303 304 /// getDescription - Given a diagnostic ID, return a description of the 305 /// issue. 306 const char *getDescription(unsigned DiagID) const; 307 308 /// isNoteWarningOrExtension - Return true if the unmapped diagnostic 309 /// level of the specified diagnostic ID is a Warning or Extension. 310 /// This only works on builtin diagnostics, not custom ones, and is not legal to 311 /// call on NOTEs. 312 static bool isBuiltinWarningOrExtension(unsigned DiagID); 313 314 /// \brief Determine whether the given built-in diagnostic ID is a 315 /// Note. 316 static bool isBuiltinNote(unsigned DiagID); 317 318 /// getDiagnosticLevel - Based on the way the client configured the Diagnostic 319 /// object, classify the specified diagnostic ID into a Level, consumable by 320 /// the DiagnosticClient. 321 Level getDiagnosticLevel(unsigned DiagID) const; 322 323 /// Report - Issue the message to the client. @c DiagID is a member of the 324 /// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder 325 /// which emits the diagnostics (through @c ProcessDiag) when it is destroyed. 326 /// @c Pos represents the source location associated with the diagnostic, 327 /// which can be an invalid location if no position information is available. 328 inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID); 329 330private: 331 /// getDiagnosticLevel - This is an internal implementation helper used when 332 /// DiagClass is already known. 333 Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const; 334 335 // This is private state used by DiagnosticBuilder. We put it here instead of 336 // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight 337 // object. This implementation choice means that we can only have one 338 // diagnostic "in flight" at a time, but this seems to be a reasonable 339 // tradeoff to keep these objects small. Assertions verify that only one 340 // diagnostic is in flight at a time. 341 friend class DiagnosticBuilder; 342 friend class DiagnosticInfo; 343 344 /// CurDiagLoc - This is the location of the current diagnostic that is in 345 /// flight. 346 FullSourceLoc CurDiagLoc; 347 348 /// CurDiagID - This is the ID of the current diagnostic that is in flight. 349 /// This is set to ~0U when there is no diagnostic in flight. 350 unsigned CurDiagID; 351 352 enum { 353 /// MaxArguments - The maximum number of arguments we can hold. We currently 354 /// only support up to 10 arguments (%0-%9). A single diagnostic with more 355 /// than that almost certainly has to be simplified anyway. 356 MaxArguments = 10 357 }; 358 359 /// NumDiagArgs - This contains the number of entries in Arguments. 360 signed char NumDiagArgs; 361 /// NumRanges - This is the number of ranges in the DiagRanges array. 362 unsigned char NumDiagRanges; 363 /// \brief The number of code modifications hints in the 364 /// CodeModificationHints array. 365 unsigned char NumCodeModificationHints; 366 /// \brief The number of post-diagnostic hooks in the 367 /// PostDiagnosticHooks array. 368 unsigned char NumPostDiagnosticHooks; 369 370 /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum 371 /// values, with one for each argument. This specifies whether the argument 372 /// is in DiagArgumentsStr or in DiagArguments. 373 unsigned char DiagArgumentsKind[MaxArguments]; 374 375 /// DiagArgumentsStr - This holds the values of each string argument for the 376 /// current diagnostic. This value is only used when the corresponding 377 /// ArgumentKind is ak_std_string. 378 std::string DiagArgumentsStr[MaxArguments]; 379 380 /// DiagArgumentsVal - The values for the various substitution positions. This 381 /// is used when the argument is not an std::string. The specific value is 382 /// mangled into an intptr_t and the intepretation depends on exactly what 383 /// sort of argument kind it is. 384 intptr_t DiagArgumentsVal[MaxArguments]; 385 386 /// DiagRanges - The list of ranges added to this diagnostic. It currently 387 /// only support 10 ranges, could easily be extended if needed. 388 const SourceRange *DiagRanges[10]; 389 390 enum { MaxCodeModificationHints = 3 }; 391 392 /// CodeModificationHints - If valid, provides a hint with some code 393 /// to insert, remove, or modify at a particular position. 394 CodeModificationHint CodeModificationHints[MaxCodeModificationHints]; 395 396 enum { MaxPostDiagnosticHooks = 10 }; 397 398 /// \brief Functions that will be invoked after the diagnostic has 399 /// been emitted. 400 PostDiagnosticHook PostDiagnosticHooks[MaxPostDiagnosticHooks]; 401 402 /// \brief Whether we're already within a post-diagnostic hook. 403 bool InPostDiagnosticHook; 404 405 /// ProcessDiag - This is the method used to report a diagnostic that is 406 /// finally fully formed. 407 void ProcessDiag(); 408}; 409 410//===----------------------------------------------------------------------===// 411// DiagnosticBuilder 412//===----------------------------------------------------------------------===// 413 414/// DiagnosticBuilder - This is a little helper class used to produce 415/// diagnostics. This is constructed by the Diagnostic::Report method, and 416/// allows insertion of extra information (arguments and source ranges) into the 417/// currently "in flight" diagnostic. When the temporary for the builder is 418/// destroyed, the diagnostic is issued. 419/// 420/// Note that many of these will be created as temporary objects (many call 421/// sites), so we want them to be small and we never want their address taken. 422/// This ensures that compilers with somewhat reasonable optimizers will promote 423/// the common fields to registers, eliminating increments of the NumArgs field, 424/// for example. 425class DiagnosticBuilder { 426 mutable Diagnostic *DiagObj; 427 mutable unsigned NumArgs, NumRanges, NumCodeModificationHints, 428 NumPostDiagnosticHooks; 429 430 void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT 431 friend class Diagnostic; 432 explicit DiagnosticBuilder(Diagnostic *diagObj) 433 : DiagObj(diagObj), NumArgs(0), NumRanges(0), 434 NumCodeModificationHints(0), NumPostDiagnosticHooks(0) {} 435 436public: 437 /// Copy constructor. When copied, this "takes" the diagnostic info from the 438 /// input and neuters it. 439 DiagnosticBuilder(const DiagnosticBuilder &D) { 440 DiagObj = D.DiagObj; 441 D.DiagObj = 0; 442 } 443 444 /// Destructor - The dtor emits the diagnostic. 445 ~DiagnosticBuilder() { 446 // If DiagObj is null, then its soul was stolen by the copy ctor. 447 if (DiagObj == 0) return; 448 449 // When destroyed, the ~DiagnosticBuilder sets the final argument count into 450 // the Diagnostic object. 451 DiagObj->NumDiagArgs = NumArgs; 452 DiagObj->NumDiagRanges = NumRanges; 453 DiagObj->NumCodeModificationHints = NumCodeModificationHints; 454 DiagObj->NumPostDiagnosticHooks = NumPostDiagnosticHooks; 455 456 // Process the diagnostic, sending the accumulated information to the 457 // DiagnosticClient. 458 DiagObj->ProcessDiag(); 459 460 // This diagnostic is no longer in flight. 461 DiagObj->CurDiagID = ~0U; 462 } 463 464 /// Operator bool: conversion of DiagnosticBuilder to bool always returns 465 /// true. This allows is to be used in boolean error contexts like: 466 /// return Diag(...); 467 operator bool() const { return true; } 468 469 void AddString(const std::string &S) const { 470 assert(NumArgs < Diagnostic::MaxArguments && 471 "Too many arguments to diagnostic!"); 472 DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string; 473 DiagObj->DiagArgumentsStr[NumArgs++] = S; 474 } 475 476 void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const { 477 assert(NumArgs < Diagnostic::MaxArguments && 478 "Too many arguments to diagnostic!"); 479 DiagObj->DiagArgumentsKind[NumArgs] = Kind; 480 DiagObj->DiagArgumentsVal[NumArgs++] = V; 481 } 482 483 void AddSourceRange(const SourceRange &R) const { 484 assert(NumRanges < 485 sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && 486 "Too many arguments to diagnostic!"); 487 DiagObj->DiagRanges[NumRanges++] = &R; 488 } 489 490 void AddCodeModificationHint(const CodeModificationHint &Hint) const { 491 assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints && 492 "Too many code modification hints!"); 493 DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint; 494 } 495 496 void AddPostDiagnosticHook(const PostDiagnosticHook &Hook) const { 497 assert(!DiagObj->InPostDiagnosticHook && 498 "Can't add a post-diagnostic hook to a diagnostic inside " 499 "a post-diagnostic hook"); 500 assert(NumPostDiagnosticHooks < Diagnostic::MaxPostDiagnosticHooks && 501 "Too many post-diagnostic hooks"); 502 DiagObj->PostDiagnosticHooks[NumPostDiagnosticHooks++] = Hook; 503 } 504}; 505 506inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 507 const std::string &S) { 508 DB.AddString(S); 509 return DB; 510} 511 512inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 513 const char *Str) { 514 DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str), 515 Diagnostic::ak_c_string); 516 return DB; 517} 518 519inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) { 520 DB.AddTaggedVal(I, Diagnostic::ak_sint); 521 return DB; 522} 523 524inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) { 525 DB.AddTaggedVal(I, Diagnostic::ak_sint); 526 return DB; 527} 528 529inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 530 unsigned I) { 531 DB.AddTaggedVal(I, Diagnostic::ak_uint); 532 return DB; 533} 534 535inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 536 const IdentifierInfo *II) { 537 DB.AddTaggedVal(reinterpret_cast<intptr_t>(II), 538 Diagnostic::ak_identifierinfo); 539 return DB; 540} 541 542inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 543 const SourceRange &R) { 544 DB.AddSourceRange(R); 545 return DB; 546} 547 548inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 549 const CodeModificationHint &Hint) { 550 DB.AddCodeModificationHint(Hint); 551 return DB; 552} 553 554inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 555 const PostDiagnosticHook &Hook) { 556 DB.AddPostDiagnosticHook(Hook); 557 return DB; 558} 559 560 561/// Report - Issue the message to the client. DiagID is a member of the 562/// diag::kind enum. This actually returns a new instance of DiagnosticBuilder 563/// which emits the diagnostics (through ProcessDiag) when it is destroyed. 564inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned DiagID){ 565 assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); 566 CurDiagLoc = Loc; 567 CurDiagID = DiagID; 568 return DiagnosticBuilder(this); 569} 570 571//===----------------------------------------------------------------------===// 572// DiagnosticInfo 573//===----------------------------------------------------------------------===// 574 575/// DiagnosticInfo - This is a little helper class (which is basically a smart 576/// pointer that forward info from Diagnostic) that allows clients to enquire 577/// about the currently in-flight diagnostic. 578class DiagnosticInfo { 579 const Diagnostic *DiagObj; 580public: 581 explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {} 582 583 const Diagnostic *getDiags() const { return DiagObj; } 584 unsigned getID() const { return DiagObj->CurDiagID; } 585 const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; } 586 587 unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } 588 589 /// getArgKind - Return the kind of the specified index. Based on the kind 590 /// of argument, the accessors below can be used to get the value. 591 Diagnostic::ArgumentKind getArgKind(unsigned Idx) const { 592 assert(Idx < getNumArgs() && "Argument index out of range!"); 593 return (Diagnostic::ArgumentKind)DiagObj->DiagArgumentsKind[Idx]; 594 } 595 596 /// getArgStdStr - Return the provided argument string specified by Idx. 597 const std::string &getArgStdStr(unsigned Idx) const { 598 assert(getArgKind(Idx) == Diagnostic::ak_std_string && 599 "invalid argument accessor!"); 600 return DiagObj->DiagArgumentsStr[Idx]; 601 } 602 603 /// getArgCStr - Return the specified C string argument. 604 const char *getArgCStr(unsigned Idx) const { 605 assert(getArgKind(Idx) == Diagnostic::ak_c_string && 606 "invalid argument accessor!"); 607 return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]); 608 } 609 610 /// getArgSInt - Return the specified signed integer argument. 611 int getArgSInt(unsigned Idx) const { 612 assert(getArgKind(Idx) == Diagnostic::ak_sint && 613 "invalid argument accessor!"); 614 return (int)DiagObj->DiagArgumentsVal[Idx]; 615 } 616 617 /// getArgUInt - Return the specified unsigned integer argument. 618 unsigned getArgUInt(unsigned Idx) const { 619 assert(getArgKind(Idx) == Diagnostic::ak_uint && 620 "invalid argument accessor!"); 621 return (unsigned)DiagObj->DiagArgumentsVal[Idx]; 622 } 623 624 /// getArgIdentifier - Return the specified IdentifierInfo argument. 625 const IdentifierInfo *getArgIdentifier(unsigned Idx) const { 626 assert(getArgKind(Idx) == Diagnostic::ak_identifierinfo && 627 "invalid argument accessor!"); 628 return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]); 629 } 630 631 /// getRawArg - Return the specified non-string argument in an opaque form. 632 intptr_t getRawArg(unsigned Idx) const { 633 assert(getArgKind(Idx) != Diagnostic::ak_std_string && 634 "invalid argument accessor!"); 635 return DiagObj->DiagArgumentsVal[Idx]; 636 } 637 638 639 /// getNumRanges - Return the number of source ranges associated with this 640 /// diagnostic. 641 unsigned getNumRanges() const { 642 return DiagObj->NumDiagRanges; 643 } 644 645 const SourceRange &getRange(unsigned Idx) const { 646 assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); 647 return *DiagObj->DiagRanges[Idx]; 648 } 649 650 unsigned getNumCodeModificationHints() const { 651 return DiagObj->NumCodeModificationHints; 652 } 653 654 const CodeModificationHint &getCodeModificationHint(unsigned Idx) const { 655 return DiagObj->CodeModificationHints[Idx]; 656 } 657 658 const CodeModificationHint *getCodeModificationHints() const { 659 return DiagObj->NumCodeModificationHints? 660 &DiagObj->CodeModificationHints[0] : 0; 661 } 662 663 /// FormatDiagnostic - Format this diagnostic into a string, substituting the 664 /// formal arguments into the %0 slots. The result is appended onto the Str 665 /// array. 666 void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const; 667}; 668 669/// DiagnosticClient - This is an abstract interface implemented by clients of 670/// the front-end, which formats and prints fully processed diagnostics. 671class DiagnosticClient { 672public: 673 virtual ~DiagnosticClient(); 674 675 /// IncludeInDiagnosticCounts - This method (whose default implementation 676 /// returns true) indicates whether the diagnostics handled by this 677 /// DiagnosticClient should be included in the number of diagnostics 678 /// reported by Diagnostic. 679 virtual bool IncludeInDiagnosticCounts() const; 680 681 /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or 682 /// capturing it to a log as needed. 683 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, 684 const DiagnosticInfo &Info) = 0; 685}; 686 687} // end namespace clang 688 689#endif 690