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