[clang-tools-extra] ec64d10 - [clangd] Add desugared type to hover

via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 7 21:28:49 PST 2021


Author: lh123
Date: 2021-12-08T13:28:12+08:00
New Revision: ec64d10340daacb066ab1bbf6356727062a8236f

URL: https://github.com/llvm/llvm-project/commit/ec64d10340daacb066ab1bbf6356727062a8236f
DIFF: https://github.com/llvm/llvm-project/commit/ec64d10340daacb066ab1bbf6356727062a8236f.diff

LOG: [clangd] Add desugared type to hover

Add desugared type to hover when the desugared type and the pretty-printed type are different.

```c++
template<typename T>
struct TestHover {
  using Type = T;
};

int main() {
  TestHover<int>::Type a;
}
```

```
variable a

Type: TestHover<int>::Type (aka int)
```

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D114522

Added: 
    

Modified: 
    clang-tools-extra/clangd/Hover.cpp
    clang-tools-extra/clangd/Hover.h
    clang-tools-extra/clangd/unittests/HoverTests.cpp
    clang/include/clang/AST/ASTDiagnostic.h
    clang/lib/AST/ASTDiagnostic.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 16a7d58325810..143bd4f8785ab 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -18,6 +18,7 @@
 #include "support/Logger.h"
 #include "support/Markup.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
@@ -46,6 +47,7 @@
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/raw_ostream.h"
 #include <string>
 
@@ -138,14 +140,15 @@ const char *getMarkdownLanguage(const ASTContext &Ctx) {
   return LangOpts.ObjC ? "objective-c" : "cpp";
 }
 
-std::string printType(QualType QT, const PrintingPolicy &PP) {
+HoverInfo::PrintedType printType(QualType QT, ASTContext &ASTCtx,
+                                 const PrintingPolicy &PP) {
   // TypePrinter doesn't resolve decltypes, so resolve them here.
   // FIXME: This doesn't handle composite types that contain a decltype in them.
   // We should rather have a printing policy for that.
   while (!QT.isNull() && QT->isDecltypeType())
     QT = QT->getAs<DecltypeType>()->getUnderlyingType();
-  std::string Result;
-  llvm::raw_string_ostream OS(Result);
+  HoverInfo::PrintedType Result;
+  llvm::raw_string_ostream OS(Result.Type);
   // Special case: if the outer type is a tag type without qualifiers, then
   // include the tag for extra clarity.
   // This isn't very idiomatic, so don't attempt it for complex cases, including
@@ -154,46 +157,57 @@ std::string printType(QualType QT, const PrintingPolicy &PP) {
     if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr()))
       OS << TT->getDecl()->getKindName() << " ";
   }
-  OS.flush();
   QT.print(OS, PP);
+  OS.flush();
+  if (!QT.isNull()) {
+    bool ShouldAKA = false;
+    QualType DesugaredTy = clang::desugarForDiagnostic(ASTCtx, QT, ShouldAKA);
+    if (ShouldAKA)
+      Result.AKA = DesugaredTy.getAsString(PP);
+  }
   return Result;
 }
 
