[cfe-commits] r95701 - in /cfe/trunk: include/clang/AST/ASTDiagnostic.h lib/AST/ASTDiagnostic.cpp lib/AST/CMakeLists.txt lib/Sema/Sema.cpp

Douglas Gregor dgregor at apple.com
Tue Feb 9 14:26:47 PST 2010


Author: dgregor
Date: Tue Feb  9 16:26:47 2010
New Revision: 95701

URL: http://llvm.org/viewvc/llvm-project?rev=95701&view=rev
Log:
Move the diagnostic argument formatting function out of Sema and make
it available within the AST library, of which Sema is one client. No
functionality change.

Added:
    cfe/trunk/lib/AST/ASTDiagnostic.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTDiagnostic.h
    cfe/trunk/lib/AST/CMakeLists.txt
    cfe/trunk/lib/Sema/Sema.cpp

Modified: cfe/trunk/include/clang/AST/ASTDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTDiagnostic.h?rev=95701&r1=95700&r2=95701&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTDiagnostic.h (original)
+++ cfe/trunk/include/clang/AST/ASTDiagnostic.h Tue Feb  9 16:26:47 2010
@@ -1,4 +1,4 @@
-//===--- DiagnosticAST.h - Diagnostics for the AST library ------*- C++ -*-===//
+//===--- ASTDiagnostic.h - Diagnostics for the AST library ------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -22,6 +22,26 @@
       NUM_BUILTIN_AST_DIAGNOSTICS
     };
   }  // end namespace diag
+  
+  /// \brief Diagnostic argument formatting function for diagnostics that
+  /// involve AST nodes.
+  ///
+  /// This function formats diagnostic arguments for various AST nodes, 
+  /// including types, declaration names, nested name specifiers, and
+  /// declaration contexts, into strings that can be printed as part of
+  /// diagnostics. It is meant to be used as the argument to
+  /// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext
+  /// pointer.
+  void FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, 
+                                       intptr_t Val,
+                                       const char *Modifier, 
+                                       unsigned ModLen,
+                                       const char *Argument, 
+                                       unsigned ArgLen,
+                                      const Diagnostic::ArgumentValue *PrevArgs,
+                                       unsigned NumPrevArgs,
+                                       llvm::SmallVectorImpl<char> &Output,
+                                       void *Cookie);
 }  // end namespace clang
 
 #endif

Added: cfe/trunk/lib/AST/ASTDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDiagnostic.cpp?rev=95701&view=auto

