[llvm-branch-commits] [clang-tools-extra] c46c7c9 - [clangd] Smarter hover on auto and decltype

Sam McCall via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Dec 18 07:32:11 PST 2020


Author: Quentin Chateau
Date: 2020-12-18T16:27:09+01:00
New Revision: c46c7c9bcf9752971fe4bbcf67140c99066ad2e0

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

LOG: [clangd] Smarter hover on auto and decltype

Only show the keyword as the hover "Name".

Show whether the type is deduced or undeduced as
the hover "Documentation".

Show the deduced type (if any) as the "Definition".

Don't show any hover information for:
- the "auto" word of "decltype(auto)"
- "auto" in lambda parameters
- "auto" in template arguments

---------------

This diff is a suggestion based on what @sammccall  suggested in https://reviews.llvm.org/D92977 about hover on "auto". It somehow "hacks" onto the "Documentation" and "Definition" fields of `HoverInfo`. It sure looks good on VSCode, let me know if this seem acceptable to you.

Reviewed By: sammccall

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

Added: 
    

Modified: 
    clang-tools-extra/clangd/AST.cpp
    clang-tools-extra/clangd/AST.h
    clang-tools-extra/clangd/Hover.cpp
    clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
    clang-tools-extra/clangd/unittests/HoverTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index b0c9ecab1e05..c5f87af86319 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -350,8 +350,7 @@ class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
       return true;
 
     if (auto *AT = D->getType()->getContainedAutoType()) {
-      if (!AT->getDeducedType().isNull())
-        DeducedType = AT->getDeducedType();
+      DeducedType = AT->desugar();
     }
     return true;
   }

diff  --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h
index 1e3447376c10..b603964189e8 100644
--- a/clang-tools-extra/clangd/AST.h
+++ b/clang-tools-extra/clangd/AST.h
@@ -109,6 +109,7 @@ QualType declaredType(const TypeDecl *D);
 
 /// Retrieves the deduced type at a given location (auto, decltype).
 /// It will return the underlying type.
+/// If the type is an undeduced auto, returns the type itself.
 llvm::Optional<QualType> getDeducedType(ASTContext &, SourceLocation Loc);
 
 /// Gets the nested name specifier necessary for spelling \p ND in \p

diff  --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index e461c7c43364..b5eda93ddbbc 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -27,6 +27,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/Specifiers.h"
@@ -550,29 +551,6 @@ HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) {
   return HI;
 }
 
-/// Generate a \p Hover object given the type \p T.
-HoverInfo getHoverContents(QualType T, ASTContext &ASTCtx,
-                           const SymbolIndex *Index,
-                           bool SuppressScope = false) {
-  HoverInfo HI;
-
-  if (const auto *D = T->getAsTagDecl()) {
-    HI.Name = printName(ASTCtx, *D);
-    HI.Kind = index::getSymbolInfo(D).Kind;
-
-    const auto *CommentD = getDeclForComment(D);
-    HI.Documentation = getDeclComment(ASTCtx, *CommentD);
-    enhanceFromIndex(HI, *CommentD, Index);
-  } else {
-    // Builtin types
-    auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
-    Policy.SuppressTagKeyword = true;
-    Policy.SuppressScope = SuppressScope;
-    HI.Name = T.getAsString(Policy);
-  }
-  return HI;
-}
-
 /// Generate a \p Hover object given the macro \p MacroDecl.
 HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
   HoverInfo HI;
@@ -608,6 +586,52 @@ HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
   return HI;
 }
 
