]> granicus.if.org Git - clang/commitdiff
Add support for sending QualType's directly into diags and convert two
authorChris Lattner <sabre@nondot.org>
Sun, 23 Nov 2008 09:13:29 +0000 (09:13 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 23 Nov 2008 09:13:29 +0000 (09:13 +0000)
diags over to use this.  QualTypes implicitly print single quotes around
them for uniformity and future extension.

Doing this requires a little function pointer dance to prevent libbasic
from depending on libast.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59907 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Type.h
include/clang/Analysis/PathSensitive/BugReporter.h
include/clang/Basic/Diagnostic.h
include/clang/Basic/DiagnosticKinds.def
lib/Basic/Diagnostic.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaExpr.cpp

index 176d67a00eba0c20a8a36ba31d50d8df37a6f2b3..ed1e33752dffad87497b10c1eed0093247ed5937 100644 (file)
 #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
index ef8321f214239f5d8e508019bad2fb4fd03b3d0b..cc3011f8e02ab4565a3af7555a778864bd693062 100644 (file)
@@ -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;
+      }
       }
     }
   }
index f622d785b678ca87e24ad041af437d3f5b3ddb8c..981a559d165b6d5f1b1319f0f4ade107f39a3c16 100644 (file)
@@ -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 {
index 203b6e0ecc08f362e5c25af3ee071e0e482c1c69..e33e6562b3ab80eab4fd3a5125f17851b72631e3 100644 (file)
@@ -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,
index e1183c602ca5584881d83d72708f7c4091e8242c..8a897f57669ca4bd6b376869416d01b2556e44ab 100644 (file)
@@ -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;
     }
   }
 }
index 2edf08ec4256778840ede150bff0b44639e35e2b..d43eadd57441ca1d289368e351f97714e1b623d4 100644 (file)
 #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. 
index ef3ead4fa2c34c47dfbdde87c8447e9d4425bfac..bebde38a18b619462757d4706f93077b80346431 100644 (file)
@@ -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();
 }