Improve the printing of __PRETTY_FUNCTION__ more provide more
information and more closely match GCC's, from Nikola Smiljanic!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154430 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index ffc8fea..1947e61 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -399,21 +399,23 @@
     }
 
     PrintingPolicy Policy(Context.getLangOpts());
-
     std::string Proto = FD->getQualifiedNameAsString(Policy);
+    llvm::raw_string_ostream POut(Proto);
 
-    const FunctionType *AFT = FD->getType()->getAs<FunctionType>();
+    const FunctionDecl *Decl = FD;
+    if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
+      Decl = Pattern;
+    const FunctionType *AFT = Decl->getType()->getAs<FunctionType>();
     const FunctionProtoType *FT = 0;
     if (FD->hasWrittenPrototype())
       FT = dyn_cast<FunctionProtoType>(AFT);
 
-    Proto += "(";
+    POut << "(";
     if (FT) {
-      llvm::raw_string_ostream POut(Proto);
-      for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+      for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
         if (i) POut << ", ";
         std::string Param;
-        FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
+        Decl->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
         POut << Param;
       }
 
@@ -422,16 +424,74 @@
         POut << "...";
       }
     }
-    Proto += ")";
+    POut << ")";
 
     if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
       Qualifiers ThisQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
       if (ThisQuals.hasConst())
-        Proto += " const";
+        POut << " const";
       if (ThisQuals.hasVolatile())
-        Proto += " volatile";
+        POut << " volatile";
+      RefQualifierKind Ref = MD->getRefQualifier();
+      if (Ref == RQ_LValue)
+        POut << " &";
+      else if (Ref == RQ_RValue)
+        POut << " &&";
     }
 
+    typedef SmallVector<const ClassTemplateSpecializationDecl *, 8> SpecsTy;
+    SpecsTy Specs;
+    const DeclContext *Ctx = FD->getDeclContext();
+    while (Ctx && isa<NamedDecl>(Ctx)) {
+      const ClassTemplateSpecializationDecl *Spec
+                               = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
+      if (Spec && !Spec->isExplicitSpecialization())
+        Specs.push_back(Spec);
+      Ctx = Ctx->getParent();
+    }
+
+    std::string TemplateParams;
+    llvm::raw_string_ostream TOut(TemplateParams);
+    for (SpecsTy::reverse_iterator I = Specs.rbegin(), E = Specs.rend();
+         I != E; ++I) {
+      const TemplateParameterList *Params 
+                  = (*I)->getSpecializedTemplate()->getTemplateParameters();
+      const TemplateArgumentList &Args = (*I)->getTemplateArgs();
+      assert(Params->size() == Args.size());
+      for (unsigned i = 0, numParams = Params->size(); i != numParams; ++i) {
+        StringRef Param = Params->getParam(i)->getName();
+        if (Param.empty()) continue;
+        TOut << Param << " = ";
+        Args.get(i).print(Policy, TOut);
+        TOut << ", ";
+      }
+    }
+
+    FunctionTemplateSpecializationInfo *FSI 
+                                          = FD->getTemplateSpecializationInfo();
+    if (FSI && !FSI->isExplicitSpecialization()) {
+      const TemplateParameterList* Params 
+                                  = FSI->getTemplate()->getTemplateParameters();
+      const TemplateArgumentList* Args = FSI->TemplateArguments;
+      assert(Params->size() == Args->size());
+      for (unsigned i = 0, e = Params->size(); i != e; ++i) {
+        StringRef Param = Params->getParam(i)->getName();
+        if (Param.empty()) continue;
+        TOut << Param << " = ";
+        Args->get(i).print(Policy, TOut);
+        TOut << ", ";
+      }
+    }
+
+    TOut.flush();
+    if (!TemplateParams.empty()) {
+      // remove the trailing comma and space
+      TemplateParams.resize(TemplateParams.size() - 2);
+      POut << " [" << TemplateParams << "]";
+    }
+
+    POut.flush();
+
     if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
       AFT->getResultType().getAsStringInternal(Proto, Policy);
 
diff --git a/test/CodeGenCXX/predefined-expr-sizeof.cpp b/test/CodeGenCXX/predefined-expr-sizeof.cpp
index f74cfb3..b4712ad 100644
--- a/test/CodeGenCXX/predefined-expr-sizeof.cpp
+++ b/test/CodeGenCXX/predefined-expr-sizeof.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
 
