blob: 566b5e3d480e4059b7532504c8c10c98f4a0d5d1 [file] [log] [blame]
//===--- Diagnostic.h - C Language Family Diagnostic Handling ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the Diagnostic-related interfaces.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_DIAGNOSTIC_H
#define LLVM_CLANG_DIAGNOSTIC_H
#include "clang/Basic/SourceLocation.h"
#include <string>
#include <cassert>
namespace clang {
class DiagnosticClient;
class SourceRange;
class SourceManager;
class DiagnosticInfo;
// Import the diagnostic enums themselves.
namespace diag {
class CustomDiagInfo;
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
enum kind {
#define DIAG(ENUM,FLAGS,DESC) ENUM,
#include "DiagnosticKinds.def"
NUM_BUILTIN_DIAGNOSTICS
};
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
/// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR
/// (emit as an error), or MAP_DEFAULT (handle the default way).
enum Mapping {
MAP_DEFAULT = 0, //< Do not map this diagnostic.
MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it.
MAP_WARNING = 2, //< Map this diagnostic to a warning.
MAP_ERROR = 3 //< Map this diagnostic to an error.
};
}
/// Diagnostic - This concrete class is used by the front-end to report
/// problems and issues. It massages the diagnostics (e.g. handling things like
/// "report warnings as errors" and passes them off to the DiagnosticClient for
/// reporting to the user.
class Diagnostic {
public:
/// Level - The level of the diagnostic, after it has been through mapping.
enum Level {
Ignored, Note, Warning, Error, Fatal
};
private:
bool IgnoreAllWarnings; // Ignore all warnings: -w
bool WarningsAsErrors; // Treat warnings like errors:
bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic.
bool ErrorOnExtensions; // Error on extensions: -pedantic-errors.
bool SuppressSystemWarnings;// Suppress warnings in system headers.
DiagnosticClient *Client;
/// DiagMappings - Mapping information for diagnostics. Mapping info is
/// packed into two bits per diagnostic.
unsigned char DiagMappings[(diag::NUM_BUILTIN_DIAGNOSTICS+3)/4];
/// ErrorOccurred - This is set to true when an error is emitted, and is
/// sticky.
bool ErrorOccurred;
unsigned NumDiagnostics; // Number of diagnostics reported
unsigned NumErrors; // Number of diagnostics that are errors
/// CustomDiagInfo - Information for uniquing and looking up custom diags.
diag::CustomDiagInfo *CustomDiagInfo;
public:
explicit Diagnostic(DiagnosticClient *client = 0);
~Diagnostic();
//===--------------------------------------------------------------------===//
// Diagnostic characterization methods, used by a client to customize how
//
DiagnosticClient *getClient() { return Client; };
const DiagnosticClient *getClient() const { return Client; };
void setClient(DiagnosticClient* client) { Client = client; }
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
/// ignored. If this and WarningsAsErrors are both set, then this one wins.
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
/// setWarningsAsErrors - When set to true, any warnings reported are issued
/// as errors.
void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
bool getWarningsAsErrors() const { return WarningsAsErrors; }
/// setWarnOnExtensions - When set to true, issue warnings on GCC extensions,
/// the equivalent of GCC's -pedantic.
void setWarnOnExtensions(bool Val) { WarnOnExtensions = Val; }
bool getWarnOnExtensions() const { return WarnOnExtensions; }
/// setErrorOnExtensions - When set to true issue errors for GCC extensions
/// instead of warnings. This is the equivalent to GCC's -pedantic-errors.
void setErrorOnExtensions(bool Val) { ErrorOnExtensions = Val; }
bool getErrorOnExtensions() const { return ErrorOnExtensions; }
/// setSuppressSystemWarnings - When set to true mask warnings that
/// come from system headers.
void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
/// setDiagnosticMapping - This allows the client to specify that certain
/// warnings are ignored. Only NOTEs, WARNINGs, and EXTENSIONs can be mapped.
void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) {
assert(Diag < diag::NUM_BUILTIN_DIAGNOSTICS &&
"Can only map builtin diagnostics");
assert(isBuiltinNoteWarningOrExtension(Diag) && "Cannot map errors!");
unsigned char &Slot = DiagMappings[Diag/4];
unsigned Bits = (Diag & 3)*2;
Slot &= ~(3 << Bits);
Slot |= Map << Bits;
}
/// getDiagnosticMapping - Return the mapping currently set for the specified
/// diagnostic.
diag::Mapping getDiagnosticMapping(diag::kind Diag) const {
return (diag::Mapping)((DiagMappings[Diag/4] >> (Diag & 3)*2) & 3);
}
bool hasErrorOccurred() const { return ErrorOccurred; }
unsigned getNumErrors() const { return NumErrors; }
unsigned getNumDiagnostics() const { return NumDiagnostics; }
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
/// and level. If this is the first request for this diagnosic, it is
/// registered and created, otherwise the existing ID is returned.
unsigned getCustomDiagID(Level L, const char *Message);
//===--------------------------------------------------------------------===//
// Diagnostic classification and reporting interfaces.
//
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
const char *getDescription(unsigned DiagID) const;
/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic
/// level of the specified diagnostic ID is a Note, Warning, or Extension.
/// Note that this only works on builtin diagnostics, not custom ones.
static bool isBuiltinNoteWarningOrExtension(unsigned DiagID);
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
/// object, classify the specified diagnostic ID into a Level, consumable by
/// the DiagnosticClient.
Level getDiagnosticLevel(unsigned DiagID) const;
/// Report - Issue the message to the client. DiagID is a member of the
/// diag::kind enum. This actually returns a new instance of DiagnosticInfo
/// which emits the diagnostics (through ProcessDiag) when it is destroyed.
inline DiagnosticInfo Report(FullSourceLoc Pos, unsigned DiagID);
private:
// This is private state used by DiagnosticInfo. We put it here instead of
// in DiagnosticInfo in order to keep DiagnosticInfo a small light-weight
// object. This implementation choice means that we can only have one
// diagnostic "in flight" at a time, but this seems to be a reasonable
// tradeoff to keep these objects small. Assertions verify that only one
// diagnostic is in flight at a time.
friend class DiagnosticInfo;
/// DiagArguments - The values for the various substitution positions. It
/// currently only support 10 arguments (%0-%9).
const std::string *DiagArguments[10];
/// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed.
const SourceRange *DiagRanges[10];
/// NumDiagArgs - This is set to -1 when no diag is in flight. Otherwise it
/// is the number of entries in Arguments.
signed char NumDiagArgs;
/// NumRanges - This is the number of ranges in the DiagRanges array.
unsigned char NumDiagRanges;
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
void ProcessDiag(const DiagnosticInfo &Info);
};
/// DiagnosticInfo - This is a little helper class used to produce diagnostics.
/// This is constructed with an ID and location, and then has some number of
/// arguments (for %0 substitution) and SourceRanges added to it with the
/// overloaded operator<<. Once it is destroyed, it emits the diagnostic with
/// the accumulated information.
///
/// Note that many of these will be created as temporary objects (many call
/// sites), so we want them to be small to reduce stack space usage etc. For
/// this reason, we stick state in the Diagnostic class, see the comment there
/// for more info.
class DiagnosticInfo {
Diagnostic *DiagObj;
FullSourceLoc Loc;
unsigned DiagID;
void operator=(const DiagnosticInfo&); // DO NOT IMPLEMENT
public:
DiagnosticInfo(Diagnostic *diagObj, FullSourceLoc loc, unsigned diagID) :
DiagObj(diagObj), Loc(loc), DiagID(diagID) {
assert(DiagObj->NumDiagArgs == -1 &&
"Multiple diagnostics in flight at once!");
DiagObj->NumDiagArgs = DiagObj->NumDiagRanges = 0;
}
/// Copy constructor. When copied, this "takes" the diagnostic info from the
/// input and neuters it.
DiagnosticInfo(DiagnosticInfo &D) {
DiagObj = D.DiagObj;
Loc = D.Loc;
DiagID = D.DiagID;
D.DiagObj = 0;
}
/// Destructor - The dtor emits the diagnostic.
~DiagnosticInfo() {
// If DiagObj is null, then its soul was stolen by the copy ctor.
if (!DiagObj) return;
DiagObj->ProcessDiag(*this);
// This diagnostic is no longer in flight.
DiagObj->NumDiagArgs = -1;
}
const Diagnostic *getDiags() const { return DiagObj; }
unsigned getID() const { return DiagID; }
const FullSourceLoc &getLocation() const { return Loc; }
unsigned getNumArgs() const { return DiagObj->NumDiagArgs; }
/// getArgStr - Return the provided argument string specified by Idx.
const std::string &getArgStr(unsigned Idx) const {
assert((signed char)Idx < DiagObj->NumDiagArgs &&
"Argument out of range!");
return *DiagObj->DiagArguments[Idx];
}
/// getNumRanges - Return the number of source ranges associated with this
/// diagnostic.
unsigned getNumRanges() const {
return DiagObj->NumDiagRanges;
}
const SourceRange &getRange(unsigned Idx) const {
assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!");
return *DiagObj->DiagRanges[Idx];
}
DiagnosticInfo &operator<<(const std::string &S) {
assert((unsigned)DiagObj->NumDiagArgs <
sizeof(DiagObj->DiagArguments)/sizeof(DiagObj->DiagArguments[0]) &&
"Too many arguments to diagnostic!");
DiagObj->DiagArguments[DiagObj->NumDiagArgs++] = &S;
return *this;
}
DiagnosticInfo &operator<<(const SourceRange &R) {
assert((unsigned)DiagObj->NumDiagArgs <
sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) &&
"Too many arguments to diagnostic!");
DiagObj->DiagRanges[DiagObj->NumDiagRanges++] = &R;
return *this;
}
};
/// Report - Issue the message to the client. DiagID is a member of the
/// diag::kind enum. This actually returns a new instance of DiagnosticInfo
/// which emits the diagnostics (through ProcessDiag) when it is destroyed.
inline DiagnosticInfo Diagnostic::Report(FullSourceLoc Pos, unsigned DiagID) {
DiagnosticInfo D(this, Pos, DiagID);
return D;
}
/// DiagnosticClient - This is an abstract interface implemented by clients of
/// the front-end, which formats and prints fully processed diagnostics.
class DiagnosticClient {
protected:
std::string FormatDiagnostic(const DiagnosticInfo &Info);
public:
virtual ~DiagnosticClient();
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
/// capturing it to a log as needed.
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) = 0;
};
} // end namespace clang
#endif