-std::string printType(const TemplateTypeParmDecl *TTP) {
-  std::string Res = TTP->wasDeclaredWithTypename() ? "typename" : "class";
+HoverInfo::PrintedType printType(const TemplateTypeParmDecl *TTP) {
+  HoverInfo::PrintedType Result;
+  Result.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
   if (TTP->isParameterPack())
-    Res += "...";
-  return Res;
+    Result.Type += "...";
+  return Result;
 }
 
-std::string printType(const NonTypeTemplateParmDecl *NTTP,
-                      const PrintingPolicy &PP) {
-  std::string Res = printType(NTTP->getType(), PP);
-  if (NTTP->isParameterPack())
-    Res += "...";
-  return Res;
+HoverInfo::PrintedType printType(const NonTypeTemplateParmDecl *NTTP,
+                                 const PrintingPolicy &PP) {
+  auto PrintedType = printType(NTTP->getType(), NTTP->getASTContext(), PP);
+  if (NTTP->isParameterPack()) {
+    PrintedType.Type += "...";
+    if (PrintedType.AKA)
+      *PrintedType.AKA += "...";
+  }
+  return PrintedType;
 }
 
-std::string printType(const TemplateTemplateParmDecl *TTP,
-                      const PrintingPolicy &PP) {
-  std::string Res;
-  llvm::raw_string_ostream OS(Res);
+HoverInfo::PrintedType printType(const TemplateTemplateParmDecl *TTP,
+                                 const PrintingPolicy &PP) {
+  HoverInfo::PrintedType Result;
+  llvm::raw_string_ostream OS(Result.Type);
   OS << "template <";
   llvm::StringRef Sep = "";
   for (const Decl *Param : *TTP->getTemplateParameters()) {
     OS << Sep;
     Sep = ", ";
     if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
-      OS << printType(TTP);
+      OS << printType(TTP).Type;
     else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
-      OS << printType(NTTP, PP);
+      OS << printType(NTTP, PP).Type;
     else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param))
-      OS << printType(TTPD, PP);
+      OS << printType(TTPD, PP).Type;
   }
   // FIXME: TemplateTemplateParameter doesn't store the info on whether this
   // param was a "typename" or "class".
   OS << "> class";
-  return OS.str();
+  OS.flush();
+  return Result;
 }
 
 std::vector<HoverInfo::Param>
@@ -329,7 +343,7 @@ const Expr *getDefaultArg(const ParmVarDecl *PVD) {
 HoverInfo::Param toHoverInfoParam(const ParmVarDecl *PVD,
                                   const PrintingPolicy &PP) {
   HoverInfo::Param Out;
-  Out.Type = printType(PVD->getType(), PP);
+  Out.Type = printType(PVD->getType(), PVD->getASTContext(), PP);
   if (!PVD->getName().empty())
     Out.Name = PVD->getNameAsString();
   if (const Expr *DefArg = getDefaultArg(PVD)) {
@@ -356,11 +370,11 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
       NK == DeclarationName::CXXConversionFunctionName)
     return;
 
-  HI.ReturnType = printType(FD->getReturnType(), PP);
+  HI.ReturnType = printType(FD->getReturnType(), FD->getASTContext(), PP);
   QualType QT = FD->getType();
   if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas
     QT = VD->getType().getDesugaredType(D->getASTContext());
-  HI.Type = printType(QT, PP);
+  HI.Type = printType(QT, D->getASTContext(), PP);
   // FIXME: handle variadics.
 }
 
@@ -589,13 +603,19 @@ HoverInfo getHoverContents(const NamedDecl *D, const PrintingPolicy &PP,
   if (const FunctionDecl *FD = getUnderlyingFunction(D))
     fillFunctionTypeAndParams(HI, D, FD, PP);
   else if (const auto *VD = dyn_cast<ValueDecl>(D))
-    HI.Type = printType(VD->getType(), PP);
+    HI.Type = printType(VD->getType(), VD->getASTContext(), PP);
   else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
     HI.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
   else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D))
     HI.Type = printType(TTP, PP);
   else if (const auto *VT = dyn_cast<VarTemplateDecl>(D))
-    HI.Type = printType(VT->getTemplatedDecl()->getType(), PP);
+    HI.Type =
+        printType(VT->getTemplatedDecl()->getType(), VT->getASTContext(), PP);
+  else if (const auto *TN = dyn_cast<TypedefNameDecl>(D))
+    HI.Type = printType(TN->getUnderlyingType(), TN->getASTContext(), PP);
+  else if (const auto *TAT = dyn_cast<TypeAliasTemplateDecl>(D))
+    HI.Type = printType(TAT->getTemplatedDecl()->getUnderlyingType(),
+                        TAT->getASTContext(), PP);
 
   // Fill in value with evaluated initializer if possible.
   if (const auto *Var = dyn_cast<VarDecl>(D)) {
@@ -646,6 +666,16 @@ HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
   return HI;
 }
 
+std::string typeAsDefinition(const HoverInfo::PrintedType &PType) {
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  OS << PType.Type;
+  if (PType.AKA)
+    OS << " // aka: " << *PType.AKA;
+  OS.flush();
+  return Result;
+}
+
 llvm::Optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE,
                                                    ASTContext &ASTCtx,
                                                    const PrintingPolicy &PP) {
@@ -660,7 +690,7 @@ llvm::Optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE,
 
   HoverInfo HI;
   HI.Name = "this";
-  HI.Definition = printType(PrettyThisType, PP);
+  HI.Definition = typeAsDefinition(printType(PrettyThisType, ASTCtx, PP));
   return HI;
 }
 
