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

Hints are shown for the individual bindings, not the aggregate.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D104617

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -462,19 +462,57 @@
 }
 
 TEST(TypeHints, StructuredBindings) {
-  // FIXME: Not handled yet.
-  // To handle it, we could print:
-  //  - the aggregate type next to the 'auto', or
-  //  - the individual types inside the brackets
-  // The latter is probably more useful.
+  // Hint individual bindings, not the aggregate.
   assertTypeHints(R"cpp(
+    // 1. Struct with public fields.
     struct Point {
       int x;
       int y;
     };
     Point foo();
-    auto [x, y] = foo();
-  )cpp");
+    auto [$x1[[x1]], $y1[[y1]]] = foo();
+
+    // 2. Array
+    int arr[2];
+    auto [$x2[[x2]], $y2[[y2]]] = arr;
+
+    // 3. Tuple-like type.
+    struct IntPair {
+      int a;
+      int b;
+    };
+    namespace std {
+      template <typename T>
+      struct tuple_size {};
+      template <>
+      struct tuple_size<IntPair> {
+        constexpr static unsigned value = 2;
+      };
+      template <unsigned I, typename T>
+      struct tuple_element {};
+      template <unsigned I>
+      struct tuple_element<I, IntPair> {
+        using type = int;
+      };
+    }
+    template <unsigned I>
+    int get(const IntPair& p) {
+      if constexpr (I == 0) {
+        return p.a;
+      } else if constexpr (I == 1) {
+        return p.b;
+      }
+    }
+    IntPair bar();
+    auto [$x3[[x3]], $y3[[y3]]] = bar();
+
+    // 4. No initializer (ill-formed).
+    // Do not show useless "NULL TYPE" hint.    
+    auto [x4, y4];  /*error-ok*/
+  )cpp",
+                  ExpectedHint{": int", "x1"}, ExpectedHint{": int", "y1"},
+                  ExpectedHint{": int", "x2"}, ExpectedHint{": int", "y2"},
+                  ExpectedHint{": int", "x3"}, ExpectedHint{": int", "y3"});
 }
 
 TEST(TypeHints, ReturnTypeDeduction) {
Index: clang-tools-extra/clangd/InlayHints.cpp
===================================================================
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -32,6 +32,12 @@
     TypeHintPolicy.SuppressScope = true; // keep type names short
     TypeHintPolicy.AnonymousTagLocations =
         false; // do not print lambda locations
+    // Print canonical types. Otherwise, SuppressScope would result in
+    // things like "metafunction<args>::type" being shorted to just "type",
+    // which is useless. This is particularly important for structured
+    // bindings that use the tuple_element protocol, where the non-canonical
+    // types would be "tuple_element<I, A>::type".
+    TypeHintPolicy.PrintCanonicalTypes = true;
   }
 
   bool VisitCXXConstructExpr(CXXConstructExpr *E) {
@@ -76,9 +82,8 @@
     if (auto *AT = D->getReturnType()->getContainedAutoType()) {
       QualType Deduced = AT->getDeducedType();
       if (!Deduced.isNull()) {
-        addInlayHint(D->getFunctionTypeLoc().getRParenLoc(),
-                     InlayHintKind::TypeHint,
-                     "-> " + D->getReturnType().getAsString(TypeHintPolicy));
+        addTypeHint(D->getFunctionTypeLoc().getRParenLoc(), D->getReturnType(),
+                    "-> ");
       }
     }
 
@@ -86,10 +91,14 @@
   }
 
   bool VisitVarDecl(VarDecl *D) {
-    // Do not show hints for the aggregate in a structured binding.
-    // In the future, we may show hints for the individual bindings.
-    if (isa<DecompositionDecl>(D))
+    // Do not show hints for the aggregate in a structured binding,
+    // but show hints for the individual bindings.
+    if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
+      for (auto *Binding : DD->bindings()) {
+        addTypeHint(Binding->getLocation(), Binding->getType(), ": ");
+      }
       return true;
+    }
 
     if (auto *AT = D->getType()->getContainedAutoType()) {
       if (!D->getType()->isDependentType()) {
@@ -98,8 +107,7 @@
         // (e.g. for `const auto& x = 42`, print `const int&`).
         // Alternatively, we could place the hint on the `auto`
         // (and then just print the type deduced for the `auto`).
-        addInlayHint(D->getLocation(), InlayHintKind::TypeHint,
-                     ": " + D->getType().getAsString(TypeHintPolicy));
+        addTypeHint(D->getLocation(), D->getType(), ": ");
       }
     }
     return true;
@@ -311,6 +319,15 @@
         Kind, Label.str()});
   }
 
+  void addTypeHint(SourceRange R, QualType T, llvm::StringRef Prefix) {
+    // Do not print useless "NULL TYPE" hint.
+    if (!T.getTypePtrOrNull())
+      return;
+
+    addInlayHint(R, InlayHintKind::TypeHint,
+                 std::string(Prefix) + T.getAsString(TypeHintPolicy));
+  }
+
   std::vector<InlayHint> &Results;
   ASTContext &AST;
   FileID MainFileID;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to