+llvm::Optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE,
+                                                   ASTContext &ASTCtx) {
+  QualType OriginThisType = CTE->getType()->getPointeeType();
+  QualType ClassType = declaredType(OriginThisType->getAsTagDecl());
+  // For partial specialization class, origin `this` pointee type will be
+  // parsed as `InjectedClassNameType`, which will ouput template arguments
+  // like "type-parameter-0-0". So we retrieve user written class type in this
+  // case.
+  QualType PrettyThisType = ASTCtx.getPointerType(
+      QualType(ClassType.getTypePtr(), OriginThisType.getCVRQualifiers()));
+
+  auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
+  Policy.SuppressTagKeyword = true;
+  Policy.SuppressScope = true;
+  HoverInfo HI;
+  HI.Name = "this";
+  HI.Definition = PrettyThisType.getAsString(Policy);
+  return HI;
+}
+
+/// Generate a HoverInfo object given the deduced type \p QT
+HoverInfo getDeducedTypeHoverContents(QualType QT, const syntax::Token &Tok,
+                                      ASTContext &ASTCtx,
+                                      const SymbolIndex *Index) {
+  HoverInfo HI;
+  // FIXME: distinguish decltype(auto) vs decltype(expr)
+  HI.Name = tok::getTokenName(Tok.kind());
+  HI.Kind = index::SymbolKind::TypeAlias;
+
+  auto PP = printingPolicyForDecls(ASTCtx.getLangOpts());
+
+  if (QT->isUndeducedAutoType()) {
+    HI.Definition = "/* not deduced */";
+  } else {
+    HI.Definition = QT.getAsString(PP);
+
+    if (const auto *D = QT->getAsTagDecl()) {
+      const auto *CommentD = getDeclForComment(D);
+      HI.Documentation = getDeclComment(ASTCtx, *CommentD);
+      enhanceFromIndex(HI, *CommentD, Index);
+    }
+  }
+
+  return HI;
+}
+
 bool isLiteral(const Expr *E) {
   // Unfortunately there's no common base Literal classes inherits from
   // (apart from Expr), therefore these exclusions.
@@ -641,18 +665,8 @@ llvm::Optional<HoverInfo> getHoverContents(const Expr *E, ParsedAST &AST,
 
   HoverInfo HI;
   // For `this` expr we currently generate hover with pointee type.
-  if (const CXXThisExpr *CTE = dyn_cast<CXXThisExpr>(E)) {
-    QualType OriginThisType = CTE->getType()->getPointeeType();
-    QualType ClassType = declaredType(OriginThisType->getAsTagDecl());
-    // For partial specialization class, origin `this` pointee type will be
-    // parsed as `InjectedClassNameType`, which will ouput template arguments
-    // like "type-parameter-0-0". So we retrieve user written class type in this
-    // case.
-    QualType PrettyThisType = AST.getASTContext().getPointerType(
-        QualType(ClassType.getTypePtr(), OriginThisType.getCVRQualifiers()));
-    return getHoverContents(PrettyThisType, AST.getASTContext(), Index,
-                            /*SuppressScope=*/true);
-  }
+  if (const CXXThisExpr *CTE = dyn_cast<CXXThisExpr>(E))
+    return getThisExprHoverContents(CTE, AST.getASTContext());
   // For expressions we currently print the type and the value, iff it is
   // evaluatable.
   if (auto Val = printExprValue(E, AST.getASTContext())) {
@@ -849,10 +863,16 @@ llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
       }
     } else if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
       if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) {
-        HI = getHoverContents(*Deduced, AST.getASTContext(), Index);
+        HI = getDeducedTypeHoverContents(*Deduced, Tok, AST.getASTContext(),
+                                         Index);
         HighlightRange = Tok.range(SM).toCharRange(SM);
         break;
       }
+
+      // If we can't find interesting hover information for this
+      // auto/decltype keyword, return nothing to avoid showing
+      // irrelevant or incorrect informations.
+      return llvm::None;
     }
   }
 

diff  --git a/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
index 6d38eb1de82a..c214695c5f07 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
@@ -106,7 +106,7 @@ Expected<Tweak::Effect> ExpandAutoType::apply(const Selection& Inputs) {
       Inputs.AST->getASTContext(), CachedLocation->getBeginLoc());
 
   // if we can't resolve the type, return an error message
-  if (DeducedType == llvm::None)
+  if (DeducedType == llvm::None || (*DeducedType)->isUndeducedAutoType())
     return error("Could not deduce type for 'auto' type");
 
   // if it's a lambda expression, return an error message

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index bac0e525664b..b72b500ee8b5 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -379,6 +379,30 @@ class Foo {})cpp";
          HI.Definition = "class X {}";
        }},
 