@@ -677,7 +707,7 @@ HoverInfo getDeducedTypeHoverContents(QualType QT, const syntax::Token &Tok,
   if (QT->isUndeducedAutoType()) {
     HI.Definition = "/* not deduced */";
   } else {
-    HI.Definition = printType(QT, PP);
+    HI.Definition = typeAsDefinition(printType(QT, ASTCtx, PP));
 
     if (const auto *D = QT->getAsTagDecl()) {
       const auto *CommentD = getDeclForComment(D);
@@ -728,7 +758,7 @@ llvm::Optional<HoverInfo> getHoverContents(const Expr *E, ParsedAST &AST,
   // For expressions we currently print the type and the value, iff it is
   // evaluatable.
   if (auto Val = printExprValue(E, AST.getASTContext())) {
-    HI.Type = printType(E->getType(), PP);
+    HI.Type = printType(E->getType(), AST.getASTContext(), PP);
     HI.Value = *Val;
     HI.Name = std::string(getNameForExpr(E));
     return HI;
@@ -1059,24 +1089,22 @@ markup::Document HoverInfo::present() const {
     // Parameters:
     // - `bool param1`
     // - `int param2 = 5`
-    Output.addParagraph().appendText("→ ").appendCode(*ReturnType);
+    Output.addParagraph().appendText("→ ").appendCode(
+        llvm::to_string(*ReturnType));
   }
 
   if (Parameters && !Parameters->empty()) {
     Output.addParagraph().appendText("Parameters: ");
     markup::BulletList &L = Output.addBulletList();
-    for (const auto &Param : *Parameters) {
-      std::string Buffer;
-      llvm::raw_string_ostream OS(Buffer);
-      OS << Param;
-      L.addItem().addParagraph().appendCode(std::move(OS.str()));
-    }
+    for (const auto &Param : *Parameters)
+      L.addItem().addParagraph().appendCode(llvm::to_string(Param));
   }
 
   // Don't print Type after Parameters or ReturnType as this will just duplicate
   // the information
   if (Type && !ReturnType && !Parameters)
-    Output.addParagraph().appendText("Type: ").appendCode(*Type);
+    Output.addParagraph().appendText("Type: ").appendCode(
+        llvm::to_string(*Type));
 
   if (Value) {
     markup::Paragraph &P = Output.addParagraph();
@@ -1109,7 +1137,7 @@ markup::Document HoverInfo::present() const {
     if (CalleeArgInfo->Name)
       OS << "as " << CalleeArgInfo->Name;
     if (CallPassType->Converted && CalleeArgInfo->Type)
-      OS << " (converted to " << CalleeArgInfo->Type << ")";
+      OS << " (converted to " << CalleeArgInfo->Type->Type << ")";
     Output.addParagraph().appendText(OS.str());
   }
 
@@ -1217,16 +1245,24 @@ void parseDocumentation(llvm::StringRef Input, markup::Document &Output) {
   FlushParagraph();
 }
 
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                              const HoverInfo::PrintedType &T) {
+  OS << T.Type;
+  if (T.AKA)
+    OS << " (aka " << *T.AKA << ")";
+  return OS;
+}
+
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
                               const HoverInfo::Param &P) {
-  std::vector<llvm::StringRef> Output;
   if (P.Type)
-    Output.push_back(*P.Type);
+    OS << P.Type->Type;
   if (P.Name)
-    Output.push_back(*P.Name);
-  OS << llvm::join(Output, " ");
+    OS << " " << *P.Name;
   if (P.Default)
     OS << " = " << *P.Default;
+  if (P.Type && P.Type->AKA)
+    OS << " (aka " << *P.Type->AKA << ")";
   return OS;
 }
 

diff  --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h
index 4e6314dfc5ed6..7478ede88a46c 100644
--- a/clang-tools-extra/clangd/Hover.h
+++ b/clang-tools-extra/clangd/Hover.h
@@ -22,15 +22,28 @@ namespace clangd {
 /// embedding clients can use the structured information to provide their own
 /// UI.
 struct HoverInfo {
+  /// Contains pretty-printed type and desugared type
+  struct PrintedType {
+    PrintedType() = default;
+    PrintedType(const char *Type) : Type(Type) {}
+    PrintedType(const char *Type, const char *AKAType)
+        : Type(Type), AKA(AKAType) {}
+
+    /// Pretty-printed type
+    std::string Type;
+    /// Desugared type
+    llvm::Optional<std::string> AKA;
+  };
+
   /// Represents parameters of a function, a template or a macro.
   /// For example:
   /// - void foo(ParamType Name = DefaultValue)
   /// - #define FOO(Name)
   /// - template <ParamType Name = DefaultType> class Foo {};
   struct Param {
-    /// The pretty-printed parameter type, e.g. "int", or "typename" (in
+    /// The printable parameter type, e.g. "int", or "typename" (in
     /// TemplateParameters), might be None for macro parameters.
-    llvm::Optional<std::string> Type;
+    llvm::Optional<PrintedType> Type;
     /// None for unnamed parameters.
     llvm::Optional<std::string> Name;
     /// None if no default is provided.
@@ -62,11 +75,11 @@ struct HoverInfo {
   /// Access specifier for declarations inside class/struct/unions, empty for
   /// others.
   std::string AccessSpecifier;
-  /// Pretty-printed variable type.
+  /// Printable variable type.
   /// Set only for variables.
-  llvm::Optional<std::string> Type;
+  llvm::Optional<PrintedType> Type;
   /// Set for functions and lambdas.
-  llvm::Optional<std::string> ReturnType;
+  llvm::Optional<PrintedType> ReturnType;
   /// Set for functions, lambdas and macros with parameters.
   llvm::Optional<std::vector<Param>> Parameters;
   /// Set for all templates(function, class, variable).
@@ -98,6 +111,11 @@ struct HoverInfo {
   markup::Document present() const;
 };
 
+inline bool operator==(const HoverInfo::PrintedType &LHS,
+                       const HoverInfo::PrintedType &RHS) {
+  return std::tie(LHS.Type, LHS.AKA) == std::tie(RHS.Type, RHS.AKA);
+}
+
 inline bool operator==(const HoverInfo::PassType &LHS,
                        const HoverInfo::PassType &RHS) {
   return std::tie(LHS.PassBy, LHS.Converted) ==
@@ -108,6 +126,8 @@ inline bool operator==(const HoverInfo::PassType &LHS,
 // FIXME: move to another file so CodeComplete doesn't depend on Hover.
 void parseDocumentation(llvm::StringRef Input, markup::Document &Output);
 
+llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+                              const HoverInfo::PrintedType &);
 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const HoverInfo::Param &);
 inline bool operator==(const HoverInfo::Param &LHS,
                        const HoverInfo::Param &RHS) {

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 5376750b25b49..0d7c227f04711 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -211,12 +211,13 @@ TEST(Hover, Structured) {
           bool Q = false, class... Ts>
 class Foo {})cpp";
          HI.TemplateParameters = {
-             {std::string("template <typename, bool...> class"),
-              std::string("C"), llvm::None},
-             {std::string("typename"), llvm::None, std::string("char")},
-             {std::string("int"), llvm::None, std::string("0")},
-             {std::string("bool"), std::string("Q"), std::string("false")},
-             {std::string("class..."), std::string("Ts"), llvm::None},
+             {{"template <typename, bool...> class"},
+              std::string("C"),
+              llvm::None},
+             {{"typename"}, llvm::None, std::string("char")},
+             {{"int"}, llvm::None, std::string("0")},
+             {{"bool"}, std::string("Q"), std::string("false")},
+             {{"class..."}, std::string("Ts"), llvm::None},
          };
        }},
       // Function template
@@ -258,8 +259,8 @@ class Foo {})cpp";
          HI.ReturnType = "Foo<bool, true, false>";
          HI.Type = "Foo<bool, true, false> (int, bool)";
          HI.Parameters = {
-             {std::string("int"), llvm::None, llvm::None},
-             {std::string("bool"), std::string("T"), std::string("false")},
+             {{"int"}, llvm::None, llvm::None},
+             {{"bool"}, std::string("T"), std::string("false")},
          };
        }},
       // Pointers to lambdas
@@ -279,8 +280,8 @@ class Foo {})cpp";
          HI.Type = "(lambda) **";
          HI.ReturnType = "bool";
          HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
+             {{"int"}, std::string("T"), llvm::None},
+             {{"bool"}, std::string("B"), llvm::None},
          };
          return HI;
        }},
