diff options
| -rw-r--r-- | clang/include/clang/AST/Type.h | 12 | ||||
| -rw-r--r-- | clang/include/clang/Analysis/PathSensitive/BugReporter.h | 10 | ||||
| -rw-r--r-- | clang/include/clang/Basic/Diagnostic.h | 37 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 4 | ||||
| -rw-r--r-- | clang/lib/Basic/Diagnostic.cpp | 33 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.cpp | 19 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 23 | 
7 files changed, 111 insertions, 27 deletions
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 176d67a00eb..ed1e33752df 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/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/clang/include/clang/Analysis/PathSensitive/BugReporter.h b/clang/include/clang/Analysis/PathSensitive/BugReporter.h index ef8321f2142..cc3011f8e02 100644 --- a/clang/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/clang/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/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index f622d785b67..981a559d165 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/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/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 203b6e0ecc0..e33e6562b3a 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/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/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index e1183c602ca..8a897f57669 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/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/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 2edf08ec425..d43eadd5744 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ef3ead4fa2c..bebde38a18b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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();  }  | 