==============================================================================
--- cfe/trunk/lib/AST/ASTDiagnostic.cpp (added)
+++ cfe/trunk/lib/AST/ASTDiagnostic.cpp Tue Feb  9 16:26:47 2010
@@ -0,0 +1,266 @@
+//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a diagnostic formatting hook for AST elements.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTDiagnostic.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+/// Determines whether we should have an a.k.a. clause when
+/// pretty-printing a type.  There are three main criteria:
+///
+/// 1) Some types provide very minimal sugar that doesn't impede the
+///    user's understanding --- for example, elaborated type
+///    specifiers.  If this is all the sugar we see, we don't want an
+///    a.k.a. clause.
+/// 2) Some types are technically sugared but are much more familiar
+///    when seen in their sugared form --- for example, va_list,
+///    vector types, and the magic Objective C types.  We don't
+///    want to desugar these, even if we do produce an a.k.a. clause.
+/// 3) Some types may have already been desugared previously in this diagnostic.
+///    if this is the case, doing another "aka" would just be clutter.
+///
+static bool ShouldAKA(ASTContext &Context, QualType QT,
+                      const Diagnostic::ArgumentValue *PrevArgs,
+                      unsigned NumPrevArgs,
+                      QualType &DesugaredQT) {
+  QualType InputTy = QT;
+  
+  bool AKA = false;
+  QualifierCollector Qc;
+  
+  while (true) {
+    const Type *Ty = Qc.strip(QT);
+    
+    // Don't aka just because we saw an elaborated type...
+    if (isa<ElaboratedType>(Ty)) {
+      QT = cast<ElaboratedType>(Ty)->desugar();
+      continue;
+    }
+    
+    // ...or a qualified name type...
+    if (isa<QualifiedNameType>(Ty)) {
+      QT = cast<QualifiedNameType>(Ty)->desugar();
+      continue;
+    }
+    
+    // ...or a substituted template type parameter.
+    if (isa<SubstTemplateTypeParmType>(Ty)) {
+      QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
+      continue;
+    }
+    
+    // Don't desugar template specializations. 
+    if (isa<TemplateSpecializationType>(Ty))
+      break;
+    
+    // Don't desugar magic Objective-C types.
+    if (QualType(Ty,0) == Context.getObjCIdType() ||
+        QualType(Ty,0) == Context.getObjCClassType() ||
+        QualType(Ty,0) == Context.getObjCSelType() ||
+        QualType(Ty,0) == Context.getObjCProtoType())
+      break;
+    
+    // Don't desugar va_list.
+    if (QualType(Ty,0) == Context.getBuiltinVaListType())
+      break;
+    
+    // Otherwise, do a single-step desugar.
+    QualType Underlying;
+    bool IsSugar = false;
+    switch (Ty->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Base)
+#define TYPE(Class, Base) \
+case Type::Class: { \
+const Class##Type *CTy = cast<Class##Type>(Ty); \
+if (CTy->isSugared()) { \
+IsSugar = true; \
+Underlying = CTy->desugar(); \
+} \
+break; \
+}
+#include "clang/AST/TypeNodes.def"
+    }
+    
+    // If it wasn't sugared, we're done.
+    if (!IsSugar)
+      break;
+    
+    // If the desugared type is a vector type, we don't want to expand
+    // it, it will turn into an attribute mess. People want their "vec4".
+    if (isa<VectorType>(Underlying))
+      break;
+    
+    // Don't desugar through the primary typedef of an anonymous type.
+    if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
+      if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
+          cast<TypedefType>(QT)->getDecl())
+        break;
+    
+    // Otherwise, we're tearing through something opaque; note that
+    // we'll eventually need an a.k.a. clause and keep going.
+    AKA = true;
+    QT = Underlying;
+    continue;
+  }
+  
+  // If we never tore through opaque sugar, don't print aka.
+  if (!AKA) return false;
+  
+  // If we did, check to see if we already desugared this type in this
+  // diagnostic.  If so, don't do it again.
+  for (unsigned i = 0; i != NumPrevArgs; ++i) {
+    // TODO: Handle ak_declcontext case.
+    if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
+      void *Ptr = (void*)PrevArgs[i].second;
+      QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
+      if (PrevTy == InputTy)
+        return false;
+    }
+  }
+  
+  DesugaredQT = Qc.apply(QT);
+  return true;
+}
+
+/// \brief Convert the given type to a string suitable for printing as part of 
+/// a diagnostic. 
+///
+/// \param Context the context in which the type was allocated
+/// \param Ty the type to print
+static std::string
+ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
+                              const Diagnostic::ArgumentValue *PrevArgs,
+                              unsigned NumPrevArgs) {
+  // FIXME: Playing with std::string is really slow.
+  std::string S = Ty.getAsString(Context.PrintingPolicy);
+  
+  // Consider producing an a.k.a. clause if removing all the direct
+  // sugar gives us something "significantly different".
+  
+  QualType DesugaredTy;
+  if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
+    S = "'"+S+"' (aka '";
+    S += DesugaredTy.getAsString(Context.PrintingPolicy);
+    S += "')";
+    return S;
+  }
+  
+  S = "'" + S + "'";
+  return S;
+}
+
+void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, 
+                                            intptr_t Val,
+                                            const char *Modifier, 
+                                            unsigned ModLen,
+                                            const char *Argument, 
+                                            unsigned ArgLen,
+                                    const Diagnostic::ArgumentValue *PrevArgs,
+                                            unsigned NumPrevArgs,
+                                            llvm::SmallVectorImpl<char> &Output,
+                                            void *Cookie) {
+  ASTContext &Context = *static_cast<ASTContext*>(Cookie);
+  
+  std::string S;
+  bool NeedQuotes = true;
+  
+  switch (Kind) {
+    default: assert(0 && "unknown ArgumentKind");
+    case Diagnostic::ak_qualtype: {
+      assert(ModLen == 0 && ArgLen == 0 &&
+             "Invalid modifier for QualType argument");
+      
+      QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
+      S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
+      NeedQuotes = false;
+      break;
+    }
+    case Diagnostic::ak_declarationname: {
+      DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
+      S = N.getAsString();
+      
+      if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
+        S = '+' + S;
+      else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
+                && ArgLen==0)
+        S = '-' + S;
+      else
+        assert(ModLen == 0 && ArgLen == 0 &&
+               "Invalid modifier for DeclarationName argument");
+      break;
+    }
+    case Diagnostic::ak_nameddecl: {
+      bool Qualified;
+      if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
+        Qualified = true;
+      else {
+        assert(ModLen == 0 && ArgLen == 0 &&
+               "Invalid modifier for NamedDecl* argument");
+        Qualified = false;
+      }
+      reinterpret_cast<NamedDecl*>(Val)->
+      getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
+      break;
+    }
+    case Diagnostic::ak_nestednamespec: {
+      llvm::raw_string_ostream OS(S);
+      reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
+                                                        Context.PrintingPolicy);
+      NeedQuotes = false;
+      break;
+    }
+    case Diagnostic::ak_declcontext: {
+      DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
+      assert(DC && "Should never have a null declaration context");
+      
+      if (DC->isTranslationUnit()) {
+        // FIXME: Get these strings from some localized place
+        if (Context.getLangOptions().CPlusPlus)
+          S = "the global namespace";
+        else
+          S = "the global scope";
+      } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
+        S = ConvertTypeToDiagnosticString(Context, 
+                                          Context.getTypeDeclType(Type),
+                                          PrevArgs, NumPrevArgs);
+      } else {
+        // FIXME: Get these strings from some localized place
+        NamedDecl *ND = cast<NamedDecl>(DC);
+        if (isa<NamespaceDecl>(ND))
+          S += "namespace ";
+        else if (isa<ObjCMethodDecl>(ND))
+          S += "method ";
+        else if (isa<FunctionDecl>(ND))
+          S += "function ";
+        
+        S += "'";
+        ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
+        S += "'";
+      }
+      NeedQuotes = false;
+      break;
+    }
+  }
+  
+  if (NeedQuotes)
+    Output.push_back('\'');
+  
+  Output.append(S.begin(), S.end());
+  
+  if (NeedQuotes)
+    Output.push_back('\'');
+}