@@ -297,11 +298,11 @@ class Foo {})cpp";
          HI.Name = "bar";
          HI.Kind = index::SymbolKind::Parameter;
          HI.Definition = "decltype(lamb) &bar";
-         HI.Type = "decltype(lamb) &";
+         HI.Type = {"decltype(lamb) &", "(lambda) &"};
          HI.ReturnType = "bool";
          HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
+             {{"int"}, std::string("T"), llvm::None},
+             {{"bool"}, std::string("B"), llvm::None},
          };
          return HI;
        }},
@@ -321,8 +322,8 @@ class Foo {})cpp";
          HI.Type = "class (lambda)";
          HI.ReturnType = "bool";
          HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
+             {{"int"}, std::string("T"), llvm::None},
+             {{"bool"}, std::string("B"), llvm::None},
          };
          HI.Value = "false";
          return HI;
@@ -344,8 +345,8 @@ class Foo {})cpp";
          HI.Type = "class (lambda)";
          HI.ReturnType = "bool";
          HI.Parameters = {
-             {std::string("int"), std::string("T"), llvm::None},
-             {std::string("bool"), std::string("B"), llvm::None},
+             {{"int"}, std::string("T"), llvm::None},
+             {{"bool"}, std::string("B"), llvm::None},
          };
          return HI;
        }},