-// CHECK: store i32 49, i32* %size
-// CHECK: store i32 52, i32* %size
+// CHECK: store i32 59, i32* %size
+// CHECK: store i32 65, i32* %size
 template<typename T>
 class TemplateClass {
 public:
@@ -10,8 +10,8 @@
   }
 };
 
-// CHECK: store i32 27, i32* %size
-// CHECK: store i32 30, i32* %size
+// CHECK: store i32 35, i32* %size
+// CHECK: store i32 38, i32* %size
 template<typename T>
 void functionTemplate(T t) {
   int size = sizeof(__PRETTY_FUNCTION__);
diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp
index 56270b5..1795ec8 100644
--- a/test/CodeGenCXX/predefined-expr.cpp
+++ b/test/CodeGenCXX/predefined-expr.cpp
@@ -1,15 +1,29 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - | FileCheck %s
 
 // CHECK: private unnamed_addr constant [15 x i8] c"externFunction\00"
 // CHECK: private unnamed_addr constant [26 x i8] c"void NS::externFunction()\00"
+// CHECK: private unnamed_addr constant [49 x i8] c"void functionTemplateExplicitSpecialization(int)\00"
+
+// CHECK: private unnamed_addr constant [95 x i8] c"void SpecializedClassTemplate<char>::memberFunctionTemplate(T, U) const [T = char, U = double]\00"
+// CHECK: private unnamed_addr constant [85 x i8] c"void SpecializedClassTemplate<int>::memberFunctionTemplate(int, U) const [U = float]\00"
+// CHECK: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00"
+// CHECK: private unnamed_addr constant [122 x i8] c"static void ClassWithTemplateTemplateParam<char, NS::ClassTemplate>::staticMember() [T = char, Param = NS::ClassTemplate]\00"
+// CHECK: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00"
+// CHECK: private unnamed_addr constant [65 x i8] c"void functionTemplateWithUnnamedTemplateParameter(T) [T = float]\00"
+
+// CHECK: private unnamed_addr constant [60 x i8] c"void functionTemplateExplicitSpecialization(T) [T = double]\00"
+// CHECK: private unnamed_addr constant [52 x i8] c"T *functionTemplateWithCompoundTypes(T *) [T = int]\00" 
+// CHECK: private unnamed_addr constant [54 x i8] c"T functionTemplateWithTemplateReturnType() [T = char]\00"
+// CHECK: private unnamed_addr constant [57 x i8] c"void functionTemplateWithoutParameterList() [T = double]\00"
+// CHECK: private unnamed_addr constant [62 x i8] c"void functionTemplateWithTwoParams(T, U) [T = int, U = float]\00"
 
 // CHECK: private unnamed_addr constant [22 x i8] c"classTemplateFunction\00"
-// CHECK: private unnamed_addr constant [60 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction()\00"
-// CHECK: private unnamed_addr constant [53 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction()\00"
+// CHECK: private unnamed_addr constant [77 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction() [T = NS::Base *]\00"
+// CHECK: private unnamed_addr constant [63 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction() [T = int]\00"
 
 // CHECK: private unnamed_addr constant [18 x i8] c"functionTemplate1\00"
-// CHECK: private unnamed_addr constant [45 x i8] c"void NS::Base::functionTemplate1(NS::Base *)\00"
-// CHECK: private unnamed_addr constant [38 x i8] c"void NS::Base::functionTemplate1(int)\00"
+// CHECK: private unnamed_addr constant [53 x i8] c"void NS::Base::functionTemplate1(T) [T = NS::Base *]\00"
+// CHECK: private unnamed_addr constant [46 x i8] c"void NS::Base::functionTemplate1(T) [T = int]\00"
 
 // CHECK: private unnamed_addr constant [23 x i8] c"anonymousUnionFunction\00"
 // CHECK: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::<anonymous union>::anonymousUnionFunction()\00"
@@ -31,6 +45,10 @@
 // CHECK: private unnamed_addr constant [16 x i8] c"virtualFunction\00"
 // CHECK: private unnamed_addr constant [44 x i8] c"virtual void NS::Derived::virtualFunction()\00"
 
+// CHECK: private unnamed_addr constant [21 x i8] c"refQualifiedFunction\00"
+// CHECK: private unnamed_addr constant [41 x i8] c"void NS::Base::refQualifiedFunction() &&\00"
+// CHECK: private unnamed_addr constant [40 x i8] c"void NS::Base::refQualifiedFunction() &\00"
+
 // CHECK: private unnamed_addr constant [22 x i8] c"constVolatileFunction\00"
 // CHECK: private unnamed_addr constant [54 x i8] c"void NS::Base::constVolatileFunction() const volatile\00"
 
@@ -78,6 +96,8 @@
 // CHECK: private unnamed_addr constant [19 x i8] c"localClassFunction\00"
 // CHECK: private unnamed_addr constant [59 x i8] c"void NS::localClass(int)::LocalClass::localClassFunction()\00"
 
+
+
 int printf(const char * _Format, ...);
 
 class ClassInTopLevelNamespace {
@@ -203,11 +223,23 @@
     printf("__FUNCTION__ %s\n", __FUNCTION__);
     printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
   }
+
+  void refQualifiedFunction() & {
+    printf("__func__ %s\n", __func__);
+    printf("__FUNCTION__ %s\n", __FUNCTION__);
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+
+  void refQualifiedFunction() && {
+    printf("__func__ %s\n", __func__);
+    printf("__FUNCTION__ %s\n", __FUNCTION__);
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
 };
 
 class Derived : public Base {
 public:
-  // Virtual function without being explicitally written.
+  // Virtual function without being explicitly written.
   void virtualFunction() {
     printf("__func__ %s\n", __func__);
     printf("__FUNCTION__ %s\n", __FUNCTION__);
@@ -294,6 +326,116 @@
 
 } // end NS namespace
 
+// additional tests for __PRETTY_FUNCTION__
+template <typename T, typename U>
+void functionTemplateWithTwoParams(T, U)
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+void functionTemplateWithoutParameterList()
+{
+  T t = T();
+
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+T functionTemplateWithTemplateReturnType()
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+
+  return T();
+}
+
+template <typename T>
+T * functionTemplateWithCompoundTypes(T a[])
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+
+  return 0;
+}
+
+template <typename T>
+void functionTemplateExplicitSpecialization(T t)
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <>
+void functionTemplateExplicitSpecialization<int>(int i)
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename, typename T>
+void functionTemplateWithUnnamedTemplateParameter(T t)
+{
+  printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+class OuterClass
+{
+public:
+  class MiddleClass
+  {
+  public:
+    template <typename U>
+    class InnerClass
+    {
+    public:
+      void memberFunction(T x, U y) const
+      {
+        printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+      }
+    };
+  };
+};
+
+template <typename T, template <typename> class Param = NS::ClassTemplate>
+class ClassWithTemplateTemplateParam
+{
+public:
+  static void staticMember()
+  {
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+};
+
+template <int Count>
+class NonTypeTemplateParam
+{
+public:
+  void size() const
+  {
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+};
+
+template <typename T>
+class SpecializedClassTemplate
+{
+public:
+  template <typename U>
+  void memberFunctionTemplate(T t, U u) const
+  {
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+};
+
+template <>
+class SpecializedClassTemplate<int>
+{
+public:
+  template <typename U>
+  void memberFunctionTemplate(int i, U u) const
+  {
+    printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+  }
+};
+
 int main() {
   ClassInAnonymousNamespace anonymousNamespace;
   anonymousNamespace.anonymousNamespaceFunction();
@@ -319,6 +461,8 @@
   b.constFunction();
   b.volatileFunction();
   b.constVolatileFunction();
+  b.refQualifiedFunction();
+  NS::Base().refQualifiedFunction();
 
   NS::Derived d;
   d.virtualFunction();
@@ -345,5 +489,29 @@
 
   NS::externFunction();
 
+  // additional tests for __PRETTY_FUNCTION__
+
+  functionTemplateWithTwoParams(0, 0.0f);
+  functionTemplateWithoutParameterList<double>();
+  functionTemplateWithTemplateReturnType<char>();
+  int array[] = { 1, 2, 3 };
+  functionTemplateWithCompoundTypes(array);
+  functionTemplateExplicitSpecialization(0);
+  functionTemplateExplicitSpecialization(0.0);
+  functionTemplateWithUnnamedTemplateParameter<int, float>(0.0f);
+
+  OuterClass<int *>::MiddleClass::InnerClass<float> omi;
+  omi.memberFunction(0, 0.0f);
+
+  ClassWithTemplateTemplateParam<char>::staticMember();
+
+  NonTypeTemplateParam<42> ntt;
+  ntt.size();
+
+  SpecializedClassTemplate<int> sct1;
+  sct1.memberFunctionTemplate(0, 0.0f);
+  SpecializedClassTemplate<char> sct2;
+  sct2.memberFunctionTemplate('0', 0.0);
+
   return 0;
 }