qchateau created this revision.
Herald added subscribers: usaxena95, kadircet, arphaman.
qchateau requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang.

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


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D93227

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp

Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -379,6 +379,41 @@
          HI.Definition = "class X {}";
        }},
 
+      // auto on structured bindings
+      {R"cpp(
+        void foo() {
+          int arr[2];
+          [[au^to]] [x, y] = arr;
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "auto";
+         HI.Documentation = "Deduced type";
+         HI.Definition = "int[2]";
+       }},
+      // 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.Documentation = "Deduced type";
+         HI.Definition = "struct S";
+       }},
+      // undeduced auto
+      {R"cpp(
+        template<typename T>
+        void foo() {
+          [[au^to]] x = T{};
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "auto";
+         HI.Documentation = "Undeduced type";
+       }},
       // auto on lambda
       {R"cpp(
         void foo() {
@@ -386,8 +421,9 @@
         }
         )cpp",
        [](HoverInfo &HI) {
-         HI.Name = "(lambda)";
-         HI.Kind = index::SymbolKind::Class;
+         HI.Name = "auto";
+         HI.Documentation = "Deduced type";
+         HI.Definition = "(lambda)";
        }},
       // auto on template instantiation
       {R"cpp(
@@ -397,8 +433,9 @@
         }
         )cpp",
        [](HoverInfo &HI) {
-         HI.Name = "Foo<int>";
-         HI.Kind = index::SymbolKind::Class;
+         HI.Name = "auto";
+         HI.Documentation = "Deduced type";
+         HI.Definition = "class Foo<int>";
        }},
       // auto on specialized template
       {R"cpp(
@@ -409,8 +446,9 @@
         }
         )cpp",
        [](HoverInfo &HI) {
-         HI.Name = "Foo<int>";
-         HI.Kind = index::SymbolKind::Class;
+         HI.Name = "auto";
+         HI.Documentation = "Deduced type";
+         HI.Definition = "class Foo<int>";
        }},
 
       // macro
@@ -582,8 +620,9 @@
           }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Foo<X>";
-            HI.Kind = index::SymbolKind::Class;
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "class Foo<class X>";
           }},
       {// Falls back to primary template, when the type is not instantiated.
        R"cpp(
@@ -955,12 +994,9 @@
   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;
-            }
+      "decltype(au^to) x = 0;",
+      R"cpp(// Lambda auto parameter. Nothing (Not useful).
+            auto lamb = [](a^uto){};
           )cpp",
       R"cpp(// Template auto parameter. Nothing (Not useful).
             template<a^uto T>