@@ -569,15 +570,16 @@ class Foo {})cpp";
          HI.AccessSpecifier = "public";
        }},
       {R"cpp(
-        constexpr int answer() { return 40 + 2; }
+        using my_int = int;
+        constexpr my_int answer() { return 40 + 2; }
         int x = [[ans^wer]]();
         )cpp",
        [](HoverInfo &HI) {
          HI.Name = "answer";
-         HI.Definition = "constexpr int answer()";
+         HI.Definition = "constexpr my_int answer()";
          HI.Kind = index::SymbolKind::Function;
-         HI.Type = "int ()";
-         HI.ReturnType = "int";
+         HI.Type = {"my_int ()", "int ()"};
+         HI.ReturnType = {"my_int", "int"};
          HI.Parameters.emplace();
          HI.NamespaceScope = "";
          HI.Value = "42 (0x2a)";
@@ -930,6 +932,71 @@ class Foo {})cpp";
          HI.Type = "m_int[4]";
          HI.NamespaceScope = "";
          HI.Definition = "m_int arr[4]";
+       }},
+      {// Canonical type
+       R"cpp(
+          template<typename T>
+          struct TestHover {
+            using Type = T;
+          };
+
+          void code() {
+            TestHover<int>::Type ^[[a]];
+          }
+         )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "a";
+         HI.NamespaceScope = "";
+         HI.LocalScope = "code::";
+         HI.Definition = "TestHover<int>::Type a";
+         HI.Kind = index::SymbolKind::Variable;
+         HI.Type = {"TestHover<int>::Type", "int"};
+       }},
+      {// Canonical template type
+       R"cpp(
+          template<typename T>
+          void ^[[foo]](T arg) {}
+         )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "foo";
+         HI.Kind = index::SymbolKind::Function;
+         HI.NamespaceScope = "";
+         HI.Definition = "template <typename T> void foo(T arg)";
+         HI.Type = "void (T)";
+         HI.ReturnType = "void";
+         HI.Parameters = {{{"T"}, std::string("arg"), llvm::None}};
+         HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}};
+       }},
+      {// TypeAlias Template
+       R"cpp(
+          template<typename T>
+          using ^[[alias]] = T;
+         )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "alias";
+         HI.NamespaceScope = "";
+         HI.LocalScope = "";
+         HI.Kind = index::SymbolKind::TypeAlias;
+         HI.Definition = "template <typename T> using alias = T";
+         HI.Type = "T";
+         HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}};
+       }},
+      {// TypeAlias Template
+       R"cpp(
+          template<typename T>
+          using A = T;
+
+          template<typename T>
+          using ^[[AA]] = A<T>;
+         )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "AA";
+         HI.NamespaceScope = "";
+         HI.LocalScope = "";
+         HI.Kind = index::SymbolKind::TypeAlias;
+         HI.Definition = "template <typename T> using AA = A<T>";
+         HI.Type = {"A<T>", "type-parameter-0-0"}; // FIXME: should be 'T'
+         HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}};
        }}};
   for (const auto &Case : Cases) {
     SCOPED_TRACE(Case.Code);
@@ -1227,7 +1294,7 @@ TEST(Hover, All) {
             HI.Documentation = "Function definition via pointer";
             HI.ReturnType = "void";
             HI.Parameters = {
-                {std::string("int"), llvm::None, llvm::None},
+                {{"int"}, llvm::None, llvm::None},
             };
           }},
       {
@@ -1246,7 +1313,7 @@ TEST(Hover, All) {
             HI.Documentation = "Function declaration via call";
             HI.ReturnType = "int";
             HI.Parameters = {
-                {std::string("int"), llvm::None, llvm::None},
+                {{"int"}, llvm::None, llvm::None},
             };
           }},
       {
@@ -1390,8 +1457,8 @@ TEST(Hover, All) {
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.NamespaceScope = "";
             HI.Definition = "typedef int Foo";
+            HI.Type = "int";
             HI.Documentation = "Typedef";
-            // FIXME: Maybe put underlying type into HI.Type for aliases?
           }},
       {
           R"cpp(// Typedef with embedded definition
@@ -1405,6 +1472,7 @@ TEST(Hover, All) {
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.NamespaceScope = "";
             HI.Definition = "typedef struct Bar Foo";
+            HI.Type = "struct Bar";
             HI.Documentation = "Typedef with embedded definition";
           }},
       {
@@ -2053,7 +2121,7 @@ TEST(Hover, All) {
           [](HoverInfo &HI) {
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
-            HI.Definition = "int_type";
+            HI.Definition = "int_type // aka: int";
           }},
       {
           R"cpp(// auto on alias
@@ -2064,7 +2132,7 @@ TEST(Hover, All) {
           [](HoverInfo &HI) {
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
-            HI.Definition = "cls_type";
+            HI.Definition = "cls_type // aka: cls";
             HI.Documentation = "auto on alias";
           }},
       {
@@ -2215,10 +2283,10 @@ TEST(Hover, All) {
             HI.Name = "foo";
             // FIXME: Handle composite types with decltype with a printing
             // policy.
-            HI.Type = "auto (decltype(a)) -> decltype(a)";
+            HI.Type = {"auto (decltype(a)) -> decltype(a)",
+                       "auto (int) -> int"};
             HI.ReturnType = "int";
-            HI.Parameters = {
-                {std::string("int"), std::string("x"), llvm::None}};
+            HI.Parameters = {{{"int"}, std::string("x"), llvm::None}};
           }},
       {
           R"cpp(// sizeof expr
@@ -2251,8 +2319,7 @@ TEST(Hover, All) {
             HI.Kind = index::SymbolKind::Function;
             HI.Type = "void (const int &)";
             HI.ReturnType = "void";
-            HI.Parameters = {
-                {std::string("const int &"), llvm::None, std::string("T()")}};
+            HI.Parameters = {{{"const int &"}, llvm::None, std::string("T()")}};
             HI.Definition = "template <> void foo<int>(const int &)";
             HI.NamespaceScope = "";
           }},
@@ -2609,9 +2676,8 @@ TEST(Hover, Present) {
             HI.Kind = index::SymbolKind::Class;
             HI.Size = 10;
             HI.TemplateParameters = {
-                {std::string("typename"), std::string("T"), llvm::None},
-                {std::string("typename"), std::string("C"),
-                 std::string("bool")},
+                {{"typename"}, std::string("T"), llvm::None},
+                {{"typename"}, std::string("C"), std::string("bool")},
             };
             HI.Documentation = "documentation";
             HI.Definition =
@@ -2630,12 +2696,12 @@ template <typename T, typename C = bool> class Foo {})",
           [](HoverInfo &HI) {
             HI.Kind = index::SymbolKind::Function;
             HI.Name = "foo";
-            HI.Type = "type";
-            HI.ReturnType = "ret_type";
+            HI.Type = {"type", "c_type"};
+            HI.ReturnType = {"ret_type", "can_ret_type"};
             HI.Parameters.emplace();
             HoverInfo::Param P;
             HI.Parameters->push_back(P);
-            P.Type = "type";
+            P.Type = {"type", "can_type"};
             HI.Parameters->push_back(P);
             P.Name = "foo";
             HI.Parameters->push_back(P);
@@ -2646,12 +2712,12 @@ template <typename T, typename C = bool> class Foo {})",
           },
           "function foo\n"
           "\n"
-          "→ ret_type\n"
+          "→ ret_type (aka can_ret_type)\n"
           "Parameters:\n"
           "- \n"
-          "- type\n"
-          "- type foo\n"
-          "- type foo = default\n"
+          "- type (aka can_type)\n"
+          "- type foo (aka can_type)\n"
+          "- type foo = default (aka can_type)\n"
           "\n"
           "// In namespace ns\n"
           "ret_type foo(params) {}",
@@ -2662,7 +2728,7 @@ template <typename T, typename C = bool> class Foo {})",
             HI.LocalScope = "test::Bar::";
             HI.Value = "value";
             HI.Name = "foo";
