Give Type::getDesugaredType a "for-display" mode that can apply more
heuristics to determine when it's useful to desugar a type for display
to the user. Introduce two C++-specific heuristics:

  - For a qualified type (like "foo::bar"), only produce a new
    desugred type if desugaring the qualified type ("bar", in this
    case) produces something interesting. For example, if "foo::bar"
    refers to a class named "bar", don't desugar. However, if
    "foo::bar" refers to a typedef of something else, desugar to that
    something else. This gives some useful desugaring such as
    "foo::bar (aka 'int')".
  - Don't desugar class template specialization types like
    "basic_string<char>" down to their underlying "class
    basic_string<char, char_traits<char>, allocator<char>>, etc.";
    it's better just to leave such types alone. 

Update diagnostics.html with some discussion and examples of type
preservation in C++, showing qualified names and class template
specialization types.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68207 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index b9bd0ba..97245c6 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -75,8 +75,13 @@
 /// to getting the canonical type, but it doesn't remove *all* typedefs.  For
 /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
 /// concrete.
-QualType QualType::getDesugaredType() const {
-  return getTypePtr()->getDesugaredType()
+///
+/// \param ForDisplay When true, the desugaring is provided for
+/// display purposes only. In this case, we apply more heuristics to
+/// decide whether it is worth providing a desugared form of the type
+/// or not.
+QualType QualType::getDesugaredType(bool ForDisplay) const {
+  return getTypePtr()->getDesugaredType(ForDisplay)
      .getWithAdditionalQualifiers(getCVRQualifiers());
 }
 
@@ -86,7 +91,12 @@
 /// to getting the canonical type, but it doesn't remove *all* typedefs.  For
 /// example, it return "T*" as "T*", (not as "int*"), because the pointer is
 /// concrete.
-QualType Type::getDesugaredType() const {
+///
+/// \param ForDisplay When true, the desugaring is provided for
+/// display purposes only. In this case, we apply more heuristics to
+/// decide whether it is worth providing a desugared form of the type
+/// or not.
+QualType Type::getDesugaredType(bool ForDisplay) const {
   if (const TypedefType *TDT = dyn_cast<TypedefType>(this))
     return TDT->LookThroughTypedefs().getDesugaredType();
   if (const TypeOfExprType *TOE = dyn_cast<TypeOfExprType>(this))
@@ -95,16 +105,26 @@
     return TOT->getUnderlyingType().getDesugaredType();
   if (const TemplateSpecializationType *Spec 
         = dyn_cast<TemplateSpecializationType>(this)) {
+    if (ForDisplay)
+      return QualType(this, 0);
+
     QualType Canon = Spec->getCanonicalTypeInternal();
     if (Canon->getAsTemplateSpecializationType())
       return QualType(this, 0);
     return Canon->getDesugaredType();
   }
-  if (const QualifiedNameType *QualName  = dyn_cast<QualifiedNameType>(this))
-    return QualName->getNamedType().getDesugaredType();
+  if (const QualifiedNameType *QualName  = dyn_cast<QualifiedNameType>(this)) {
+    if (ForDisplay) {
+      // If desugaring the type that the qualified name is referring to
+      // produces something interesting, that's our desugared type.
+      QualType NamedType = QualName->getNamedType().getDesugaredType();
+      if (NamedType != QualName->getNamedType())
+        return NamedType;
+    } else
+      return QualName->getNamedType().getDesugaredType();
+  }
 
-  // FIXME: remove this cast.
-  return QualType(const_cast<Type*>(this), 0);
+  return QualType(this, 0);
 }
 
 /// isVoidType - Helper method to determine if this is the 'void' type.