blob: d6c8797fc901f5f8158a34bbffce8f51657a5aa4 [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 "llvm/ADT/StringRef.h"
#include "llvm/Support/type_traits.h"
#include <string>
#include <vector>
#include <cassert>
namespace llvm {
template <typename T> class SmallVectorImpl;
class raw_ostream;
}
namespace clang {
class DeclContext;
class DiagnosticBuilder;
class DiagnosticClient;
class FileManager;
class IdentifierInfo;
class LangOptions;
class PartialDiagnostic;
class Preprocessor;
class SourceManager;
class SourceRange;
// Import the diagnostic enums themselves.
namespace diag {
// Start position for diagnostics.
enum {
DIAG_START_DRIVER = 300,
DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
DIAG_START_LEX = DIAG_START_FRONTEND + 100,
DIAG_START_PARSE = DIAG_START_LEX + 300,
DIAG_START_AST = DIAG_START_PARSE + 300,
DIAG_START_SEMA = DIAG_START_AST + 100,
DIAG_START_ANALYSIS = DIAG_START_SEMA + 1500,
DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
};
class CustomDiagInfo;
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
typedef unsigned kind;
// Get typedefs for common diagnostics.
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
#include "clang/Basic/DiagnosticCommonKinds.inc"
NUM_BUILTIN_COMMON_DIAGNOSTICS
#undef DIAG
};
/// 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). It allows clients to map errors to
/// MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop emitting diagnostics after this
/// one).
enum Mapping {
// NOTE: 0 means "uncomputed".
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.
MAP_FATAL = 4, //< Map this diagnostic to a fatal error.
/// Map this diagnostic to "warning", but make it immune to -Werror. This
/// happens when you specify -Wno-error=foo.
MAP_WARNING_NO_WERROR = 5,
/// Map this diagnostic to "error", but make it immune to -Wfatal-errors.
/// This happens for -Wno-fatal-errors=foo.
MAP_ERROR_NO_WFATAL = 6
};
}
/// \brief Annotates a diagnostic with some code that should be
/// inserted, removed, or replaced to fix the problem.
///
/// This kind of hint should be used when we are certain that the
/// introduction, removal, or modification of a particular (small!)
/// amount of code will correct a compilation error. The compiler
/// should also provide full recovery from such errors, such that
/// suppressing the diagnostic output can still result in successful
/// compilation.
class CodeModificationHint {
public:
/// \brief Tokens that should be removed to correct the error.
SourceRange RemoveRange;
/// \brief The location at which we should insert code to correct
/// the error.
SourceLocation InsertionLoc;
/// \brief The actual code to insert at the insertion location, as a
/// string.
std::string CodeToInsert;
/// \brief Empty code modification hint, indicating that no code
/// modification is known.
CodeModificationHint() : RemoveRange(), InsertionLoc() { }
bool isNull() const {
return !RemoveRange.isValid() && !InsertionLoc.isValid();
}
/// \brief Create a code modification hint that inserts the given
/// code string at a specific location.
static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
llvm::StringRef Code) {
CodeModificationHint Hint;
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert = Code;
return Hint;
}
/// \brief Create a code modification hint that removes the given
/// source range.
static CodeModificationHint CreateRemoval(SourceRange RemoveRange) {
CodeModificationHint Hint;
Hint.RemoveRange = RemoveRange;
return Hint;
}
/// \brief Create a code modification hint that replaces the given
/// source range with the given code string.
static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
llvm::StringRef Code) {
CodeModificationHint Hint;
Hint.RemoveRange = RemoveRange;
Hint.InsertionLoc = RemoveRange.getBegin();
Hint.CodeToInsert = Code;
return Hint;
}
};
/// 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
};
/// ExtensionHandling - How do we handle otherwise-unmapped extension? This
/// is controlled by -pedantic and -pedantic-errors.
enum ExtensionHandling {
Ext_Ignore, Ext_Warn, Ext_Error
};
enum ArgumentKind {
ak_std_string, // std::string
ak_c_string, // const char *
ak_sint, // int
ak_uint, // unsigned
ak_identifierinfo, // IdentifierInfo
ak_qualtype, // QualType
ak_declarationname, // DeclarationName
ak_nameddecl, // NamedDecl *
ak_nestednamespec, // NestedNameSpecifier *
ak_declcontext // DeclContext *
};
/// ArgumentValue - This typedef represents on argument value, which is a
/// union discriminated by ArgumentKind, with a value.
typedef std::pair<ArgumentKind, intptr_t> ArgumentValue;
private:
unsigned char AllExtensionsSilenced; // Used by __extension__
bool IgnoreAllWarnings; // Ignore all warnings: -w
bool WarningsAsErrors; // Treat warnings like errors:
bool ErrorsAsFatal; // Treat errors like fatal errors.
bool SuppressSystemWarnings; // Suppress warnings in system headers.
bool SuppressAllDiagnostics; // Suppress all diagnostics.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
DiagnosticClient *Client;
/// DiagMappings - Mapping information for diagnostics. Mapping info is
/// packed into four bits per diagnostic. The low three bits are the mapping
/// (an instance of diag::Mapping), or zero if unset. The high bit is set
/// when the mapping was established as a user mapping. If the high bit is
/// clear, then the low bits are set to the default value, and should be
/// mapped with -pedantic, -Werror, etc.
typedef std::vector<unsigned char> DiagMappings;
mutable std::vector<DiagMappings> DiagMappingsStack;
/// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or
/// fatal error is emitted, and is sticky.
bool ErrorOccurred;
bool FatalErrorOccurred;
/// LastDiagLevel - This is the level of the last diagnostic emitted. This is
/// used to emit continuation diagnostics with the same level as the
/// diagnostic that they follow.
Diagnostic::Level LastDiagLevel;
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;
/// ArgToStringFn - A function pointer that converts an opaque diagnostic
/// argument to a strings. This takes the modifiers and argument that was
/// present in the diagnostic.
///
/// The PrevArgs array (whose length is NumPrevArgs) indicates the previous
/// arguments formatted for this diagnostic. Implementations of this function
/// can use this information to avoid redundancy across arguments.
///
/// This is a hack to avoid a layering violation between libbasic and libsema.
typedef void (*ArgToStringFnTy)(ArgumentKind Kind, intptr_t Val,
const char *Modifier, unsigned ModifierLen,
const char *Argument, unsigned ArgumentLen,
const ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
llvm::SmallVectorImpl<char> &Output,
void *Cookie);
void *ArgToStringCookie;
ArgToStringFnTy ArgToStringFn;
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; }
/// pushMappings - Copies the current DiagMappings and pushes the new copy
/// onto the top of the stack.
void pushMappings();
/// popMappings - Pops the current DiagMappings off the top of the stack
/// causing the new top of the stack to be the active mappings. Returns
/// true if the pop happens, false if there is only one DiagMapping on the
/// stack.
bool popMappings();
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; }
/// setErrorsAsFatal - When set to true, any error reported is made a
/// fatal error.
void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; }
bool getErrorsAsFatal() const { return ErrorsAsFatal; }
/// setSuppressSystemWarnings - When set to true mask warnings that
/// come from system headers.
void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
/// \brief Suppress all diagnostics, to silence the front end when we
/// know that we don't want any more diagnostics to be passed along to the
/// client
void setSuppressAllDiagnostics(bool Val = true) {
SuppressAllDiagnostics = Val;
}
bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; }
/// \brief Pretend that the last diagnostic issued was ignored. This can
/// be used by clients who suppress diagnostics themselves.
void setLastDiagnosticIgnored() {
LastDiagLevel = Ignored;
}
/// setExtensionHandlingBehavior - This controls whether otherwise-unmapped
/// extension diagnostics are mapped onto ignore/warning/error. This
/// corresponds to the GCC -pedantic and -pedantic-errors option.
void setExtensionHandlingBehavior(ExtensionHandling H) {
ExtBehavior = H;
}
/// AllExtensionsSilenced - This is a counter bumped when an __extension__
/// block is encountered. When non-zero, all extension diagnostics are
/// entirely silenced, no matter how they are mapped.
void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; }
void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; }
bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; }
/// setDiagnosticMapping - This allows the client to specify that certain
/// warnings are ignored. Notes can never be mapped, errors can only be
/// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily.
void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) {
assert(Diag < diag::DIAG_UPPER_LIMIT &&
"Can only map builtin diagnostics");
assert((isBuiltinWarningOrExtension(Diag) || Map == diag::MAP_FATAL) &&
"Cannot map errors!");
setDiagnosticMappingInternal(Diag, Map, true);
}
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
/// "unknown-pragmas" to have the specified mapping. This returns true and
/// ignores the request if "Group" was unknown, false otherwise.
bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map);
bool hasErrorOccurred() const { return ErrorOccurred; }
bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
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, llvm::StringRef Message);
/// ConvertArgToString - This method converts a diagnostic argument (as an
/// intptr_t) into the string that represents it.
void ConvertArgToString(ArgumentKind Kind, intptr_t Val,
const char *Modifier, unsigned ModLen,
const char *Argument, unsigned ArgLen,
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
llvm::SmallVectorImpl<char> &Output) const {
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
PrevArgs, NumPrevArgs, Output, ArgToStringCookie);
}
void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) {
ArgToStringFn = Fn;
ArgToStringCookie = Cookie;
}
//===--------------------------------------------------------------------===//
// Diagnostic classification and reporting interfaces.
//
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
const char *getDescription(unsigned DiagID) const;
/// isNoteWarningOrExtension - Return true if the unmapped diagnostic
/// level of the specified diagnostic ID is a Warning or Extension.
/// This only works on builtin diagnostics, not custom ones, and is not legal to
/// call on NOTEs.
static bool isBuiltinWarningOrExtension(unsigned DiagID);
/// \brief Determine whether the given built-in diagnostic ID is a
/// Note.
static bool isBuiltinNote(unsigned DiagID);
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
/// ID is for an extension of some sort.
///
static bool isBuiltinExtensionDiag(unsigned DiagID);
/// getWarningOptionForDiag - Return the lowest-level warning option that
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
/// the diagnostic, this returns null.
static const char *getWarningOptionForDiag(unsigned DiagID);
/// \brief Determines whether the given built-in diagnostic ID is
/// for an error that is suppressed if it occurs during C++ template
/// argument deduction.
///
/// When an error is suppressed due to SFINAE, the template argument
/// deduction fails but no diagnostic is emitted. Certain classes of
/// errors, such as those errors that involve C++ access control,
/// are not SFINAE errors.
static bool isBuiltinSFINAEDiag(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. @c DiagID is a member of the
/// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder
/// which emits the diagnostics (through @c ProcessDiag) when it is destroyed.
/// @c Pos represents the source location associated with the diagnostic,
/// which can be an invalid location if no position information is available.
inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID);
inline DiagnosticBuilder Report(unsigned DiagID);
/// \brief Clear out the current diagnostic.
void Clear() { CurDiagID = ~0U; }
private:
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
/// specified builtin diagnostic. This returns the high bit encoding, or zero
/// if the field is completely uninitialized.
unsigned getDiagnosticMappingInfo(diag::kind Diag) const {
const DiagMappings &currentMappings = DiagMappingsStack.back();
return (diag::Mapping)((currentMappings[Diag/2] >> (Diag & 1)*4) & 15);
}
void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map,
bool isUser) const {
if (isUser) Map |= 8; // Set the high bit for user mappings.
unsigned char &Slot = DiagMappingsStack.back()[DiagId/2];
unsigned Shift = (DiagId & 1)*4;
Slot &= ~(15 << Shift);
Slot |= Map << Shift;
}
/// getDiagnosticLevel - This is an internal implementation helper used when
/// DiagClass is already known.
Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const;
// This is private state used by DiagnosticBuilder. We put it here instead of
// in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight
// 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 DiagnosticBuilder;
friend class DiagnosticInfo;
/// CurDiagLoc - This is the location of the current diagnostic that is in
/// flight.
FullSourceLoc CurDiagLoc;
/// CurDiagID - This is the ID of the current diagnostic that is in flight.
/// This is set to ~0U when there is no diagnostic in flight.
unsigned CurDiagID;
enum {
/// MaxArguments - The maximum number of arguments we can hold. We currently
/// only support up to 10 arguments (%0-%9). A single diagnostic with more
/// than that almost certainly has to be simplified anyway.
MaxArguments = 10
};
/// NumDiagArgs - This contains the number of entries in Arguments.
signed char NumDiagArgs;
/// NumRanges - This is the number of ranges in the DiagRanges array.
unsigned char NumDiagRanges;
/// \brief The number of code modifications hints in the
/// CodeModificationHints array.
unsigned char NumCodeModificationHints;
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
/// is in DiagArgumentsStr or in DiagArguments.
unsigned char DiagArgumentsKind[MaxArguments];
/// DiagArgumentsStr - This holds the values of each string argument for the
/// current diagnostic. This value is only used when the corresponding
/// ArgumentKind is ak_std_string.
std::string DiagArgumentsStr[MaxArguments];
/// DiagArgumentsVal - The values for the various substitution positions. This
/// is used when the argument is not an std::string. The specific value is
/// mangled into an intptr_t and the intepretation depends on exactly what
/// sort of argument kind it is.
intptr_t DiagArgumentsVal[MaxArguments];
/// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed.
SourceRange DiagRanges[10];
enum { MaxCodeModificationHints = 3 };
/// CodeModificationHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
///
/// \returns true if the diagnostic was emitted, false if it was
/// suppressed.
bool ProcessDiag();
};
//===----------------------------------------------------------------------===//
// DiagnosticBuilder
//===----------------------------------------------------------------------===//
/// DiagnosticBuilder - This is a little helper class used to produce
/// diagnostics. This is constructed by the Diagnostic::Report method, and
/// allows insertion of extra information (arguments and source ranges) into the
/// currently "in flight" diagnostic. When the temporary for the builder is
/// destroyed, the diagnostic is issued.
///
/// Note that many of these will be created as temporary objects (many call
/// sites), so we want them to be small and we never want their address taken.
/// This ensures that compilers with somewhat reasonable optimizers will promote
/// the common fields to registers, eliminating increments of the NumArgs field,
/// for example.
class DiagnosticBuilder {
mutable Diagnostic *DiagObj;
mutable unsigned NumArgs, NumRanges, NumCodeModificationHints;
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
friend class Diagnostic;
explicit DiagnosticBuilder(Diagnostic *diagObj)
: DiagObj(diagObj), NumArgs(0), NumRanges(0),
NumCodeModificationHints(0) {}
public:
/// Copy constructor. When copied, this "takes" the diagnostic info from the
/// input and neuters it.
DiagnosticBuilder(const DiagnosticBuilder &D) {
DiagObj = D.DiagObj;
D.DiagObj = 0;
NumArgs = D.NumArgs;
NumRanges = D.NumRanges;
NumCodeModificationHints = D.NumCodeModificationHints;
}
/// \brief Simple enumeration value used to give a name to the
/// suppress-diagnostic constructor.
enum SuppressKind { Suppress };
/// \brief Create an empty DiagnosticBuilder object that represents
/// no actual diagnostic.
explicit DiagnosticBuilder(SuppressKind)
: DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { }
/// \brief Force the diagnostic builder to emit the diagnostic now.
///
/// Once this function has been called, the DiagnosticBuilder object
/// should not be used again before it is destroyed.
///
/// \returns true if a diagnostic was emitted, false if the
/// diagnostic was suppressed.
bool Emit() {
// If DiagObj is null, then its soul was stolen by the copy ctor
// or the user called Emit().
if (DiagObj == 0) return false;
// When emitting diagnostics, we set the final argument count into
// the Diagnostic object.
DiagObj->NumDiagArgs = NumArgs;
DiagObj->NumDiagRanges = NumRanges;
DiagObj->NumCodeModificationHints = NumCodeModificationHints;
// Process the diagnostic, sending the accumulated information to the
// DiagnosticClient.
bool Emitted = DiagObj->ProcessDiag();
// Clear out the current diagnostic object.
DiagObj->Clear();
// This diagnostic is dead.
DiagObj = 0;
return Emitted;
}
/// Destructor - The dtor emits the diagnostic if it hasn't already
/// been emitted.
~DiagnosticBuilder() { Emit(); }
/// isActive - Determine whether this diagnostic is still active.
bool isActive() const { return DiagObj != 0; }
/// Operator bool: conversion of DiagnosticBuilder to bool always returns
/// true. This allows is to be used in boolean error contexts like:
/// return Diag(...);
operator bool() const { return true; }
void AddString(llvm::StringRef S) const {
assert(NumArgs < Diagnostic::MaxArguments &&
"Too many arguments to diagnostic!");
if (DiagObj) {
DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string;
DiagObj->DiagArgumentsStr[NumArgs++] = S;
}
}
void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
assert(NumArgs < Diagnostic::MaxArguments &&
"Too many arguments to diagnostic!");
if (DiagObj) {
DiagObj->DiagArgumentsKind[NumArgs] = Kind;
DiagObj->DiagArgumentsVal[NumArgs++] = V;
}
}
void AddSourceRange(const SourceRange &R) const {
assert(NumRanges <
sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) &&
"Too many arguments to diagnostic!");
if (DiagObj)
DiagObj->DiagRanges[NumRanges++] = R;
}
void AddCodeModificationHint(const CodeModificationHint &Hint) const {
if (Hint.isNull())
return;
assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints &&
"Too many code modification hints!");
if (DiagObj)
DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint;
}
};
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
llvm::StringRef S) {
DB.AddString(S);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const char *Str) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str),
Diagnostic::ak_c_string);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) {
DB.AddTaggedVal(I, Diagnostic::ak_sint);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) {
DB.AddTaggedVal(I, Diagnostic::ak_sint);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
unsigned I) {
DB.AddTaggedVal(I, Diagnostic::ak_uint);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const IdentifierInfo *II) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(II),
Diagnostic::ak_identifierinfo);
return DB;
}
// Adds a DeclContext to the diagnostic. The enable_if template magic is here
// so that we only match those arguments that are (statically) DeclContexts;
// other arguments that derive from DeclContext (e.g., RecordDecls) will not
// match.
template<typename T>
inline
typename llvm::enable_if<llvm::is_same<T, DeclContext>,
const DiagnosticBuilder &>::type
operator<<(const DiagnosticBuilder &DB, T *DC) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
Diagnostic::ak_declcontext);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const SourceRange &R) {
DB.AddSourceRange(R);
return DB;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const CodeModificationHint &Hint) {
DB.AddCodeModificationHint(Hint);
return DB;
}
/// Report - Issue the message to the client. DiagID is a member of the
/// diag::kind enum. This actually returns a new instance of DiagnosticBuilder
/// which emits the diagnostics (through ProcessDiag) when it is destroyed.
inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned DiagID){
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
CurDiagLoc = Loc;
CurDiagID = DiagID;
return DiagnosticBuilder(this);
}
inline DiagnosticBuilder Diagnostic::Report(unsigned DiagID) {
return Report(FullSourceLoc(), DiagID);
}
//===----------------------------------------------------------------------===//
// DiagnosticInfo
//===----------------------------------------------------------------------===//
/// DiagnosticInfo - This is a little helper class (which is basically a smart
/// pointer that forward info from Diagnostic) that allows clients to enquire
/// about the currently in-flight diagnostic.
class DiagnosticInfo {
const Diagnostic *DiagObj;
public:
explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {}
const Diagnostic *getDiags() const { return DiagObj; }
unsigned getID() const { return DiagObj->CurDiagID; }
const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; }
unsigned getNumArgs() const { return DiagObj->NumDiagArgs; }
/// getArgKind - Return the kind of the specified index. Based on the kind
/// of argument, the accessors below can be used to get the value.
Diagnostic::ArgumentKind getArgKind(unsigned Idx) const {
assert(Idx < getNumArgs() && "Argument index out of range!");
return (Diagnostic::ArgumentKind)DiagObj->DiagArgumentsKind[Idx];
}
/// getArgStdStr - Return the provided argument string specified by Idx.
const std::string &getArgStdStr(unsigned Idx) const {
assert(getArgKind(Idx) == Diagnostic::ak_std_string &&
"invalid argument accessor!");
return DiagObj->DiagArgumentsStr[Idx];
}
/// getArgCStr - Return the specified C string argument.
const char *getArgCStr(unsigned Idx) const {
assert(getArgKind(Idx) == Diagnostic::ak_c_string &&
"invalid argument accessor!");
return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]);
}
/// getArgSInt - Return the specified signed integer argument.
int getArgSInt(unsigned Idx) const {
assert(getArgKind(Idx) == Diagnostic::ak_sint &&
"invalid argument accessor!");
return (int)DiagObj->DiagArgumentsVal[Idx];
}
/// getArgUInt - Return the specified unsigned integer argument.
unsigned getArgUInt(unsigned Idx) const {
assert(getArgKind(Idx) == Diagnostic::ak_uint &&
"invalid argument accessor!");
return (unsigned)DiagObj->DiagArgumentsVal[Idx];
}
/// getArgIdentifier - Return the specified IdentifierInfo argument.
const IdentifierInfo *getArgIdentifier(unsigned Idx) const {
assert(getArgKind(Idx) == Diagnostic::ak_identifierinfo &&
"invalid argument accessor!");
return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]);
}
/// getRawArg - Return the specified non-string argument in an opaque form.
intptr_t getRawArg(unsigned Idx) const {
assert(getArgKind(Idx) != Diagnostic::ak_std_string &&
"invalid argument accessor!");
return DiagObj->DiagArgumentsVal[Idx];
}
/// getNumRanges - Return the number of source ranges associated with this
/// diagnostic.
unsigned getNumRanges() const {
return DiagObj->NumDiagRanges;
}
SourceRange getRange(unsigned Idx) const {
assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!");
return DiagObj->DiagRanges[Idx];
}
unsigned getNumCodeModificationHints() const {
return DiagObj->NumCodeModificationHints;
}
const CodeModificationHint &getCodeModificationHint(unsigned Idx) const {
return DiagObj->CodeModificationHints[Idx];
}
const CodeModificationHint *getCodeModificationHints() const {
return DiagObj->NumCodeModificationHints?
&DiagObj->CodeModificationHints[0] : 0;
}
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
/// formal arguments into the %0 slots. The result is appended onto the Str
/// array.
void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const;
/// FormatDiagnostic - Format the given format-string into the
/// output buffer using the arguments stored in this diagnostic.
void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
llvm::SmallVectorImpl<char> &OutStr) const;
};
/**
* \brief Represents a diagnostic in a form that can be serialized and
* deserialized.
*/
class StoredDiagnostic {
Diagnostic::Level Level;
FullSourceLoc Loc;
std::string Message;
std::vector<SourceRange> Ranges;
std::vector<CodeModificationHint> FixIts;
public:
StoredDiagnostic();
StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info);
StoredDiagnostic(Diagnostic::Level Level, llvm::StringRef Message);
~StoredDiagnostic();
/// \brief Evaluates true when this object stores a diagnostic.
operator bool() const { return Message.size() > 0; }
Diagnostic::Level getLevel() const { return Level; }
const FullSourceLoc &getLocation() const { return Loc; }
llvm::StringRef getMessage() const { return Message; }
typedef std::vector<SourceRange>::const_iterator range_iterator;
range_iterator range_begin() const { return Ranges.begin(); }
range_iterator range_end() const { return Ranges.end(); }
unsigned range_size() const { return Ranges.size(); }
typedef std::vector<CodeModificationHint>::const_iterator fixit_iterator;
fixit_iterator fixit_begin() const { return FixIts.begin(); }
fixit_iterator fixit_end() const { return FixIts.end(); }
unsigned fixit_size() const { return FixIts.size(); }
/// Serialize - Serialize the given diagnostic (with its diagnostic
/// level) to the given stream. Serialization is a lossy operation,
/// since the specific diagnostic ID and any macro-instantiation
/// information is lost.
void Serialize(llvm::raw_ostream &OS) const;
/// Deserialize - Deserialize the first diagnostic within the memory
/// [Memory, MemoryEnd), producing a new diagnostic builder describing the
/// deserialized diagnostic. If the memory does not contain a
/// diagnostic, returns a diagnostic builder with no diagnostic ID.
static StoredDiagnostic Deserialize(FileManager &FM, SourceManager &SM,
const char *&Memory, const char *MemoryEnd);
};
/// DiagnosticClient - This is an abstract interface implemented by clients of
/// the front-end, which formats and prints fully processed diagnostics.
class DiagnosticClient {
public:
virtual ~DiagnosticClient();
/// BeginSourceFile - Callback to inform the diagnostic client that processing
/// of a source file is beginning.
///
/// Note that diagnostics may be emitted outside the processing of a source
/// file, for example during the parsing of command line options. However,
/// diagnostics with source range information are required to only be emitted
/// in between BeginSourceFile() and EndSourceFile().
///
/// \arg LO - The language options for the source file being processed.
/// \arg PP - The preprocessor object being used for the source; this optional
/// and may not be present, for example when processing AST source files.
virtual void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP = 0) {}
/// EndSourceFile - Callback to inform the diagnostic client that processing
/// of a source file has ended. The diagnostic client should assume that any
/// objects made available via \see BeginSourceFile() are inaccessible.
virtual void EndSourceFile() {}
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticClient should be included in the number of diagnostics reported
/// by Diagnostic.
virtual bool IncludeInDiagnosticCounts() const;
/// 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