[clangd] ExpandAutoType: Do not offer code action on lambdas.
authorAdam Czachorowski <adamcz@google.com>
Tue, 1 Dec 2020 15:53:21 +0000 (16:53 +0100)
committerAdam Czachorowski <adamcz@google.com>
Tue, 8 Dec 2020 19:03:16 +0000 (20:03 +0100)
We can't expand lambda types anyway. Now we simply not offer the code
action instead of showing it and then returning an error in apply().

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

clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
clang-tools-extra/clangd/test/check-fail.test
clang-tools-extra/clangd/unittests/TweakTests.cpp

index 61f68a6..6d38eb1 100644 (file)
@@ -63,6 +63,25 @@ bool isStructuredBindingType(const SelectionTree::Node *N) {
   return N && N->ASTNode.get<DecompositionDecl>();
 }
 
+// Returns true iff Node is a lambda, and thus should not be expanded. Loc is
+// the location of the auto type.
+bool isDeducedAsLambda(const SelectionTree::Node *Node, SourceLocation Loc) {
+  // getDeducedType() does a traversal, which we want to avoid in prepare().
+  // But at least check this isn't auto x = []{...};, which can't ever be
+  // expanded.
+  // (It would be nice if we had an efficient getDeducedType(), instead).
+  for (const auto *It = Node; It; It = It->Parent) {
+    if (const auto *DD = It->ASTNode.get<DeclaratorDecl>()) {
+      if (DD->getTypeSourceInfo() &&
+          DD->getTypeSourceInfo()->getTypeLoc().getBeginLoc() == Loc) {
+        if (auto *RD = DD->getType()->getAsRecordDecl())
+          return RD->isLambda();
+      }
+    }
+  }
+  return false;
+}
+
 bool ExpandAutoType::prepare(const Selection& Inputs) {
   CachedLocation = llvm::None;
   if (auto *Node = Inputs.ASTSelection.commonAncestor()) {
@@ -70,11 +89,13 @@ bool ExpandAutoType::prepare(const Selection& Inputs) {
       if (const AutoTypeLoc Result = TypeNode->getAs<AutoTypeLoc>()) {
         // Code in apply() does handle 'decltype(auto)' yet.
         if (!Result.getTypePtr()->isDecltypeAuto() &&
-            !isStructuredBindingType(Node))
+            !isStructuredBindingType(Node) &&
+            !isDeducedAsLambda(Node, Result.getBeginLoc()))
           CachedLocation = Result;
       }
     }
   }
+
   return (bool) CachedLocation;
 }
 
index 0ee777f..dd50b59 100644 (file)
@@ -11,4 +11,5 @@
 // CHECK: All checks completed, 2 errors
 
 #include "missing.h"
-auto x = []{};
+void fun();
+auto x = fun;
index 85edd92..0dcf8fe 100644 (file)
@@ -559,8 +559,7 @@ TEST_F(ExpandAutoTypeTest, Test) {
   EXPECT_THAT(apply("au^to x = &ns::Func;"),
               StartsWith("fail: Could not expand type of function pointer"));
   // lambda types are not replaced
-  EXPECT_THAT(apply("au^to x = []{};"),
-              StartsWith("fail: Could not expand type of lambda expression"));
+  EXPECT_UNAVAILABLE("au^to x = []{};");
   // inline namespaces
   EXPECT_EQ(apply("au^to x = inl_ns::Visible();"),
             "Visible x = inl_ns::Visible();");