+      // auto on structured bindings
+      {R"cpp(
+        void foo() {
+          struct S { int x; float y; };
+          [[au^to]] [x, y] = S();
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "auto";
+         HI.Kind = index::SymbolKind::TypeAlias;
+         HI.Definition = "struct S";
+       }},
+      // undeduced auto
+      {R"cpp(
+        template<typename T>
+        void foo() {
+          [[au^to]] x = T{};
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "auto";
+         HI.Kind = index::SymbolKind::TypeAlias;
+         HI.Definition = "/* not deduced */";
+       }},
       // auto on lambda
       {R"cpp(
         void foo() {
@@ -386,8 +410,9 @@ class Foo {})cpp";
         }
         )cpp",
        [](HoverInfo &HI) {
-         HI.Name = "(lambda)";
-         HI.Kind = index::SymbolKind::Class;
+         HI.Name = "auto";
+         HI.Kind = index::SymbolKind::TypeAlias;
+         HI.Definition = "class(lambda)";
        }},
       // auto on template instantiation
       {R"cpp(
@@ -397,8 +422,9 @@ class Foo {})cpp";
         }
         )cpp",
        [](HoverInfo &HI) {
-         HI.Name = "Foo<int>";
-         HI.Kind = index::SymbolKind::Class;
+         HI.Name = "auto";
+         HI.Kind = index::SymbolKind::TypeAlias;
+         HI.Definition = "class Foo<int>";
        }},
       // auto on specialized template
       {R"cpp(
@@ -409,8 +435,9 @@ class Foo {})cpp";
         }
         )cpp",
        [](HoverInfo &HI) {
-         HI.Name = "Foo<int>";
-         HI.Kind = index::SymbolKind::Class;
+         HI.Name = "auto";
+         HI.Kind = index::SymbolKind::TypeAlias;
+         HI.Definition = "class Foo<int>";
        }},
 
       // macro
@@ -582,8 +609,9 @@ class Foo {})cpp";
           }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Foo<X>";
