Diagnostic.h revision 509355e982d15da4f8f3939493516379665f6275
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 21#define DIAG_START_LEX 300 22#define DIAG_START_PARSE (DIAG_START_LEX + 300) 23#define DIAG_START_AST (DIAG_START_PARSE + 300) 24#define DIAG_START_SEMA (DIAG_START_AST + 100) 25#define DIAG_START_ANALYSIS (DIAG_START_SEMA + 1000) 26#define DIAG_UPPER_LIMIT (DIAG_START_ANALYSIS + 100) 27 28namespace llvm { 29 template <typename T> class SmallVectorImpl; 30} 31 32namespace clang { 33 class DiagnosticClient; 34 class SourceRange; 35 class SourceManager; 36 class DiagnosticBuilder; 37 class IdentifierInfo; 38 39 // Import the diagnostic enums themselves. 40 namespace diag { 41 class CustomDiagInfo; 42 43 /// diag::kind - All of the diagnostics that can be emitted by the frontend. 44 typedef unsigned kind; 45 46 /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs 47 /// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR 48 /// (emit as an error), or MAP_DEFAULT (handle the default way). 49 enum Mapping { 50 MAP_DEFAULT = 0, //< Do not map this diagnostic. 51 MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it. 52 MAP_WARNING = 2, //< Map this diagnostic to a warning. 53 MAP_ERROR = 3 //< Map this diagnostic to an error. 54 }; 55 } 56 57/// Diagnostic - This concrete class is used by the front-end to report 58/// problems and issues. It massages the diagnostics (e.g. handling things like 59/// "report warnings as errors" and passes them off to the DiagnosticClient for 60/// reporting to the user. 61class Diagnostic { 62public: 63 /// Level - The level of the diagnostic, after it has been through mapping. 64 enum Level { 65 Ignored, Note, Warning, Error 66 }; 67 68 enum ArgumentKind { 69 ak_std_string, // std::string 70 ak_c_string, // const char * 71 ak_sint, // int 72 ak_uint, // unsigned 73 ak_identifierinfo, // IdentifierInfo 74 ak_qualtype, // QualType 75 ak_declarationname // DeclarationName 76 }; 77 78private: 79 bool IgnoreAllWarnings; // Ignore all warnings: -w 80 bool WarningsAsErrors; // Treat warnings like errors: 81 bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic. 82 bool ErrorOnExtensions; // Error on extensions: -pedantic-errors. 83 bool SuppressSystemWarnings;// Suppress warnings in system headers. 84 DiagnosticClient *Client; 85 86 /// DiagMappings - Mapping information for diagnostics. Mapping info is 87 /// packed into two bits per diagnostic. 88 unsigned char DiagMappings[DIAG_UPPER_LIMIT/4]; 89 90 /// ErrorOccurred - This is set to true when an error is emitted, and is 91 /// sticky. 92 bool ErrorOccurred; 93 94 unsigned NumDiagnostics; // Number of diagnostics reported 95 unsigned NumErrors; // Number of diagnostics that are errors 96 97 /// CustomDiagInfo - Information for uniquing and looking up custom diags. 98 diag::CustomDiagInfo *CustomDiagInfo; 99 100 /// ArgToStringFn - A function pointer that converts an opaque diagnostic 101 /// argument to a strings. This takes the modifiers and argument that was 102 /// present in the diagnostic. 103 /// This is a hack to avoid a layering violation between libbasic and libsema. 104 typedef void (*ArgToStringFnTy)(ArgumentKind Kind, intptr_t Val, 105 const char *Modifier, unsigned ModifierLen, 106 const char *Argument, unsigned ArgumentLen, 107 llvm::SmallVectorImpl<char> &Output); 108 ArgToStringFnTy ArgToStringFn; 109public: 110 explicit Diagnostic(DiagnosticClient *client = 0); 111 ~Diagnostic(); 112 113 //===--------------------------------------------------------------------===// 114 // Diagnostic characterization methods, used by a client to customize how 115 // 116 117 DiagnosticClient *getClient() { return Client; }; 118 const DiagnosticClient *getClient() const { return Client; }; 119 120 void setClient(DiagnosticClient* client) { Client = client; } 121 122 /// setIgnoreAllWarnings - When set to true, any unmapped warnings are 123 /// ignored. If this and WarningsAsErrors are both set, then this one wins. 124 void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } 125 bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } 126 127 /// setWarningsAsErrors - When set to true, any warnings reported are issued 128 /// as errors. 129 void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } 130 bool getWarningsAsErrors() const { return WarningsAsErrors; } 131 132 /// setWarnOnExtensions - When set to true, issue warnings on GCC extensions, 133 /// the equivalent of GCC's -pedantic. 134 void setWarnOnExtensions(bool Val) { WarnOnExtensions = Val; } 135 bool getWarnOnExtensions() const { return WarnOnExtensions; } 136 137 /// setErrorOnExtensions - When set to true issue errors for GCC extensions 138 /// instead of warnings. This is the equivalent to GCC's -pedantic-errors. 139 void setErrorOnExtensions(bool Val) { ErrorOnExtensions = Val; } 140 bool getErrorOnExtensions() const { return ErrorOnExtensions; } 141 142 /// setSuppressSystemWarnings - When set to true mask warnings that 143 /// come from system headers. 144 void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } 145 bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } 146 147 /// setDiagnosticMapping - This allows the client to specify that certain 148 /// warnings are ignored. Only NOTEs, WARNINGs, and EXTENSIONs can be mapped. 149 void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) { 150 assert(Diag < DIAG_UPPER_LIMIT && 151 "Can only map builtin diagnostics"); 152 assert(isBuiltinNoteWarningOrExtension(Diag) && "Cannot map errors!"); 153 unsigned char &Slot = DiagMappings[Diag/4]; 154 unsigned Bits = (Diag & 3)*2; 155 Slot &= ~(3 << Bits); 156 Slot |= Map << Bits; 157 } 158 159 /// getDiagnosticMapping - Return the mapping currently set for the specified 160 /// diagnostic. 161 diag::Mapping getDiagnosticMapping(diag::kind Diag) const { 162 return (diag::Mapping)((DiagMappings[Diag/4] >> (Diag & 3)*2) & 3); 163 } 164 165 bool hasErrorOccurred() const { return ErrorOccurred; } 166 167 unsigned getNumErrors() const { return NumErrors; } 168 unsigned getNumDiagnostics() const { return NumDiagnostics; } 169 170 /// getCustomDiagID - Return an ID for a diagnostic with the specified message 171 /// and level. If this is the first request for this diagnosic, it is 172 /// registered and created, otherwise the existing ID is returned. 173 unsigned getCustomDiagID(Level L, const char *Message); 174 175 176 /// ConvertArgToString - This method converts a diagnostic argument (as an 177 /// intptr_t) into the string that represents it. 178 void ConvertArgToString(ArgumentKind Kind, intptr_t Val, 179 const char *Modifier, unsigned ModLen, 180 const char *Argument, unsigned ArgLen, 181 llvm::SmallVectorImpl<char> &Output) const { 182 ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output); 183 } 184 185 void SetArgToStringFn(ArgToStringFnTy Fn) { 186 ArgToStringFn = Fn; 187 } 188 189 //===--------------------------------------------------------------------===// 190 // Diagnostic classification and reporting interfaces. 191 // 192 193 /// getDescription - Given a diagnostic ID, return a description of the 194 /// issue. 195 const char *getDescription(unsigned DiagID) const; 196 197 /// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic 198 /// level of the specified diagnostic ID is a Note, Warning, or Extension. 199 /// Note that this only works on builtin diagnostics, not custom ones. 200 static bool isBuiltinNoteWarningOrExtension(unsigned DiagID); 201 202 /// getDiagnosticLevel - Based on the way the client configured the Diagnostic 203 /// object, classify the specified diagnostic ID into a Level, consumable by 204 /// the DiagnosticClient. 205 Level getDiagnosticLevel(unsigned DiagID) const; 206 207 208 /// Report - Issue the message to the client. @c DiagID is a member of the 209 /// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder 210 /// which emits the diagnostics (through @c ProcessDiag) when it is destroyed. 211 /// @c Pos represents the source location associated with the diagnostic, 212 /// which can be an invalid location if no position information is available. 213 inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID); 214 215private: 216 // This is private state used by DiagnosticBuilder. We put it here instead of 217 // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight 218 // object. This implementation choice means that we can only have one 219 // diagnostic "in flight" at a time, but this seems to be a reasonable 220 // tradeoff to keep these objects small. Assertions verify that only one 221 // diagnostic is in flight at a time. 222 friend class DiagnosticBuilder; 223 friend class DiagnosticInfo; 224 225 /// CurDiagLoc - This is the location of the current diagnostic that is in 226 /// flight. 227 FullSourceLoc CurDiagLoc; 228 229 /// CurDiagID - This is the ID of the current diagnostic that is in flight. 230 /// This is set to ~0U when there is no diagnostic in flight. 231 unsigned CurDiagID; 232 233 enum { 234 /// MaxArguments - The maximum number of arguments we can hold. We currently 235 /// only support up to 10 arguments (%0-%9). A single diagnostic with more 236 /// than that almost certainly has to be simplified anyway. 237 MaxArguments = 10 238 }; 239 240 /// NumDiagArgs - This contains the number of entries in Arguments. 241 signed char NumDiagArgs; 242 /// NumRanges - This is the number of ranges in the DiagRanges array. 243 unsigned char NumDiagRanges; 244 245 /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum 246 /// values, with one for each argument. This specifies whether the argument 247 /// is in DiagArgumentsStr or in DiagArguments. 248 unsigned char DiagArgumentsKind[MaxArguments]; 249 250 /// DiagArgumentsStr - This holds the values of each string argument for the 251 /// current diagnostic. This value is only used when the corresponding 252 /// ArgumentKind is ak_std_string. 253 std::string DiagArgumentsStr[MaxArguments]; 254 255 /// DiagArgumentsVal - The values for the various substitution positions. This 256 /// is used when the argument is not an std::string. The specific value is 257 /// mangled into an intptr_t and the intepretation depends on exactly what 258 /// sort of argument kind it is. 259 intptr_t DiagArgumentsVal[MaxArguments]; 260 261 /// DiagRanges - The list of ranges added to this diagnostic. It currently 262 /// only support 10 ranges, could easily be extended if needed. 263 const SourceRange *DiagRanges[10]; 264 265 /// ProcessDiag - This is the method used to report a diagnostic that is 266 /// finally fully formed. 267 void ProcessDiag(); 268}; 269 270//===----------------------------------------------------------------------===// 271// DiagnosticBuilder 272//===----------------------------------------------------------------------===// 273 274/// DiagnosticBuilder - This is a little helper class used to produce 275/// diagnostics. This is constructed by the Diagnostic::Report method, and 276/// allows insertion of extra information (arguments and source ranges) into the 277/// currently "in flight" diagnostic. When the temporary for the builder is 278/// destroyed, the diagnostic is issued. 279/// 280/// Note that many of these will be created as temporary objects (many call 281/// sites), so we want them to be small and we never want their address taken. 282/// This ensures that compilers with somewhat reasonable optimizers will promote 283/// the common fields to registers, eliminating increments of the NumArgs field, 284/// for example. 285class DiagnosticBuilder { 286 mutable Diagnostic *DiagObj; 287 mutable unsigned NumArgs, NumRanges; 288 289 void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT 290 friend class Diagnostic; 291 explicit DiagnosticBuilder(Diagnostic *diagObj) 292 : DiagObj(diagObj), NumArgs(0), NumRanges(0) {} 293public: 294 295 /// Copy constructor. When copied, this "takes" the diagnostic info from the 296 /// input and neuters it. 297 DiagnosticBuilder(const DiagnosticBuilder &D) { 298 DiagObj = D.DiagObj; 299 D.DiagObj = 0; 300 } 301 302 /// Destructor - The dtor emits the diagnostic. 303 ~DiagnosticBuilder() { 304 // If DiagObj is null, then its soul was stolen by the copy ctor. 305 if (DiagObj == 0) return; 306 307 // When destroyed, the ~DiagnosticBuilder sets the final argument count into 308 // the Diagnostic object. 309 DiagObj->NumDiagArgs = NumArgs; 310 DiagObj->NumDiagRanges = NumRanges; 311 312 // Process the diagnostic, sending the accumulated information to the 313 // DiagnosticClient. 314 DiagObj->ProcessDiag(); 315 316 // This diagnostic is no longer in flight. 317 DiagObj->CurDiagID = ~0U; 318 } 319 320 /// Operator bool: conversion of DiagnosticBuilder to bool always returns 321 /// true. This allows is to be used in boolean error contexts like: 322 /// return Diag(...); 323 operator bool() const { return true; } 324 325 void AddString(const std::string &S) const { 326 assert(NumArgs < Diagnostic::MaxArguments && 327 "Too many arguments to diagnostic!"); 328 DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string; 329 DiagObj->DiagArgumentsStr[NumArgs++] = S; 330 } 331 332 void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const { 333 assert(NumArgs < Diagnostic::MaxArguments && 334 "Too many arguments to diagnostic!"); 335 DiagObj->DiagArgumentsKind[NumArgs] = Kind; 336 DiagObj->DiagArgumentsVal[NumArgs++] = V; 337 } 338 339 void AddSourceRange(const SourceRange &R) const { 340 assert(NumRanges < 341 sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && 342 "Too many arguments to diagnostic!"); 343 DiagObj->DiagRanges[NumRanges++] = &R; 344 } 345}; 346 347inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 348 const std::string &S) { 349 DB.AddString(S); 350 return DB; 351} 352 353inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 354 const char *Str) { 355 DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str), 356 Diagnostic::ak_c_string); 357 return DB; 358} 359 360inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) { 361 DB.AddTaggedVal(I, Diagnostic::ak_sint); 362 return DB; 363} 364 365inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) { 366 DB.AddTaggedVal(I, Diagnostic::ak_sint); 367 return DB; 368} 369 370inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 371 unsigned I) { 372 DB.AddTaggedVal(I, Diagnostic::ak_uint); 373 return DB; 374} 375 376inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 377 const IdentifierInfo *II) { 378 DB.AddTaggedVal(reinterpret_cast<intptr_t>(II), 379 Diagnostic::ak_identifierinfo); 380 return DB; 381} 382 383inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 384 const SourceRange &R) { 385 DB.AddSourceRange(R); 386 return DB; 387} 388 389 390/// Report - Issue the message to the client. DiagID is a member of the 391/// diag::kind enum. This actually returns a new instance of DiagnosticBuilder 392/// which emits the diagnostics (through ProcessDiag) when it is destroyed. 393inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned DiagID){ 394 assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); 395 CurDiagLoc = Loc; 396 CurDiagID = DiagID; 397 return DiagnosticBuilder(this); 398} 399 400//===----------------------------------------------------------------------===// 401// DiagnosticInfo 402//===----------------------------------------------------------------------===// 403 404/// DiagnosticInfo - This is a little helper class (which is basically a smart 405/// pointer that forward info from Diagnostic) that allows clients ot enquire 406/// about the currently in-flight diagnostic. 407class DiagnosticInfo { 408 const Diagnostic *DiagObj; 409public: 410 explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {} 411 412 const Diagnostic *getDiags() const { return DiagObj; } 413 unsigned getID() const { return DiagObj->CurDiagID; } 414 const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; } 415 416 unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } 417 418 /// getArgKind - Return the kind of the specified index. Based on the kind 419 /// of argument, the accessors below can be used to get the value. 420 Diagnostic::ArgumentKind getArgKind(unsigned Idx) const { 421 assert(Idx < getNumArgs() && "Argument index out of range!"); 422 return (Diagnostic::ArgumentKind)DiagObj->DiagArgumentsKind[Idx]; 423 } 424 425 /// getArgStdStr - Return the provided argument string specified by Idx. 426 const std::string &getArgStdStr(unsigned Idx) const { 427 assert(getArgKind(Idx) == Diagnostic::ak_std_string && 428 "invalid argument accessor!"); 429 return DiagObj->DiagArgumentsStr[Idx]; 430 } 431 432 /// getArgCStr - Return the specified C string argument. 433 const char *getArgCStr(unsigned Idx) const { 434 assert(getArgKind(Idx) == Diagnostic::ak_c_string && 435 "invalid argument accessor!"); 436 return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]); 437 } 438 439 /// getArgSInt - Return the specified signed integer argument. 440 int getArgSInt(unsigned Idx) const { 441 assert(getArgKind(Idx) == Diagnostic::ak_sint && 442 "invalid argument accessor!"); 443 return (int)DiagObj->DiagArgumentsVal[Idx]; 444 } 445 446 /// getArgUInt - Return the specified unsigned integer argument. 447 unsigned getArgUInt(unsigned Idx) const { 448 assert(getArgKind(Idx) == Diagnostic::ak_uint && 449 "invalid argument accessor!"); 450 return (unsigned)DiagObj->DiagArgumentsVal[Idx]; 451 } 452 453 /// getArgIdentifier - Return the specified IdentifierInfo argument. 454 const IdentifierInfo *getArgIdentifier(unsigned Idx) const { 455 assert(getArgKind(Idx) == Diagnostic::ak_identifierinfo && 456 "invalid argument accessor!"); 457 return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]); 458 } 459 460 /// getRawArg - Return the specified non-string argument in an opaque form. 461 intptr_t getRawArg(unsigned Idx) const { 462 assert(getArgKind(Idx) != Diagnostic::ak_std_string && 463 "invalid argument accessor!"); 464 return DiagObj->DiagArgumentsVal[Idx]; 465 } 466 467 468 /// getNumRanges - Return the number of source ranges associated with this 469 /// diagnostic. 470 unsigned getNumRanges() const { 471 return DiagObj->NumDiagRanges; 472 } 473 474 const SourceRange &getRange(unsigned Idx) const { 475 assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); 476 return *DiagObj->DiagRanges[Idx]; 477 } 478 479 480 /// FormatDiagnostic - Format this diagnostic into a string, substituting the 481 /// formal arguments into the %0 slots. The result is appended onto the Str 482 /// array. 483 void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const; 484}; 485 486 487/// DiagnosticClient - This is an abstract interface implemented by clients of 488/// the front-end, which formats and prints fully processed diagnostics. 489class DiagnosticClient { 490public: 491 virtual ~DiagnosticClient(); 492 493 /// IncludeInDiagnosticCounts - This method (whose default implementation 494 /// returns true) indicates whether the diagnostics handled by this 495 /// DiagnosticClient should be included in the number of diagnostics 496 /// reported by Diagnostic. 497 virtual bool IncludeInDiagnosticCounts() const; 498 499 /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or 500 /// capturing it to a log as needed. 501 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, 502 const DiagnosticInfo &Info) = 0; 503}; 504 505} // end namespace clang 506 507#endif 508