Diagnostic.h revision 73d2a1b05bb04ab0136af374ddaa5d4602d4c939
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 clang { 22 class DiagnosticClient; 23 class SourceRange; 24 class SourceManager; 25 class DiagnosticInfo; 26 27 // Import the diagnostic enums themselves. 28 namespace diag { 29 class CustomDiagInfo; 30 31 /// diag::kind - All of the diagnostics that can be emitted by the frontend. 32 enum kind { 33#define DIAG(ENUM,FLAGS,DESC) ENUM, 34#include "DiagnosticKinds.def" 35 NUM_BUILTIN_DIAGNOSTICS 36 }; 37 38 /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs 39 /// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR 40 /// (emit as an error), or MAP_DEFAULT (handle the default way). 41 enum Mapping { 42 MAP_DEFAULT = 0, //< Do not map this diagnostic. 43 MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it. 44 MAP_WARNING = 2, //< Map this diagnostic to a warning. 45 MAP_ERROR = 3 //< Map this diagnostic to an error. 46 }; 47 } 48 49/// Diagnostic - This concrete class is used by the front-end to report 50/// problems and issues. It massages the diagnostics (e.g. handling things like 51/// "report warnings as errors" and passes them off to the DiagnosticClient for 52/// reporting to the user. 53class Diagnostic { 54public: 55 /// Level - The level of the diagnostic, after it has been through mapping. 56 enum Level { 57 Ignored, Note, Warning, Error, Fatal 58 }; 59 60private: 61 bool IgnoreAllWarnings; // Ignore all warnings: -w 62 bool WarningsAsErrors; // Treat warnings like errors: 63 bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic. 64 bool ErrorOnExtensions; // Error on extensions: -pedantic-errors. 65 bool SuppressSystemWarnings;// Suppress warnings in system headers. 66 DiagnosticClient *Client; 67 68 /// DiagMappings - Mapping information for diagnostics. Mapping info is 69 /// packed into two bits per diagnostic. 70 unsigned char DiagMappings[(diag::NUM_BUILTIN_DIAGNOSTICS+3)/4]; 71 72 /// ErrorOccurred - This is set to true when an error is emitted, and is 73 /// sticky. 74 bool ErrorOccurred; 75 76 unsigned NumDiagnostics; // Number of diagnostics reported 77 unsigned NumErrors; // Number of diagnostics that are errors 78 79 /// CustomDiagInfo - Information for uniquing and looking up custom diags. 80 diag::CustomDiagInfo *CustomDiagInfo; 81 82public: 83 explicit Diagnostic(DiagnosticClient *client = 0); 84 ~Diagnostic(); 85 86 //===--------------------------------------------------------------------===// 87 // Diagnostic characterization methods, used by a client to customize how 88 // 89 90 DiagnosticClient *getClient() { return Client; }; 91 const DiagnosticClient *getClient() const { return Client; }; 92 93 void setClient(DiagnosticClient* client) { Client = client; } 94 95 /// setIgnoreAllWarnings - When set to true, any unmapped warnings are 96 /// ignored. If this and WarningsAsErrors are both set, then this one wins. 97 void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } 98 bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } 99 100 /// setWarningsAsErrors - When set to true, any warnings reported are issued 101 /// as errors. 102 void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } 103 bool getWarningsAsErrors() const { return WarningsAsErrors; } 104 105 /// setWarnOnExtensions - When set to true, issue warnings on GCC extensions, 106 /// the equivalent of GCC's -pedantic. 107 void setWarnOnExtensions(bool Val) { WarnOnExtensions = Val; } 108 bool getWarnOnExtensions() const { return WarnOnExtensions; } 109 110 /// setErrorOnExtensions - When set to true issue errors for GCC extensions 111 /// instead of warnings. This is the equivalent to GCC's -pedantic-errors. 112 void setErrorOnExtensions(bool Val) { ErrorOnExtensions = Val; } 113 bool getErrorOnExtensions() const { return ErrorOnExtensions; } 114 115 /// setSuppressSystemWarnings - When set to true mask warnings that 116 /// come from system headers. 117 void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } 118 bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } 119 120 /// setDiagnosticMapping - This allows the client to specify that certain 121 /// warnings are ignored. Only NOTEs, WARNINGs, and EXTENSIONs can be mapped. 122 void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) { 123 assert(Diag < diag::NUM_BUILTIN_DIAGNOSTICS && 124 "Can only map builtin diagnostics"); 125 assert(isBuiltinNoteWarningOrExtension(Diag) && "Cannot map errors!"); 126 unsigned char &Slot = DiagMappings[Diag/4]; 127 unsigned Bits = (Diag & 3)*2; 128 Slot &= ~(3 << Bits); 129 Slot |= Map << Bits; 130 } 131 132 /// getDiagnosticMapping - Return the mapping currently set for the specified 133 /// diagnostic. 134 diag::Mapping getDiagnosticMapping(diag::kind Diag) const { 135 return (diag::Mapping)((DiagMappings[Diag/4] >> (Diag & 3)*2) & 3); 136 } 137 138 bool hasErrorOccurred() const { return ErrorOccurred; } 139 140 unsigned getNumErrors() const { return NumErrors; } 141 unsigned getNumDiagnostics() const { return NumDiagnostics; } 142 143 /// getCustomDiagID - Return an ID for a diagnostic with the specified message 144 /// and level. If this is the first request for this diagnosic, it is 145 /// registered and created, otherwise the existing ID is returned. 146 unsigned getCustomDiagID(Level L, const char *Message); 147 148 //===--------------------------------------------------------------------===// 149 // Diagnostic classification and reporting interfaces. 150 // 151 152 /// getDescription - Given a diagnostic ID, return a description of the 153 /// issue. 154 const char *getDescription(unsigned DiagID) const; 155 156 /// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic 157 /// level of the specified diagnostic ID is a Note, Warning, or Extension. 158 /// Note that this only works on builtin diagnostics, not custom ones. 159 static bool isBuiltinNoteWarningOrExtension(unsigned DiagID); 160 161 /// getDiagnosticLevel - Based on the way the client configured the Diagnostic 162 /// object, classify the specified diagnostic ID into a Level, consumable by 163 /// the DiagnosticClient. 164 Level getDiagnosticLevel(unsigned DiagID) const; 165 166 167 /// Report - Issue the message to the client. DiagID is a member of the 168 /// diag::kind enum. This actually returns a new instance of DiagnosticInfo 169 /// which emits the diagnostics (through ProcessDiag) when it is destroyed. 170 inline DiagnosticInfo Report(FullSourceLoc Pos, unsigned DiagID); 171 172private: 173 // This is private state used by DiagnosticInfo. We put it here instead of 174 // in DiagnosticInfo in order to keep DiagnosticInfo a small light-weight 175 // object. This implementation choice means that we can only have one 176 // diagnostic "in flight" at a time, but this seems to be a reasonable 177 // tradeoff to keep these objects small. Assertions verify that only one 178 // diagnostic is in flight at a time. 179 friend class DiagnosticInfo; 180 181 enum { 182 /// MaxArguments - The maximum number of arguments we can hold. We currently 183 /// only support up to 10 arguments (%0-%9). A single diagnostic with more 184 /// than that almost certainly has to be simplified anyway. 185 MaxArguments = 10 186 }; 187 188 /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum 189 /// values, with one for each argument. This specifies whether the argument 190 /// is in DiagArgumentsStr or in DiagArguments. 191 unsigned char DiagArgumentsKind[MaxArguments]; 192 193 /// DiagArgumentsStr - This holds the values of each string argument for the 194 /// current diagnostic. This value is only used when the corresponding 195 /// ArgumentKind is ak_std_string. 196 std::string DiagArgumentsStr[MaxArguments]; 197 198 /// DiagArgumentsVal - The values for the various substitution positions. This 199 /// is used when the argument is not an std::string. The specific value is 200 /// mangled into an intptr_t and the intepretation depends on exactly what 201 /// sort of argument kind it is. 202 intptr_t DiagArgumentsVal[MaxArguments]; 203 204 /// DiagRanges - The list of ranges added to this diagnostic. It currently 205 /// only support 10 ranges, could easily be extended if needed. 206 const SourceRange *DiagRanges[10]; 207 208 /// NumDiagArgs - This is set to -1 when no diag is in flight. Otherwise it 209 /// is the number of entries in Arguments. 210 signed char NumDiagArgs; 211 /// NumRanges - This is the number of ranges in the DiagRanges array. 212 unsigned char NumDiagRanges; 213 214 /// ProcessDiag - This is the method used to report a diagnostic that is 215 /// finally fully formed. 216 void ProcessDiag(const DiagnosticInfo &Info); 217}; 218 219/// DiagnosticInfo - This is a little helper class used to produce diagnostics. 220/// This is constructed with an ID and location, and then has some number of 221/// arguments (for %0 substitution) and SourceRanges added to it with the 222/// overloaded operator<<. Once it is destroyed, it emits the diagnostic with 223/// the accumulated information. 224/// 225/// Note that many of these will be created as temporary objects (many call 226/// sites), so we want them to be small to reduce stack space usage etc. For 227/// this reason, we stick state in the Diagnostic class, see the comment there 228/// for more info. 229class DiagnosticInfo { 230 mutable Diagnostic *DiagObj; 231 FullSourceLoc Loc; 232 unsigned DiagID; 233 void operator=(const DiagnosticInfo&); // DO NOT IMPLEMENT 234public: 235 enum ArgumentKind { 236 ak_std_string, // std::string 237 ak_c_string // const char * 238 }; 239 240 241 DiagnosticInfo(Diagnostic *diagObj, FullSourceLoc loc, unsigned diagID) : 242 DiagObj(diagObj), Loc(loc), DiagID(diagID) { 243 if (DiagObj == 0) return; 244 assert(DiagObj->NumDiagArgs == -1 && 245 "Multiple diagnostics in flight at once!"); 246 DiagObj->NumDiagArgs = DiagObj->NumDiagRanges = 0; 247 } 248 249 /// Copy constructor. When copied, this "takes" the diagnostic info from the 250 /// input and neuters it. 251 DiagnosticInfo(const DiagnosticInfo &D) { 252 DiagObj = D.DiagObj; 253 Loc = D.Loc; 254 DiagID = D.DiagID; 255 D.DiagObj = 0; 256 } 257 258 /// Destructor - The dtor emits the diagnostic. 259 ~DiagnosticInfo() { 260 // If DiagObj is null, then its soul was stolen by the copy ctor. 261 if (!DiagObj) return; 262 263 DiagObj->ProcessDiag(*this); 264 265 // This diagnostic is no longer in flight. 266 DiagObj->NumDiagArgs = -1; 267 } 268 269 const Diagnostic *getDiags() const { return DiagObj; } 270 unsigned getID() const { return DiagID; } 271 const FullSourceLoc &getLocation() const { return Loc; } 272 273 /// Operator bool: conversion of DiagnosticInfo to bool always returns true. 274 /// This allows is to be used in boolean error contexts like: 275 /// return Diag(...); 276 operator bool() const { return true; } 277 278 unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } 279 280 281 /// getArgKind - Return the kind of the specified index. Based on the kind 282 /// of argument, the accessors below can be used to get the value. 283 ArgumentKind getArgKind(unsigned Idx) const { 284 assert((signed char)Idx < DiagObj->NumDiagArgs && 285 "Argument index out of range!"); 286 return (ArgumentKind)DiagObj->DiagArgumentsKind[Idx]; 287 } 288 289 /// getArgStdStr - Return the provided argument string specified by Idx. 290 const std::string &getArgStdStr(unsigned Idx) const { 291 assert(getArgKind(Idx) == ak_std_string && "invalid argument accessor!"); 292 return DiagObj->DiagArgumentsStr[Idx]; 293 } 294 295 /// getArgCStr - Return the specified C string argument. 296 const char *getArgCStr(unsigned Idx) const { 297 assert(getArgKind(Idx) == ak_c_string && "invalid argument accessor!"); 298 return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]); 299 } 300 301 /// getNumRanges - Return the number of source ranges associated with this 302 /// diagnostic. 303 unsigned getNumRanges() const { 304 return DiagObj->NumDiagRanges; 305 } 306 307 const SourceRange &getRange(unsigned Idx) const { 308 assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); 309 return *DiagObj->DiagRanges[Idx]; 310 } 311 312 DiagnosticInfo &operator<<(const std::string &S) { 313 assert((unsigned)DiagObj->NumDiagArgs < Diagnostic::MaxArguments && 314 "Too many arguments to diagnostic!"); 315 DiagObj->DiagArgumentsKind[DiagObj->NumDiagArgs] = ak_std_string; 316 DiagObj->DiagArgumentsStr[DiagObj->NumDiagArgs++] = S; 317 return *this; 318 } 319 320 DiagnosticInfo &operator<<(const char *Str) { 321 assert((unsigned)DiagObj->NumDiagArgs < Diagnostic::MaxArguments && 322 "Too many arguments to diagnostic!"); 323 DiagObj->DiagArgumentsKind[DiagObj->NumDiagArgs] = ak_c_string; 324 DiagObj->DiagArgumentsVal[DiagObj->NumDiagArgs++] = 325 reinterpret_cast<intptr_t>(Str); 326 return *this; 327 } 328 329 DiagnosticInfo &operator<<(const SourceRange &R) { 330 assert((unsigned)DiagObj->NumDiagArgs < 331 sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && 332 "Too many arguments to diagnostic!"); 333 DiagObj->DiagRanges[DiagObj->NumDiagRanges++] = &R; 334 return *this; 335 } 336 337}; 338 339 340/// Report - Issue the message to the client. DiagID is a member of the 341/// diag::kind enum. This actually returns a new instance of DiagnosticInfo 342/// which emits the diagnostics (through ProcessDiag) when it is destroyed. 343inline DiagnosticInfo Diagnostic::Report(FullSourceLoc Pos, unsigned DiagID) { 344 DiagnosticInfo D(this, Pos, DiagID); 345 return D; 346} 347 348 349/// DiagnosticClient - This is an abstract interface implemented by clients of 350/// the front-end, which formats and prints fully processed diagnostics. 351class DiagnosticClient { 352protected: 353 std::string FormatDiagnostic(const DiagnosticInfo &Info); 354public: 355 virtual ~DiagnosticClient(); 356 357 /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or 358 /// capturing it to a log as needed. 359 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, 360 const DiagnosticInfo &Info) = 0; 361}; 362 363} // end namespace clang 364 365#endif 366