]> granicus.if.org Git - clang/commitdiff
Give Type::getDesugaredType a "for-display" mode that can apply more
authorDouglas Gregor <dgregor@apple.com>
Wed, 1 Apr 2009 15:47:24 +0000 (15:47 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 1 Apr 2009 15:47:24 +0000 (15:47 +0000)
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

include/clang/AST/Type.h
lib/AST/Type.cpp
lib/Sema/Sema.cpp
test/SemaCXX/qualified-names-diag.cpp
test/SemaTemplate/qualified-names-diag.cpp
www/diagnostics.html

index c3195eb66809725531e033b1fffe7044af267a92..514c69e72c37946bf59cb528de29bea042eb2b7c 100644 (file)
@@ -162,7 +162,7 @@ public:
   /// 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 getDesugaredType() const;
+  QualType getDesugaredType(bool ForDisplay = false) const;
 
   /// operator==/!= - Indicate whether the specified types and qualifiers are
   /// identical.
@@ -461,7 +461,7 @@ public:
   /// 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 getDesugaredType() const;
+  QualType getDesugaredType(bool ForDisplay = false) const;
   
   /// More type predicates useful for type checking/promotion
   bool isPromotableIntegerType() const; // C99 6.3.1.1p2
index b9bd0bae046c80673fdda62b8942fd157ddaadfd..97245c699a4941d9a7be128c2152cbac81e518ec 100644 (file)
@@ -75,8 +75,13 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
 /// 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 @@ QualType QualType::getDesugaredType() const {
 /// 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 @@ QualType Type::getDesugaredType() const {
     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.
index 7e72a8453b6211fd0d4c2ca90ca236b762b4dd4c..f11ce2043a8ab6ceb6a78c2ccdb74fc9c6857131 100644 (file)
@@ -40,7 +40,7 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
     
     // If this is a sugared type (like a typedef, typeof, etc), then unwrap one
     // level of the sugar so that the type is more obvious to the user.
-    QualType DesugaredTy = Ty->getDesugaredType();
+    QualType DesugaredTy = Ty->getDesugaredType(true);
     DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() |
                                  Ty.getCVRQualifiers());
 
index a1591d01d4576b7e4773d3f2ca5418afebcfe94d..3bffd7c05d3bcfac85a938fc64c4f42515c7838a 100644 (file)
@@ -21,12 +21,12 @@ namespace bar {
 void test() {
   foo::wibble::x a;
   ::bar::y b;
-  a + b; // expected-error{{invalid operands to binary expression ('foo::wibble::x' (aka 'struct foo::wibble::x') and '::bar::y' (aka 'int'))}}
+  a + b; // expected-error{{invalid operands to binary expression ('foo::wibble::x' and '::bar::y' (aka 'int'))}}
 
   ::foo::wibble::bar::wonka::x::y c;
-  c + b; // expected-error{{invalid operands to binary expression ('::foo::wibble::bar::wonka::x::y' (aka 'struct foo::wibble::bar::wonka::x::y') and '::bar::y' (aka 'int'))}}
+  c + b; // expected-error{{invalid operands to binary expression ('::foo::wibble::bar::wonka::x::y' and '::bar::y' (aka 'int'))}}
 
-  (void)sizeof(bar::incomplete); // expected-error{{invalid application of 'sizeof' to an incomplete type 'bar::incomplete' (aka 'struct bar::incomplete')}}
+  (void)sizeof(bar::incomplete); // expected-error{{invalid application of 'sizeof' to an incomplete type 'bar::incomplete'}}
 }
 
 int ::foo::wibble::bar::wonka::x::y::* ptrmem;
index bf4ae1187696b625d412f42a4d3e114b60bd3049..4bc8bdfc9a84e81afdca14bde246fe1328cb2cf9 100644 (file)
@@ -12,5 +12,5 @@ void test() {
 
   std::vector<INT> v1;
   vector<Real> v2;
-  v1 = v2; // expected-error{{incompatible type assigning 'vector<Real>' (aka 'class std::vector<float>'), expected 'std::vector<INT>' (aka 'class std::vector<int>')}}
+  v1 = v2; // expected-error{{incompatible type assigning 'vector<Real>', expected 'std::vector<INT>'}}
 }
index 38c87728aec63a04e14dc872e128eb38a6488bd0..4f68f58d520f1d49d6a119e526fb86819e97d3bb 100644 (file)
@@ -156,6 +156,48 @@ is useful for the compiler to expose underlying details of a typedef:</p>
 <p>If the user was somehow confused about how the system "pid_t" typedef is
 defined, Clang helpfully displays it with "aka".</p>
 
+<p>In C++, type preservation includes retaining any qualification written into type names. For example, if we take a small snippet of code such as:
+
+<blockquote>
+<pre>
+namespace services {
+  struct WebService {  };
+}
+namespace myapp {
+  namespace servers {
+    struct Server {  };
+  }
+}
+
+using namespace myapp;
+void addHTTPService(servers::Server const &server, ::services::WebService const *http) {
+  server += http;
+}
+</pre>
+</blockquote>
+
+<p>and then compile it, we see that Clang is both providing more accurate information and is retaining the types as written by the user (e.g., "servers::Server", "::services::WebService"):
+
+<pre>
+  $ <b>g++-4.2 -fsyntax-only t.cpp</b>
+  t.cpp:9: error: no match for 'operator+=' in 'server += http'
+  $ <b>clang -fsyntax-only t.cpp</b>
+  t.cpp:9:10: error: invalid operands to binary expression ('servers::Server const' and '::services::WebService const *')
+    <font color="darkgreen">server += http;</font>
+    <font color="blue">~~~~~~ ^  ~~~~</font>
+</pre>
+
+<p>Naturally, type preservation extends to uses of templates, and Clang retains information about how a particular template specialization (like <code>std::vector&lt;Real&gt;</code>) was spelled within the source code. For example:</p>
+
+<pre>
+  $ <b>g++-4.2 -fsyntax-only t.cpp</b>
+  t.cpp:12: error: no match for 'operator=' in 'str = vec'
+  $ <b>clang -fsyntax-only t.cpp</b>
+  t.cpp:12:7: error: incompatible type assigning 'vector&lt;Real&gt;', expected 'std::string' (aka 'class std::basic_string&lt;char&gt;')
+    <font color="darkgreen">str = vec</font>;
+        <font color="blue">^ ~~~</font>
+</pre>
+
 <h2>Fix-it Hints</h2>
 
 <p>simple example + template&lt;&gt; example</p>
@@ -203,11 +245,6 @@ implements the "wwopen" class of APIs):</p>
 <p>In practice, we've found that this is actually more useful in multiply nested
 macros that in simple ones.</p>
 
-<h2>C++ Fun Examples</h2>
-
-<p>...</p>
-
-
 </div>
 </body>
 </html>