@@ -1545,9 +1581,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "int";
-            // FIXME: Should be Builtin/Integral.
-            HI.Kind = index::SymbolKind::Unknown;
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int";
           }},
       {
           R"cpp(// Simple initialization with const auto
@@ -1555,14 +1591,22 @@
               const ^[[auto]] i = 1;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            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.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with auto&
             void foo() {
@@ -1570,7 +1614,11 @@
               ^[[auto]]& i = x;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with auto*
             void foo() {
@@ -1578,7 +1626,23 @@
               ^[[auto]]* i = &a;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            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.Documentation = "Deduced type";
+            HI.Definition = "int *";
+          }},
       {
           R"cpp(// Auto with initializer list.
             namespace std
@@ -1591,8 +1655,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "initializer_list<int>";
-            HI.Kind = index::SymbolKind::Class;
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "class std::initializer_list<int>";
           }},
       {
           R"cpp(// User defined conversion to auto
@@ -1600,14 +1665,22 @@
               operator ^[[auto]]() const { return 10; }
             };
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            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.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Simple initialization with const decltype(auto)
             void foo() {
@@ -1615,7 +1688,11 @@
               ^[[decltype]](auto) i = j;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "const int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "const int";
+          }},
       {
           R"cpp(// Simple initialization with const& decltype(auto)
             void foo() {
@@ -1624,7 +1701,11 @@
               ^[[decltype]](auto) i = j;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "const int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "const int &";
+          }},
       {
           R"cpp(// Simple initialization with & decltype(auto)
             void foo() {
@@ -1633,14 +1714,22 @@
               ^[[decltype]](auto) i = j;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            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.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// auto function return with trailing type
             struct Bar {};
@@ -1649,9 +1738,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "auto function return with trailing type";
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// trailing return type
@@ -1661,9 +1750,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "trailing return type";
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// auto in function return
@@ -1673,9 +1762,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "auto in function return";
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// auto& in function return
@@ -1686,9 +1775,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "auto& in function return";
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// auto* in function return
@@ -1699,9 +1788,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "auto* in function return";
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// const auto& in function return
@@ -1712,9 +1801,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "const auto& in function return";
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// decltype(auto) in function return
@@ -1724,9 +1813,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "decltype(auto) in function return";
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// decltype(auto) reference in function return
@@ -1735,7 +1824,11 @@
               return (a);
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int &";
+          }},
       {
           R"cpp(// decltype lvalue reference
             void foo() {
@@ -1743,7 +1836,11 @@
               ^[[decltype]](I) J = I;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// decltype lvalue reference
             void foo() {
@@ -1752,7 +1849,11 @@
               ^[[decltype]](K) J = I;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int &";
+          }},
       {
           R"cpp(// decltype lvalue reference parenthesis
             void foo() {
@@ -1760,7 +1861,11 @@
               ^[[decltype]]((I)) J = I;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int &";
+          }},
       {
           R"cpp(// decltype rvalue reference
             void foo() {
@@ -1768,7 +1873,11 @@
               ^[[decltype]](static_cast<int&&>(I)) J = static_cast<int&&>(I);
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &&"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int &&";
+          }},
       {
           R"cpp(// decltype rvalue reference function call
             int && bar();
@@ -1777,7 +1886,11 @@
               ^[[decltype]](bar()) J = bar();
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int &&"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int &&";
+          }},
       {
           R"cpp(// decltype of function with trailing return type.
             struct Bar {};
@@ -1789,10 +1902,9 @@
             }
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "Bar";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation =
-                "decltype of function with trailing return type.";
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct Bar";
           }},
       {
           R"cpp(// decltype of var with decltype.
@@ -1802,13 +1914,21 @@
               ^[[decltype]](J) K = J;
             }
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// More complicated structured types.
             int bar();
             ^[[auto]] (*foo)() = bar;
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// Should not crash when evaluating the initializer.
             struct Test {};
@@ -1827,7 +1947,11 @@
           typedef int int_type;
           ^[[auto]] x = int_type();
           )cpp",
-          [](HoverInfo &HI) { HI.Name = "int"; }},
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "int";
+          }},
       {
           R"cpp(// auto on alias
           struct cls {};
@@ -1835,9 +1959,9 @@
           ^[[auto]] y = cls_type();
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "cls";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "auto on alias";
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct cls";
           }},
       {
           R"cpp(// auto on alias
@@ -1846,9 +1970,42 @@
           ^[[auto]] z = templ<int>();
           )cpp",
           [](HoverInfo &HI) {
-            HI.Name = "templ<int>";
-            HI.Kind = index::SymbolKind::Struct;
-            HI.Documentation = "auto on alias";
+            HI.Name = "auto";
+            HI.Documentation = "Deduced type";
+            HI.Definition = "struct templ<int>";
+          }},
+      {
+          R"cpp(// Undeduced auto declaration
+            template<typename T>
+            void foo() {
+              ^[[auto]] x = T();
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Undeduced type";
+          }},
+      {
+          R"cpp(// Undeduced auto return type
+            template<typename T>
+            ^[[auto]] foo() {
+              return T();
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "auto";
+            HI.Documentation = "Undeduced type";
+          }},
+      {
+          R"cpp(// Undeduced decltype(auto) return type
+            template<typename T>
+            ^[[decltype]](auto) foo() {
+              return T();
+            }
+          )cpp",
+          [](HoverInfo &HI) {
+            HI.Name = "decltype";
+            HI.Documentation = "Undeduced type";
           }},
       {
           R"cpp(// should not crash.
@@ -2069,7 +2226,7 @@
   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");
@@ -2100,10 +2257,9 @@
   // doc
   template <typename T> T baz;
   void foo() {
-    au^to t = X<int>();
     X^<int>();
     b^ar<int>();
-    au^to T = ba^z<X<int>>;
+    auto T = ba^z<X<int>>;
     ba^z<int> = 0;
   })cpp");
 
