Diagnostic.h revision 520987fc4e5e60c80bcce613b0f8813ffb2fdca0
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 /// DiagArguments - The values for the various substitution positions. It 182 /// currently only support 10 arguments (%0-%9). 183 const std::string *DiagArguments[10]; 184 /// DiagRanges - The list of ranges added to this diagnostic. It currently 185 /// only support 10 ranges, could easily be extended if needed. 186 const SourceRange *DiagRanges[10]; 187 188 /// NumDiagArgs - This is set to -1 when no diag is in flight. Otherwise it 189 /// is the number of entries in Arguments. 190 signed char NumDiagArgs; 191 /// NumRanges - This is the number of ranges in the DiagRanges array. 192 unsigned char NumDiagRanges; 193 194 /// ProcessDiag - This is the method used to report a diagnostic that is 195 /// finally fully formed. 196 void ProcessDiag(const DiagnosticInfo &Info); 197}; 198 199/// DiagnosticInfo - This is a little helper class used to produce diagnostics. 200/// This is constructed with an ID and location, and then has some number of 201/// arguments (for %0 substitution) and SourceRanges added to it with the 202/// overloaded operator<<. Once it is destroyed, it emits the diagnostic with 203/// the accumulated information. 204/// 205/// Note that many of these will be created as temporary objects (many call 206/// sites), so we want them to be small to reduce stack space usage etc. For 207/// this reason, we stick state in the Diagnostic class, see the comment there 208/// for more info. 209class DiagnosticInfo { 210 mutable Diagnostic *DiagObj; 211 FullSourceLoc Loc; 212 unsigned DiagID; 213 void operator=(const DiagnosticInfo&); // DO NOT IMPLEMENT 214public: 215 DiagnosticInfo(Diagnostic *diagObj, FullSourceLoc loc, unsigned diagID) : 216 DiagObj(diagObj), Loc(loc), DiagID(diagID) { 217 assert(DiagObj->NumDiagArgs == -1 && 218 "Multiple diagnostics in flight at once!"); 219 DiagObj->NumDiagArgs = DiagObj->NumDiagRanges = 0; 220 } 221 222 /// Copy constructor. When copied, this "takes" the diagnostic info from the 223 /// input and neuters it. 224 DiagnosticInfo(const DiagnosticInfo &D) { 225 DiagObj = D.DiagObj; 226 Loc = D.Loc; 227 DiagID = D.DiagID; 228 D.DiagObj = 0; 229 } 230 231 /// Destructor - The dtor emits the diagnostic. 232 ~DiagnosticInfo() { 233 // If DiagObj is null, then its soul was stolen by the copy ctor. 234 if (!DiagObj) return; 235 236 DiagObj->ProcessDiag(*this); 237 238 // This diagnostic is no longer in flight. 239 DiagObj->NumDiagArgs = -1; 240 } 241 242 const Diagnostic *getDiags() const { return DiagObj; } 243 unsigned getID() const { return DiagID; } 244 const FullSourceLoc &getLocation() const { return Loc; } 245 246 unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } 247 248 /// getArgStr - Return the provided argument string specified by Idx. 249 const std::string &getArgStr(unsigned Idx) const { 250 assert((signed char)Idx < DiagObj->NumDiagArgs && 251 "Argument out of range!"); 252 return *DiagObj->DiagArguments[Idx]; 253 } 254 255 /// getNumRanges - Return the number of source ranges associated with this 256 /// diagnostic. 257 unsigned getNumRanges() const { 258 return DiagObj->NumDiagRanges; 259 } 260 261 const SourceRange &getRange(unsigned Idx) const { 262 assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); 263 return *DiagObj->DiagRanges[Idx]; 264 } 265 266 DiagnosticInfo &operator<<(const std::string &S) { 267 assert((unsigned)DiagObj->NumDiagArgs < 268 sizeof(DiagObj->DiagArguments)/sizeof(DiagObj->DiagArguments[0]) && 269 "Too many arguments to diagnostic!"); 270 DiagObj->DiagArguments[DiagObj->NumDiagArgs++] = &S; 271 return *this; 272 } 273 274 DiagnosticInfo &operator<<(const SourceRange &R) { 275 assert((unsigned)DiagObj->NumDiagArgs < 276 sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && 277 "Too many arguments to diagnostic!"); 278 DiagObj->DiagRanges[DiagObj->NumDiagRanges++] = &R; 279 return *this; 280 } 281 282}; 283 284 285/// Report - Issue the message to the client. DiagID is a member of the 286/// diag::kind enum. This actually returns a new instance of DiagnosticInfo 287/// which emits the diagnostics (through ProcessDiag) when it is destroyed. 288inline DiagnosticInfo Diagnostic::Report(FullSourceLoc Pos, unsigned DiagID) { 289 DiagnosticInfo D(this, Pos, DiagID); 290 return D; 291} 292 293 294/// DiagnosticClient - This is an abstract interface implemented by clients of 295/// the front-end, which formats and prints fully processed diagnostics. 296class DiagnosticClient { 297protected: 298 std::string FormatDiagnostic(const DiagnosticInfo &Info); 299public: 300 virtual ~DiagnosticClient(); 301 302 /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or 303 /// capturing it to a log as needed. 304 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, 305 const DiagnosticInfo &Info) = 0; 306}; 307 308} // end namespace clang 309 310#endif 311