diff options
-rw-r--r-- | include/clang/AST/Type.h | 12 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/BugReporter.h | 10 | ||||
-rw-r--r-- | include/clang/Basic/Diagnostic.h | 37 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 4 | ||||
-rw-r--r-- | lib/Basic/Diagnostic.cpp | 33 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 23 |
7 files changed, 111 insertions, 27 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 176d67a00e..ed1e33752d 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -14,11 +14,11 @@ #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; @@ -1486,6 +1486,16 @@ inline bool Type::isOverloadType() const { 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 diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index ef8321f214..cc3011f8e0 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -21,6 +21,7 @@ #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> @@ -316,6 +317,7 @@ public: 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: @@ -333,7 +335,13 @@ public: 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; + } } } } diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index f622d785b6..981a559d16 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -84,6 +84,12 @@ private: /// 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(); @@ -150,6 +156,19 @@ public: /// 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. // @@ -233,7 +252,8 @@ public: ak_c_string, // const char * ak_sint, // int ak_uint, // unsigned - ak_identifierinfo // IdentifierInfo + ak_identifierinfo, // IdentifierInfo + ak_qualtype // QualType }; }; @@ -273,11 +293,14 @@ public: ~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. @@ -419,6 +442,14 @@ public: 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 { diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 203b6e0ecc..e33e6562b3 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -1123,9 +1123,9 @@ DIAG(err_typecheck_invalid_lvalue_addrof, ERROR, 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, diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index e1183c602c..8a897f5766 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -116,6 +116,14 @@ namespace clang { // 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; @@ -130,6 +138,8 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { NumErrors = 0; CustomDiagInfo = 0; CurDiagID = ~0U; + + QualTypeToString = DummyQTToStringFnTy; } Diagnostic::~Diagnostic() { @@ -468,29 +478,29 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { } 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); @@ -507,7 +517,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { break; } case Diagnostic::ak_uint: { - unsigned Val = getArgUInt(StrNo); + unsigned Val = getArgUInt(ArgNo); if (ModifierIs(Modifier, ModifierLen, "select")) { HandleSelectModifier(Val, Argument, ArgumentLen, OutStr); @@ -521,9 +531,16 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { // 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; } } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 2edf08ec42..d43eadd574 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -20,6 +20,22 @@ #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, @@ -108,6 +124,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer) 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. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ef3ead4fa2..bebde38a18 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2054,7 +2054,7 @@ Sema::CheckCompoundAssignmentConstraints(QualType lhsType, QualType rhsType) { 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(); } @@ -2809,20 +2809,19 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { 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(); } |