#ifndef LLVM_CLANG_AST_TYPE_H
#define LLVM_CLANG_AST_TYPE_H
+#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/Bitcode/SerializationFwd.h"
-
using llvm::isa;
using llvm::cast;
using llvm::cast_or_null;
return false;
}
+/// Insertion operator for diagnostics. This allows sending QualType's into a
+/// diagnostic with <<.
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ QualType T) {
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
+ Diagnostic::ak_qualtype);
+ return DB;
+}
+
+
} // end namespace clang
#endif
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include <list>
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
R.addRange(Info.getRange(i));
+ // FIXME: This is losing/ignoring formatting.
for (unsigned i = 0, e = Info.getNumArgs(); i != e; ++i) {
switch (Info.getArgKind(i)) {
case Diagnostic::ak_std_string:
case Diagnostic::ak_identifierinfo:
R.addString(Info.getArgIdentifier(i)->getName());
break;
-
+ case Diagnostic::ak_qualtype: {
+ llvm::SmallString<64> Str;
+ Info.getDiags()->ConvertQualTypeToString(Info.getRawArg(i), 0, 0, 0, 0,
+ Str);
+ R.addString(std::string(Str.begin(), Str.end()));
+ break;
+ }
}
}
}
/// CustomDiagInfo - Information for uniquing and looking up custom diags.
diag::CustomDiagInfo *CustomDiagInfo;
+ /// QualTypeToString - A function pointer that converts QualType's to strings.
+ /// This is a hack to avoid a layering violation between libbasic and libsema.
+ typedef void (*QTToStringFnTy)(intptr_t QT, const char *Modifier, unsigned ML,
+ const char *Argument, unsigned ArgLen,
+ llvm::SmallVectorImpl<char> &Output);
+ QTToStringFnTy QualTypeToString;
public:
explicit Diagnostic(DiagnosticClient *client = 0);
~Diagnostic();
/// registered and created, otherwise the existing ID is returned.
unsigned getCustomDiagID(Level L, const char *Message);
+
+ /// ConvertQualTypeToString - This method converts a QualType (as an intptr_t)
+ /// into the string that represents it if possible.
+ void ConvertQualTypeToString(intptr_t QT, const char *Modifier, unsigned ML,
+ const char *Argument, unsigned ArgLen,
+ llvm::SmallVectorImpl<char> &Output) const {
+ QualTypeToString(QT, Modifier, ML, Argument, ArgLen, Output);
+ }
+
+ void SetQualTypeToStringFn(QTToStringFnTy Fn) {
+ QualTypeToString = Fn;
+ }
+
//===--------------------------------------------------------------------===//
// Diagnostic classification and reporting interfaces.
//
ak_c_string, // const char *
ak_sint, // int
ak_uint, // unsigned
- ak_identifierinfo // IdentifierInfo
+ ak_identifierinfo, // IdentifierInfo
+ ak_qualtype // QualType
};
};
~DiagnosticBuilder() {
// If DiagObj is null, then its soul was stolen by the copy ctor.
if (DiagObj == 0) return;
-
-
+
+ // When destroyed, the ~DiagnosticBuilder sets the final argument count into
+ // the Diagnostic object.
DiagObj->NumDiagArgs = NumArgs;
DiagObj->NumDiagRanges = NumRanges;
+ // Process the diagnostic, sending the accumulated information to the
+ // DiagnosticClient.
DiagObj->ProcessDiag();
// This diagnostic is no longer in flight.
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 {
DIAG(err_typecheck_unary_expr, ERROR,
"invalid argument type to unary expression '%0'")
DIAG(err_typecheck_indirection_requires_pointer, ERROR,
- "indirection requires pointer operand ('%0' invalid)")
+ "indirection requires pointer operand (%0 invalid)")
DIAG(err_typecheck_invalid_operands, ERROR,
- "invalid operands to binary expression ('%0' and '%1')")
+ "invalid operands to binary expression (%0 and %1)")
DIAG(err_typecheck_sub_ptr_object, ERROR,
"'%0' is not a complete object type")
DIAG(err_typecheck_sub_ptr_compatible, ERROR,
// Common Diagnostic implementation
//===----------------------------------------------------------------------===//
+static void DummyQTToStringFnTy(intptr_t QT, const char *Modifier, unsigned ML,
+ const char *Argument, unsigned ArgLen,
+ llvm::SmallVectorImpl<char> &Output) {
+ const char *Str = "<can't format QualType>";
+ Output.append(Str, Str+strlen(Str));
+}
+
+
Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
IgnoreAllWarnings = false;
WarningsAsErrors = false;
NumErrors = 0;
CustomDiagInfo = 0;
CurDiagID = ~0U;
+
+ QualTypeToString = DummyQTToStringFnTy;
}
Diagnostic::~Diagnostic() {
}
assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");
- unsigned StrNo = *DiagStr++ - '0';
+ unsigned ArgNo = *DiagStr++ - '0';
- switch (getArgKind(StrNo)) {
+ switch (getArgKind(ArgNo)) {
case Diagnostic::ak_std_string: {
- const std::string &S = getArgStdStr(StrNo);
+ const std::string &S = getArgStdStr(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
OutStr.append(S.begin(), S.end());
break;
}
case Diagnostic::ak_c_string: {
- const char *S = getArgCStr(StrNo);
+ const char *S = getArgCStr(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
OutStr.append(S, S + strlen(S));
break;
}
case Diagnostic::ak_identifierinfo: {
- const IdentifierInfo *II = getArgIdentifier(StrNo);
+ const IdentifierInfo *II = getArgIdentifier(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
OutStr.append(II->getName(), II->getName() + II->getLength());
break;
}
case Diagnostic::ak_sint: {
- int Val = getArgSInt(StrNo);
+ int Val = getArgSInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
break;
}
case Diagnostic::ak_uint: {
- unsigned Val = getArgUInt(StrNo);
+ unsigned Val = getArgUInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
// FIXME: Optimize
std::string S = llvm::utostr_32(Val);
OutStr.append(S.begin(), S.end());
- break;
}
+ break;
}
+ case Diagnostic::ak_qualtype:
+ OutStr.push_back('\'');
+ getDiags()->ConvertQualTypeToString(getRawArg(ArgNo),
+ Modifier, ModifierLen,
+ Argument, ArgumentLen, OutStr);
+ OutStr.push_back('\'');
+ break;
}
}
}
#include "clang/Basic/Diagnostic.h"
using namespace clang;
+/// ConvertQualTypeToStringFn - This function is used to pretty print the
+/// specified QualType as a string in diagnostics.
+static void ConvertQualTypeToStringFn(intptr_t QT,
+ const char *Modifier, unsigned ML,
+ const char *Argument, unsigned ArgLen,
+ llvm::SmallVectorImpl<char> &Output) {
+ assert(ML == 0 && ArgLen == 0 && "Invalid modifier for QualType argument");
+
+ QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(QT)));
+
+ // FIXME: Playing with std::string is really slow.
+ std::string S = Ty.getAsString();
+ Output.append(S.begin(), S.end());
+}
+
+
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
+
+ // Tell diagnostics how to render things from the AST library.
+ PP.getDiagnostics().SetQualTypeToStringFn(ConvertQualTypeToStringFn);
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
Diag(Loc, diag::err_typecheck_invalid_operands)
- << lex->getType().getAsString() << rex->getType().getAsString()
+ << lex->getType() << rex->getType()
<< lex->getSourceRange() << rex->getSourceRange();
return QualType();
}
return Context.getPointerType(op->getType());
}
-QualType Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) {
- UsualUnaryConversions(op);
- QualType qType = op->getType();
+QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
+ UsualUnaryConversions(Op);
+ QualType Ty = Op->getType();
- if (const PointerType *PT = qType->getAsPointerType()) {
- // Note that per both C89 and C99, this is always legal, even
- // if ptype is an incomplete type or void.
- // It would be possible to warn about dereferencing a
- // void pointer, but it's completely well-defined,
- // and such a warning is unlikely to catch any mistakes.
+ // Note that per both C89 and C99, this is always legal, even if ptype is an
+ // incomplete type or void. It would be possible to warn about dereferencing
+ // a void pointer, but it's completely well-defined, and such a warning is
+ // unlikely to catch any mistakes.
+ if (const PointerType *PT = Ty->getAsPointerType())
return PT->getPointeeType();
- }
+
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
- << qType.getAsString() << op->getSourceRange();
+ << Ty << Op->getSourceRange();
return QualType();
}