Modified: cfe/trunk/lib/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=95701&r1=95700&r2=95701&view=diff

==============================================================================
--- cfe/trunk/lib/AST/CMakeLists.txt (original)
+++ cfe/trunk/lib/AST/CMakeLists.txt Tue Feb  9 16:26:47 2010
@@ -5,6 +5,7 @@
   ASTConsumer.cpp
   ASTContext.cpp
   ASTImporter.cpp
+  ASTDiagnostic.cpp
   AttrImpl.cpp
   CXXInheritance.cpp
   Decl.cpp

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=95701&r1=95700&r2=95701&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Feb  9 16:26:47 2010
@@ -19,257 +19,14 @@
 #include "llvm/ADT/APFloat.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
 using namespace clang;
-
-/// Determines whether we should have an a.k.a. clause when
-/// pretty-printing a type.  There are three main criteria:
-///
-/// 1) Some types provide very minimal sugar that doesn't impede the
-///    user's understanding --- for example, elaborated type
-///    specifiers.  If this is all the sugar we see, we don't want an
-///    a.k.a. clause.
-/// 2) Some types are technically sugared but are much more familiar
-///    when seen in their sugared form --- for example, va_list,
-///    vector types, and the magic Objective C types.  We don't
-///    want to desugar these, even if we do produce an a.k.a. clause.
-/// 3) Some types may have already been desugared previously in this diagnostic.
-///    if this is the case, doing another "aka" would just be clutter.
-///
-static bool ShouldAKA(ASTContext &Context, QualType QT,
-                      const Diagnostic::ArgumentValue *PrevArgs,
-                      unsigned NumPrevArgs,
-                      QualType &DesugaredQT) {
-  QualType InputTy = QT;
-  
-  bool AKA = false;
-  QualifierCollector Qc;
-
-  while (true) {
-    const Type *Ty = Qc.strip(QT);
-
-    // Don't aka just because we saw an elaborated type...
-    if (isa<ElaboratedType>(Ty)) {
-      QT = cast<ElaboratedType>(Ty)->desugar();
-      continue;
-    }
-
-    // ...or a qualified name type...
-    if (isa<QualifiedNameType>(Ty)) {
-      QT = cast<QualifiedNameType>(Ty)->desugar();
-      continue;
-    }
-
-    // ...or a substituted template type parameter.
-    if (isa<SubstTemplateTypeParmType>(Ty)) {
-      QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
-      continue;
-    }
-      
-    // Don't desugar template specializations. 
-    if (isa<TemplateSpecializationType>(Ty))
-      break;
-
-    // Don't desugar magic Objective-C types.
-    if (QualType(Ty,0) == Context.getObjCIdType() ||
-        QualType(Ty,0) == Context.getObjCClassType() ||
-        QualType(Ty,0) == Context.getObjCSelType() ||
-        QualType(Ty,0) == Context.getObjCProtoType())
-      break;
-
-    // Don't desugar va_list.
-    if (QualType(Ty,0) == Context.getBuiltinVaListType())
-      break;
-
-    // Otherwise, do a single-step desugar.
-    QualType Underlying;
-    bool IsSugar = false;
-    switch (Ty->getTypeClass()) {
-#define ABSTRACT_TYPE(Class, Base)
-#define TYPE(Class, Base) \
-    case Type::Class: { \
-      const Class##Type *CTy = cast<Class##Type>(Ty); \
-      if (CTy->isSugared()) { \
-        IsSugar = true; \
-        Underlying = CTy->desugar(); \
-      } \
-      break; \
-    }
-#include "clang/AST/TypeNodes.def"
-    }
-
-    // If it wasn't sugared, we're done.
-    if (!IsSugar)
-      break;
-
-    // If the desugared type is a vector type, we don't want to expand
-    // it, it will turn into an attribute mess. People want their "vec4".
-    if (isa<VectorType>(Underlying))
-      break;
-
-    // Don't desugar through the primary typedef of an anonymous type.
-    if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
-      if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
-          cast<TypedefType>(QT)->getDecl())
-        break;
-
-    // Otherwise, we're tearing through something opaque; note that
-    // we'll eventually need an a.k.a. clause and keep going.
-    AKA = true;
-    QT = Underlying;
-    continue;
-  }
-
-  // If we never tore through opaque sugar, don't print aka.
-  if (!AKA) return false;
-
-  // If we did, check to see if we already desugared this type in this
-  // diagnostic.  If so, don't do it again.
-  for (unsigned i = 0; i != NumPrevArgs; ++i) {
-    // TODO: Handle ak_declcontext case.
-    if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
-      void *Ptr = (void*)PrevArgs[i].second;
-      QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
-      if (PrevTy == InputTy)
-        return false;
-    }
-  }
-  
-  DesugaredQT = Qc.apply(QT);
-  return true;
-}
-
-/// \brief Convert the given type to a string suitable for printing as part of 
-/// a diagnostic. 
-///
-/// \param Context the context in which the type was allocated
-/// \param Ty the type to print
-static std::string
-ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
-                              const Diagnostic::ArgumentValue *PrevArgs,
-                              unsigned NumPrevArgs) {
-  // FIXME: Playing with std::string is really slow.
-  std::string S = Ty.getAsString(Context.PrintingPolicy);
-  
-  // Consider producing an a.k.a. clause if removing all the direct
-  // sugar gives us something "significantly different".
-
-  QualType DesugaredTy;
-  if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
-    S = "'"+S+"' (aka '";
-    S += DesugaredTy.getAsString(Context.PrintingPolicy);
-    S += "')";
-    return S;
-  }
-
-  S = "'" + S + "'";
-  return S;
-}
                                        
