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