-            HI.Type = "type";
+            HI.Type = {"type", "can_type"};
             HI.Definition = "def";
             HI.Size = 4;
             HI.Offset = 12;
@@ -2670,7 +2736,7 @@ template <typename T, typename C = bool> class Foo {})",
           },
           R"(field foo
 
-Type: type
+Type: type (aka can_type)
 Value = value
 Offset: 12 bytes
 Size: 4 bytes (+4 padding)
@@ -2693,22 +2759,22 @@ public: def)",
       },
       {
           [](HoverInfo &HI) {
-            HI.Definition = "int method()";
+            HI.Definition = "size_t method()";
             HI.AccessSpecifier = "protected";
             HI.Kind = index::SymbolKind::InstanceMethod;
             HI.NamespaceScope = "";
             HI.LocalScope = "cls<int>::";
             HI.Name = "method";
             HI.Parameters.emplace();
-            HI.ReturnType = "int";
-            HI.Type = "int ()";
+            HI.ReturnType = {"size_t", "unsigned long"};
+            HI.Type = {"size_t ()", "unsigned long ()"};
           },
           R"(instance-method method
 
-→ int
+→ size_t (aka unsigned long)
 
 // In cls<int>
-protected: int method())",
+protected: size_t method())",
       },
       {
           [](HoverInfo &HI) {
@@ -2809,7 +2875,7 @@ int foo = 3)",
             HI.Type = "int";
             HI.CalleeArgInfo.emplace();
             HI.CalleeArgInfo->Name = "arg_a";
-            HI.CalleeArgInfo->Type = "int";
+            HI.CalleeArgInfo->Type = {"alias_int", "int"};
             HI.CalleeArgInfo->Default = "7";
             HI.CallPassType.emplace();
             HI.CallPassType->PassBy = PassMode::Value;
@@ -2819,7 +2885,7 @@ int foo = 3)",
 
 Type: int
 Value = 3