Index: clang-tools-extra/clangd/Hover.cpp
===================================================================
--- clang-tools-extra/clangd/Hover.cpp
+++ 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,27 +551,6 @@
   return HI;
 }
 
-/// Generate a \p Hover object given the type \p T.
-HoverInfo getHoverContents(QualType T, ASTContext &ASTCtx,
-                           const SymbolIndex *Index) {
-  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;
-    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;
@@ -606,6 +586,60 @@
   return HI;
 }
 
+/// Generate a HoverInfo object given the deduced type \p QT
+HoverInfo getDeducedTypeHoverContents(QualType QT) {
+  HoverInfo HI;
+
+  if (QT->isUndeducedAutoType()) {
+    HI.Kind = index::SymbolKind::Unknown;
+    HI.Documentation = "Undeduced type";
+  } else {
+    HI.Kind = index::SymbolKind::Unknown;
+    HI.Documentation = "Deduced type";
+    CXXRecordDecl *D = QT->getAsCXXRecordDecl();
+    if (D && D->isLambda())
+      HI.Definition = "(lambda)";
+    else
+      HI.Definition = QT.getAsString();
+  }
+
+  return HI;
+}
+
+/// Visit the relevant nodes to display hover information over an "auto"
+/// keyword or "decltype()" expression. Only types not returned by
+// getDeducedType are handled.
+class ExtraAutoTypeHoverVisitor
+    : public RecursiveASTVisitor<ExtraAutoTypeHoverVisitor> {
+  SourceLocation SearchedLocation;
+
+public:
+  ExtraAutoTypeHoverVisitor(SourceLocation SearchedLocation)
+      : SearchedLocation(SearchedLocation) {}
+
+  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+    if (!D->getTypeSourceInfo() ||
+        D->getTypeSourceInfo()->getTypeLoc().getBeginLoc() != SearchedLocation)
+      return true;
+
+    if (isa<NonTypeTemplateParmDecl, ParmVarDecl>(D)) {
+      // Handle template<auto k> and [](auto){}
+      // FIXME: Until we have something useful to display, just display nothing
+    } else {
+      // At this point only a few cases are left:
+      // - decomposition of arrays
+      // - undeduced auto in a declaration
+      // Just give the declaration type to getDeducedTypeHoverContents
+      // which will handle it
+      HI = getDeducedTypeHoverContents(D->getType());
+    }
+
+    return false;
+  }
+
+  llvm::Optional<HoverInfo> HI;
+};
+
 bool isLiteral(const Expr *E) {
   // Unfortunately there's no common base Literal classes inherits from
   // (apart from Expr), therefore these exclusions.
@@ -833,10 +867,22 @@
       }
     } 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);
-        HighlightRange = Tok.range(SM).toCharRange(SM);
-        break;
+        HI = getDeducedTypeHoverContents(*Deduced);
+      } else {
+        ExtraAutoTypeHoverVisitor V(Tok.location());
+        V.TraverseAST(AST.getASTContext());
+        HI = V.HI;
       }
+
+      // If we can't find interesting hover information for this
+      // auto/decltype keyword, return nothing to avoid showing
+      // irrelevant or incorrect informations.
+      if (!HI)
+        return llvm::None;
+
+      HI->Name = tok::getTokenName(Tok.kind());
+      HighlightRange = Tok.range(SM).toCharRange(SM);
+      break;
     }
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to