-/// ConvertQualTypeToStringFn - This function is used to pretty print the
-/// specified QualType as a string in diagnostics.
-static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
-                                 const char *Modifier, unsigned ModLen,
-                                 const char *Argument, unsigned ArgLen,
-                                 const Diagnostic::ArgumentValue *PrevArgs,
-                                 unsigned NumPrevArgs,
-                                 llvm::SmallVectorImpl<char> &Output,
-                                 void *Cookie) {
-  ASTContext &Context = *static_cast<ASTContext*>(Cookie);
-
-  std::string S;
-  bool NeedQuotes = true;
-  
-  switch (Kind) {
-  default: assert(0 && "unknown ArgumentKind");
-  case Diagnostic::ak_qualtype: {
-    assert(ModLen == 0 && ArgLen == 0 &&
-           "Invalid modifier for QualType argument");
-
-    QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
-    S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
-    NeedQuotes = false;
-    break;
-  }
-  case Diagnostic::ak_declarationname: {
-    DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
-    S = N.getAsString();
-
-    if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
-      S = '+' + S;
-    else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
-      S = '-' + S;
-    else
-      assert(ModLen == 0 && ArgLen == 0 &&
-             "Invalid modifier for DeclarationName argument");
-    break;
-  }
-  case Diagnostic::ak_nameddecl: {
-    bool Qualified;
-    if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
-      Qualified = true;
-    else {
-      assert(ModLen == 0 && ArgLen == 0 &&
-           "Invalid modifier for NamedDecl* argument");
-      Qualified = false;
-    }
-    reinterpret_cast<NamedDecl*>(Val)->
-      getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
-    break;
-  }
-  case Diagnostic::ak_nestednamespec: {
-    llvm::raw_string_ostream OS(S);
-    reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
-                                                       Context.PrintingPolicy);
-    NeedQuotes = false;
-    break;
-  }
-  case Diagnostic::ak_declcontext: {
-    DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
-    assert(DC && "Should never have a null declaration context");
-    
-    if (DC->isTranslationUnit()) {
-      // FIXME: Get these strings from some localized place
-      if (Context.getLangOptions().CPlusPlus)
-        S = "the global namespace";
-      else
-        S = "the global scope";
-    } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
-      S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type),
-                                        PrevArgs, NumPrevArgs);
-    } else {
-      // FIXME: Get these strings from some localized place
-      NamedDecl *ND = cast<NamedDecl>(DC);
-      if (isa<NamespaceDecl>(ND))
-        S += "namespace ";
-      else if (isa<ObjCMethodDecl>(ND))
-        S += "method ";
-      else if (isa<FunctionDecl>(ND))
-        S += "function ";
-
-      S += "'";
-      ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
-      S += "'";
-    }
-    NeedQuotes = false;
-    break;
-  }
-  }
-
-  if (NeedQuotes)
-    Output.push_back('\'');
-  
-  Output.append(S.begin(), S.end());
-  
-  if (NeedQuotes)
-    Output.push_back('\'');
-}
-
-
 static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
   if (C.getLangOptions().CPlusPlus)
     return CXXRecordDecl::Create(C, TagDecl::TK_struct,
@@ -371,7 +128,8 @@
     FieldCollector.reset(new CXXFieldCollector());
 
   // Tell diagnostics how to render things from the AST library.
-  PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
+  PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, 
+                                       &Context);
 
   ExprEvalContexts.push_back(
                   ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));





More information about the cfe-commits mailing list