-Passed as arg_a (converted to int)
+Passed as arg_a (converted to alias_int)
 
 // In test::Bar
 int foo = 3)",

diff  --git a/clang/include/clang/AST/ASTDiagnostic.h b/clang/include/clang/AST/ASTDiagnostic.h
index d6549e12d92ac..4cd9097517258 100644
--- a/clang/include/clang/AST/ASTDiagnostic.h
+++ b/clang/include/clang/AST/ASTDiagnostic.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_AST_ASTDIAGNOSTIC_H
 #define LLVM_CLANG_AST_ASTDIAGNOSTIC_H
 
+#include "clang/AST/Type.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticAST.h"
 
@@ -31,6 +32,11 @@ namespace clang {
       SmallVectorImpl<char> &Output,
       void *Cookie,
       ArrayRef<intptr_t> QualTypeVals);
+
+  /// Returns a desugared version of the QualType, and marks ShouldAKA as true
+  /// whenever we remove significant sugar from the type.
+  QualType desugarForDiagnostic(ASTContext &Context, QualType QT,
+                                bool &ShouldAKA);
 }  // end namespace clang
 
 #endif

diff  --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 7e435e8b35b80..e1b517db28ac9 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -26,7 +26,8 @@ using namespace clang;
 
 // Returns a desugared version of the QualType, and marks ShouldAKA as true
 // whenever we remove significant sugar from the type.
