Vastly improve PredefinedExpr output, both in Sema and CodeGen. Patch by Sam Weinig!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81237 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index ca1ae63..4e07b95 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -216,6 +216,10 @@
 //===----------------------------------------------------------------------===//
 
 std::string NamedDecl::getQualifiedNameAsString() const {
+  return getQualifiedNameAsString(getASTContext().getLangOptions());
+}
+
+std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
   std::vector<std::string> Names;
   std::string QualName;
   const DeclContext *Ctx = getDeclContext();
@@ -232,12 +236,11 @@
     if (const ClassTemplateSpecializationDecl *Spec 
           = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
       const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
-      PrintingPolicy Policy(getASTContext().getLangOptions());
       std::string TemplateArgsStr
         = TemplateSpecializationType::PrintTemplateArgumentList(
                                            TemplateArgs.getFlatArgumentList(),
                                            TemplateArgs.flat_size(),
-                                           Policy);
+                                           P);
       Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr);
     } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
       Names.push_back(ND->getNameAsString());
@@ -259,7 +262,6 @@
   return QualName;
 }
 
-
 bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
   assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
 
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 8338c48..ee2b815 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -290,23 +290,6 @@
                                        Context.getObjCSelType()));
 }
 
-
-
-/// getSynthesizedMethodSize - Compute size of synthesized method name
-/// as done be the rewrite.
-///
-unsigned ObjCMethodDecl::getSynthesizedMethodSize() const {
-  // syntesized method name is a concatenation of -/+[class-name selector]
-  // Get length of this name.
-  unsigned length = 3;  // _I_ or _C_
-  length += getClassInterface()->getNameAsString().size()+1; // extra for _
-  if (const ObjCCategoryImplDecl *CID = 
-      dyn_cast<ObjCCategoryImplDecl>(getDeclContext()))
-    length += CID->getNameAsString().size()+1;
-  length += getSelector().getAsString().size(); // selector name
-  return length; 
-}
-
 ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
   if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext()))
     return ID;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index daa98ae..7171c79 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 using namespace clang;
 
@@ -29,6 +30,82 @@
 // Primary Expressions.
 //===----------------------------------------------------------------------===//
 
+// FIXME: Maybe this should use DeclPrinter with a special "print predefined
+// expr" policy instead.
+std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
+                                        const Decl *CurrentDecl) {
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
+    if (IT != PrettyFunction)
+      return FD->getNameAsString();
+
+    llvm::SmallString<256> Name;
+    llvm::raw_svector_ostream Out(Name);
+
+    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+      if (MD->isVirtual())
+        Out << "virtual ";
+    }
+
+    PrintingPolicy Policy(Context.getLangOptions());
+    Policy.SuppressTagKind = true;
+
+    std::string Proto = FD->getQualifiedNameAsString(Policy);
+
+    const FunctionType *AFT = FD->getType()->getAsFunctionType();
+    const FunctionProtoType *FT = 0;
+    if (FD->hasWrittenPrototype())
+      FT = dyn_cast<FunctionProtoType>(AFT);
+
+    Proto += "(";
+    if (FT) {
+      llvm::raw_string_ostream POut(Proto);
+      for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+        if (i) POut << ", ";
+        std::string Param;
+        FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
+        POut << Param;
+      }
+
+      if (FT->isVariadic()) {
+        if (FD->getNumParams()) POut << ", ";
+        POut << "...";
+      }
+    }
+    Proto += ")";
+
+    AFT->getResultType().getAsStringInternal(Proto, Policy);
+
+    Out << Proto;
+
+    Out.flush();
+    return Name.str().str();
+  }
+  if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) {
+    llvm::SmallString<256> Name;
+    llvm::raw_svector_ostream Out(Name);
+    Out << (MD->isInstanceMethod() ? '-' : '+');
+    Out << '[';
+    Out << MD->getClassInterface()->getNameAsString();
+    if (const ObjCCategoryImplDecl *CID =
+        dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
+      Out << '(';
+      Out <<  CID->getNameAsString();
+      Out <<  ')';
+    }
+    Out <<  ' ';
+    Out << MD->getSelector().getAsString();
+    Out <<  ']';
+
+    Out.flush();
+    return Name.str().str();
+  }
+  if (isa<TranslationUnitDecl>(CurrentDecl) && IT == PrettyFunction) {
+    // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
+    return "top level";
+  }
+  return "";
+}
+
 /// getValueAsApproximateDouble - This returns the value as an inaccurate
 /// double.  Note that this may cause loss of precision, but is useful for
 /// debugging dumps, etc.
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 4a8253d..d39e10f 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -845,24 +845,13 @@
     GlobalVarName = "__FUNCTION__.";
     break;
   case PredefinedExpr::PrettyFunction:
-    // FIXME:: Demangle C++ method names
     GlobalVarName = "__PRETTY_FUNCTION__.";
     break;
   }
 
-  // FIXME: This isn't right at all.  The logic for computing this should go
-  // into a method on PredefinedExpr.  This would allow sema and codegen to be
-  // consistent for things like sizeof(__func__) etc.
-  std::string FunctionName;
-  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl)) {
-    FunctionName = CGM.getMangledName(FD);
-  } else {
-    // Just get the mangled name; skipping the asm prefix if it
-    // exists.
-    FunctionName = CurFn->getName();
-    if (FunctionName[0] == '\01')
-      FunctionName = FunctionName.substr(1, std::string::npos);
-  }
+  std::string FunctionName =
+    PredefinedExpr::ComputeName(getContext(), (PredefinedExpr::IdentType)Type, 
+                                CurCodeDecl);
 
   GlobalVarName += FunctionName;
   llvm::Constant *C = 
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 7d2e308..1770834 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1151,17 +1151,15 @@
 
   // Pre-defined identifiers are of type char[x], where x is the length of the
   // string.
-  unsigned Length;
-  if (FunctionDecl *FD = getCurFunctionDecl())
-    Length = FD->getIdentifier()->getLength();
-  else if (ObjCMethodDecl *MD = getCurMethodDecl())
-    Length = MD->getSynthesizedMethodSize();
-  else {
+  
+  Decl *currentDecl = getCurFunctionOrMethodDecl();
+  if (!currentDecl) {
     Diag(Loc, diag::ext_predef_outside_function);
-    // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
-    Length = IT == PredefinedExpr::PrettyFunction ? strlen("top level") : 0;
+    currentDecl = Context.getTranslationUnitDecl();
   }
 
+  unsigned Length =
+    PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
 
   llvm::APInt LengthI(32, Length + 1);
   QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);