-            HI.Kind = index::SymbolKind::Class;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "class Foo<class X>";
           }},
       {// Falls back to primary template, when the type is not instantiated.
        R"cpp(
@@ -955,20 +983,11 @@ TEST(Hover, NoHover) {
   llvm::StringRef Tests[] = {
       "^int main() {}",
       "void foo() {^}",
-      R"cpp(// structured binding. Not supported yet
-            struct Bar {};
-            void foo() {
-              Bar a[2];
-              ^auto [x,y] = a;
-            }
-          )cpp",
-      R"cpp(// Template auto parameter. Nothing (Not useful).
-            template<a^uto T>
-            void func() {
-            }
-            void foo() {
-               func<1>();
-            }
+      // FIXME: "decltype(auto)" should be a single hover
+      "decltype(au^to) x = 0;",
+      // FIXME: not supported yet
+      R"cpp(// Lambda auto parameter
+            auto lamb = [](a^uto){};
           )cpp",
       R"cpp(// non-named decls don't get hover. Don't crash!
             ^static_assert(1, "");
@@ -1545,9 +1564,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "int";
-            // FIXME: Should be Builtin/Integral.
-            HI.Kind = index::SymbolKind::Unknown;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
           }},
       {
           R"cpp(// Simple initialization with const auto
@@ -1555,14 +1574,22 @@ TEST(Hover, All) {
               const ^[[auto]] i = 1;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with const auto&
             void foo() {
               const ^[[auto]]& i = 1;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with auto&
             void foo() {
@@ -1570,7 +1597,11 @@ TEST(Hover, All) {
               ^[[auto]]& i = x;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with auto*
             void foo() {
@@ -1578,7 +1609,23 @@ TEST(Hover, All) {
               ^[[auto]]* i = &a;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
+      {
+          R"cpp(// Simple initialization with auto from pointer
+            void foo() {
+              int a = 1;
+              ^[[auto]] i = &a;
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int *";
+          }},
       {
           R"cpp(// Auto with initializer list.
             namespace std
@@ -1591,8 +1638,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "initializer_list<int>";
-            HI.Kind = index::SymbolKind::Class;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "class std::initializer_list<int>";
           }},
       {
           R"cpp(// User defined conversion to auto
@@ -1600,14 +1648,22 @@ TEST(Hover, All) {
               operator ^[[auto]]() const { return 10; }
             };
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with decltype(auto)
             void foo() {
               ^[[decltype]](auto) i = 1;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with const decltype(auto)
             void foo() {
@@ -1615,7 +1671,11 @@ TEST(Hover, All) {
               ^[[decltype]](auto) i = j;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "const int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "const int";
+          }},
       {
           R"cpp(// Simple initialization with const& decltype(auto)
             void foo() {
@@ -1624,7 +1684,11 @@ TEST(Hover, All) {
               ^[[decltype]](auto) i = j;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "const int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "const int &";
+          }},
       {
           R"cpp(// Simple initialization with & decltype(auto)
             void foo() {
@@ -1633,14 +1697,22 @@ TEST(Hover, All) {
               ^[[decltype]](auto) i = j;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int &";
+          }},
       {
           R"cpp(// simple trailing return type
             ^[[auto]] main() -> int {
               return 0;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// auto function return with trailing type
             struct Bar {};
@@ -1649,8 +1721,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation = "auto function return with trailing type";
           }},
       {
@@ -1661,8 +1734,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation = "trailing return type";
           }},
       {
@@ -1673,8 +1747,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation = "auto in function return";
           }},
       {
@@ -1686,8 +1761,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation = "auto& in function return";
           }},
       {
@@ -1699,8 +1775,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation = "auto* in function return";
           }},
       {
@@ -1712,8 +1789,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation = "const auto& in function return";
           }},
       {
@@ -1724,8 +1802,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation = "decltype(auto) in function return";
           }},
       {
@@ -1735,7 +1814,11 @@ TEST(Hover, All) {
               return (a);
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int &";
+          }},
       {
           R"cpp(// decltype lvalue reference
             void foo() {
@@ -1743,7 +1826,11 @@ TEST(Hover, All) {
               ^[[decltype]](I) J = I;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// decltype lvalue reference
             void foo() {
@@ -1752,7 +1839,11 @@ TEST(Hover, All) {
               ^[[decltype]](K) J = I;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int &";
+          }},
       {
           R"cpp(// decltype lvalue reference parenthesis
             void foo() {
@@ -1760,7 +1851,11 @@ TEST(Hover, All) {
               ^[[decltype]]((I)) J = I;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int &";
+          }},
       {
           R"cpp(// decltype rvalue reference
             void foo() {
@@ -1768,7 +1863,11 @@ TEST(Hover, All) {
               ^[[decltype]](static_cast<int&&>(I)) J = static_cast<int&&>(I);
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &&"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int &&";
+          }},
       {
           R"cpp(// decltype rvalue reference function call
             int && bar();
@@ -1777,7 +1876,11 @@ TEST(Hover, All) {
               ^[[decltype]](bar()) J = bar();
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &&"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int &&";
+          }},
       {
           R"cpp(// decltype of function with trailing return type.
             struct Bar {};
@@ -1789,8 +1892,9 @@ TEST(Hover, All) {
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct Bar";
             HI.Documentation =
                 "decltype of function with trailing return type.";
           }},
@@ -1802,13 +1906,33 @@ TEST(Hover, All) {
               ^[[decltype]](J) K = J;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
+      {
+          R"cpp(// decltype of dependent type
+            template <typename T>
+            struct X {
+              using Y = ^[[decltype]](T::Z);
+            };
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "<dependent type>";
+          }},
       {
           R"cpp(// More complicated structured types.
             int bar();
             ^[[auto]] (*foo)() = bar;
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Should not crash when evaluating the initializer.
             struct Test {};
@@ -1827,7 +1951,11 @@ TEST(Hover, All) {
           typedef int int_type;
           ^[[auto]] x = int_type();
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// auto on alias
           struct cls {};
@@ -1835,8 +1963,9 @@ TEST(Hover, All) {
           ^[[auto]] y = cls_type();
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "cls";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct cls";
             HI.Documentation = "auto on alias";
           }},
       {
@@ -1846,10 +1975,60 @@ TEST(Hover, All) {
           ^[[auto]] z = templ<int>();
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "templ<int>";
-            HI.Kind = index::SymbolKind::Struct;
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "struct templ<int>";
             HI.Documentation = "auto on alias";
           }},
+      {
+          R"cpp(// Undeduced auto declaration
+            template<typename T>
+            void foo() {
+              ^[[auto]] x = T();
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "/* not deduced */";
+          }},
+      {
+          R"cpp(// Undeduced auto return type
+            template<typename T>
+            ^[[auto]] foo() {
+              return T();
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "/* not deduced */";
+          }},
+      {
+          R"cpp(// Template auto parameter
+            template<[[a^uto]] T>
+              void func() {
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            // FIXME: not sure this is what we want, but this
+            // is what we currently get with getDeducedType
+            HI.Name = "auto";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "/* not deduced */";
+          }},
+      {
+          R"cpp(// Undeduced decltype(auto) return type
+            template<typename T>
+            ^[[decltype]](auto) foo() {
+              return T();
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Kind = index::SymbolKind::TypeAlias;
+            HI.Definition = "/* not deduced */";
+          }},
       {
           R"cpp(// should not crash.
           template <class T> struct cls {
@@ -2030,7 +2209,10 @@ TEST(Hover, All) {
             };
           }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "Foo *"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "this";
+            HI.Definition = "Foo *";
+          }},
       {
           R"cpp(// this expr for template class
           namespace ns {
@@ -2042,7 +2224,10 @@ TEST(Hover, All) {
             };
           }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "const Foo<T> *"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "this";
+            HI.Definition = "const Foo<T> *";
+          }},
       {
           R"cpp(// this expr for specialization class
           namespace ns {
@@ -2055,7 +2240,10 @@ TEST(Hover, All) {
             };
           }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "Foo<int> *"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "this";
+            HI.Definition = "Foo<int> *";
+          }},
       {
           R"cpp(// this expr for partial specialization struct
           namespace ns {
@@ -2068,7 +2256,10 @@ TEST(Hover, All) {
             };
           }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "const Foo<int, F> *"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "this";
+            HI.Definition = "const Foo<int, F> *";
+          }},
   };
 
   // Create a tiny index, so tests above can verify documentation is fetched.
@@ -2119,7 +2310,7 @@ TEST(Hover, DocsFromIndex) {
   Annotations T(R"cpp(
   template <typename T> class X {};
   void foo() {
-    au^to t = X<int>();
+    auto t = X<int>();
     X^<int> w;
     (void)w;
   })cpp");
@@ -2250,17 +2441,17 @@ template <typename T, typename C = bool> class Foo {})",
             HI.NamespaceScope = "ns::";
             HI.Definition = "ret_type foo(params) {}";
           },
-          R"(function foo
-
-→ ret_type
-Parameters:
-- 
-- type
-- type foo
-- type foo = default
-
-// In namespace ns
-ret_type foo(params) {})",
+          "function foo\n"
+          "\n"
+          "→ ret_type\n"
+          "Parameters:\n"
+          "- \n"
+          "- type\n"
+          "- type foo\n"
+          "- type foo = default\n"
+          "\n"
+          "// In namespace ns\n"
+          "ret_type foo(params) {}",
       },
       {
           [](HoverInfo &HI) {
@@ -2540,15 +2731,16 @@ TEST(Hover, PresentRulers) {
   HI.Value = "val";
   HI.Definition = "def";
 
-  llvm::StringRef ExpectedMarkdown = R"md(### variable `foo`  
-
----
-Value = `val`  
-
----
-```cpp
-def
-```)md";
+  llvm::StringRef ExpectedMarkdown = //
+      "### variable `foo`  \n"
+      "\n"
+      "---\n"
+      "Value = `val`  \n"
+      "\n"
+      "---\n"
+      "```cpp\n"
+      "def\n"
+      "```";
   EXPECT_EQ(HI.present().asMarkdown(), ExpectedMarkdown);
 
   llvm::StringRef ExpectedPlaintext = R"pt(variable foo


        


More information about the llvm-branch-commits mailing list