-static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
+QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
+                                     bool &ShouldAKA) {
   QualifierCollector QC;
 
   while (true) {
@@ -76,7 +77,7 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
     if (const FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
       bool DesugarReturn = false;
       QualType SugarRT = FT->getReturnType();
-      QualType RT = Desugar(Context, SugarRT, DesugarReturn);
+      QualType RT = desugarForDiagnostic(Context, SugarRT, DesugarReturn);
       if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) {
         RT = Context.getAttributedType(
             AttributedType::getNullabilityAttrKind(*nullability), RT, RT);
@@ -87,7 +88,7 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
       const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT);
       if (FPT) {
         for (QualType SugarPT : FPT->param_types()) {
-          QualType PT = Desugar(Context, SugarPT, DesugarArgument);
+          QualType PT = desugarForDiagnostic(Context, SugarPT, DesugarArgument);
           if (auto nullability =
                   AttributedType::stripOuterNullability(SugarPT)) {
             PT = Context.getAttributedType(
@@ -115,7 +116,8 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
         for (unsigned I = 0, N = TST->getNumArgs(); I != N; ++I) {
           const TemplateArgument &Arg = TST->getArg(I);
           if (Arg.getKind() == TemplateArgument::Type)
-            Args.push_back(Desugar(Context, Arg.getAsType(), DesugarArgument));
+            Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(),
+                                                DesugarArgument));
           else
             Args.push_back(Arg);
         }
@@ -181,24 +183,25 @@ break; \
   // If we have a pointer-like type, desugar the pointee as well.
   // FIXME: Handle other pointer-like types.
   if (const PointerType *Ty = QT->getAs<PointerType>()) {
-    QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
-                                        ShouldAKA));
+    QT = Context.getPointerType(
+        desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
   } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) {
-    QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(),
-                                                  ShouldAKA));
+    QT = Context.getObjCObjectPointerType(
+        desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
   } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
-    QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
-                                                ShouldAKA));
+    QT = Context.getLValueReferenceType(
+        desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
   } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
-    QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(),
-                                                ShouldAKA));
+    QT = Context.getRValueReferenceType(
+        desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
   } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) {
     if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) {
-      QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA);
-      QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(),
-                                     llvm::makeArrayRef(Ty->qual_begin(),
-                                                        Ty->getNumProtocols()),
-                                     Ty->isKindOfTypeAsWritten());
+      QualType BaseType =
+          desugarForDiagnostic(Context, Ty->getBaseType(), ShouldAKA);
+      QT = Context.getObjCObjectType(
+          BaseType, Ty->getTypeArgsAsWritten(),
+          llvm::makeArrayRef(Ty->qual_begin(), Ty->getNumProtocols()),
+          Ty->isKindOfTypeAsWritten());
     }
   }
 
@@ -251,7 +254,8 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
       continue;  // Same canonical types
     std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy());
     bool ShouldAKA = false;
-    QualType CompareDesugar = Desugar(Context, CompareTy, ShouldAKA);
+    QualType CompareDesugar =
+        desugarForDiagnostic(Context, CompareTy, ShouldAKA);
     std::string CompareDesugarStr =
         CompareDesugar.getAsString(Context.getPrintingPolicy());
     if (CompareS != S && CompareDesugarStr != S)
@@ -286,7 +290,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
   // sugar gives us something "significantly 
diff erent".
   if (!Repeated) {
     bool ShouldAKA = false;
-    QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA);
+    QualType DesugaredTy = desugarForDiagnostic(Context, Ty, ShouldAKA);
     if (ShouldAKA || ForceAKA) {
       if (DesugaredTy == Ty) {
         DesugaredTy = Ty.getCanonicalType();


        


More information about the cfe-commits mailing list