aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Basic/Diagnostic.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Basic/Diagnostic.h')
-rw-r--r--include/clang/Basic/Diagnostic.h194
1 files changed, 122 insertions, 72 deletions
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 207710bdff31..380192e9dae6 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -15,7 +15,9 @@
#define LLVM_CLANG_DIAGNOSTIC_H
#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/type_traits.h"
#include <string>
+#include <vector>
#include <cassert>
namespace llvm {
@@ -23,12 +25,14 @@ namespace llvm {
}
namespace clang {
- class DiagnosticClient;
- class SourceRange;
+ class DeclContext;
class DiagnosticBuilder;
+ class DiagnosticClient;
class IdentifierInfo;
class LangOptions;
-
+ class PartialDiagnostic;
+ class SourceRange;
+
// Import the diagnostic enums themselves.
namespace diag {
// Start position for diagnostics.
@@ -44,7 +48,7 @@ namespace clang {
};
class CustomDiagInfo;
-
+
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
typedef unsigned kind;
@@ -55,7 +59,7 @@ namespace clang {
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
@@ -67,13 +71,13 @@ namespace clang {
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
};
}
-
+
/// \brief Annotates a diagnostic with some code that should be
/// inserted, removed, or replaced to fix the problem.
///
@@ -102,7 +106,7 @@ public:
/// \brief Create a code modification hint that inserts the given
/// code string at a specific location.
- static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
+ static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
const std::string &Code) {
CodeModificationHint Hint;
Hint.InsertionLoc = InsertionLoc;
@@ -120,7 +124,7 @@ public:
/// \brief Create a code modification hint that replaces the given
/// source range with the given code string.
- static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
+ static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
const std::string &Code) {
CodeModificationHint Hint;
Hint.RemoveRange = RemoveRange;
@@ -140,13 +144,13 @@ public:
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 *
@@ -155,14 +159,17 @@ public:
ak_identifierinfo, // IdentifierInfo
ak_qualtype, // QualType
ak_declarationname, // DeclarationName
- ak_nameddecl // NamedDecl *
+ ak_nameddecl, // NamedDecl *
+ ak_nestednamespec, // NestedNameSpecifier *
+ ak_declcontext // DeclContext *
};
-private:
+private:
unsigned char AllExtensionsSilenced; // Used by __extension__
bool IgnoreAllWarnings; // Ignore all warnings: -w
- bool WarningsAsErrors; // Treat warnings like errors:
+ bool WarningsAsErrors; // Treat warnings like errors:
bool SuppressSystemWarnings; // Suppress warnings in system headers.
+ bool SuppressAllDiagnostics; // Suppress all diagnostics.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
DiagnosticClient *Client;
@@ -172,13 +179,15 @@ private:
/// 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.
- mutable unsigned char DiagMappings[diag::DIAG_UPPER_LIMIT/2];
-
+
+ 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.
@@ -204,44 +213,70 @@ private:
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; }
-
+
/// 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.
@@ -252,7 +287,7 @@ public:
"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.
@@ -263,13 +298,13 @@ public:
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);
-
-
+
+
/// ConvertArgToString - This method converts a diagnostic argument (as an
/// intptr_t) into the string that represents it.
void ConvertArgToString(ArgumentKind Kind, intptr_t Val,
@@ -279,12 +314,12 @@ public:
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output,
ArgToStringCookie);
}
-
+
void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) {
ArgToStringFn = Fn;
ArgToStringCookie = Cookie;
}
-
+
//===--------------------------------------------------------------------===//
// Diagnostic classification and reporting interfaces.
//
@@ -292,7 +327,7 @@ public:
/// 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
@@ -302,12 +337,12 @@ public:
/// \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.
@@ -326,8 +361,8 @@ public:
/// 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;
-
+ 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.
@@ -337,24 +372,25 @@ public:
/// \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 {
- return (diag::Mapping)((DiagMappings[Diag/2] >> (Diag & 1)*4) & 15);
+ 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 = DiagMappings[DiagId/2];
+ 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;
@@ -371,7 +407,7 @@ private:
/// 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;
@@ -382,7 +418,7 @@ private:
/// 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.
@@ -395,7 +431,7 @@ private:
/// 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.
@@ -406,11 +442,11 @@ private:
/// 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.
const SourceRange *DiagRanges[10];
-
+
enum { MaxCodeModificationHints = 3 };
/// CodeModificationHints - If valid, provides a hint with some code
@@ -443,14 +479,14 @@ private:
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),
+ : DiagObj(diagObj), NumArgs(0), NumRanges(0),
NumCodeModificationHints(0) {}
-public:
+public:
/// Copy constructor. When copied, this "takes" the diagnostic info from the
/// input and neuters it.
DiagnosticBuilder(const DiagnosticBuilder &D) {
@@ -467,7 +503,7 @@ public:
/// \brief Create an empty DiagnosticBuilder object that represents
/// no actual diagnostic.
- explicit DiagnosticBuilder(SuppressKind)
+ explicit DiagnosticBuilder(SuppressKind)
: DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { }
/// \brief Force the diagnostic builder to emit the diagnostic now.
@@ -504,7 +540,7 @@ public:
/// Destructor - The dtor emits the diagnostic if it hasn't already
/// been emitted.
~DiagnosticBuilder() { Emit(); }
-
+
/// Operator bool: conversion of DiagnosticBuilder to bool always returns
/// true. This allows is to be used in boolean error contexts like:
/// return Diag(...);
@@ -518,7 +554,7 @@ public:
DiagObj->DiagArgumentsStr[NumArgs++] = S;
}
}
-
+
void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
assert(NumArgs < Diagnostic::MaxArguments &&
"Too many arguments to diagnostic!");
@@ -527,14 +563,14 @@ public:
DiagObj->DiagArgumentsVal[NumArgs++] = V;
}
}
-
+
void AddSourceRange(const SourceRange &R) const {
- assert(NumRanges <
+ 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 {
assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints &&
@@ -579,6 +615,20 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
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) {
@@ -605,7 +655,7 @@ inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned 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.
@@ -613,74 +663,74 @@ 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;
}
-
+
const SourceRange &getRange(unsigned Idx) const {
assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!");
return *DiagObj->DiagRanges[Idx];
}
-
+
unsigned getNumCodeModificationHints() const {
return DiagObj->NumCodeModificationHints;
}
@@ -690,7 +740,7 @@ public:
}
const CodeModificationHint *getCodeModificationHints() const {
- return DiagObj->NumCodeModificationHints?
+ return DiagObj->NumCodeModificationHints?
&DiagObj->CodeModificationHints[0] : 0;
}
@@ -699,20 +749,20 @@ public:
/// array.
void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const;
};
-
+
/// 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();
-
+
/// setLangOptions - This is set by clients of diagnostics when they know the
/// language parameters of the diagnostics that may be sent through. Note
/// that this can change over time if a DiagClient has multiple languages sent
/// through it. It may also be set to null (e.g. when processing command line
/// options).
virtual void setLangOptions(const LangOptions *LO) {}
-
+
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticClient should be included in the number of diagnostics