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

Enable the existing code action `ExpandAutoType` to expand
`decltype(expr)`, e.g.

  decltype(0) i;

will expand to

  int i;


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D141226

Files:
  clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
  clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp

Index: clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
@@ -50,7 +50,10 @@
               StartsWith("fail: Could not deduce type for 'auto' type"));
   // function pointers should not be replaced
   EXPECT_THAT(apply("au^to x = &ns::Func;"),
-              StartsWith("fail: Could not expand type of function pointer"));
+              StartsWith("fail: Could not expand type of function"));
+  // function references should not be replaced
+  EXPECT_THAT(apply("au^to &x = ns::Func;"),
+              StartsWith("fail: Could not expand type of function"));
   // lambda types are not replaced
   EXPECT_UNAVAILABLE("au^to x = []{};");
   // inline namespaces
@@ -78,6 +81,17 @@
   EXPECT_THAT(apply("template <typename T> void x() { ^auto y = T::z(); }"),
               StartsWith("fail: Could not deduce type for 'auto' type"));
 
+  EXPECT_EQ(apply("decl^type(0) i;"), "int i;");
+  EXPECT_THAT(apply("void f(); decl^type(f) g;"),
+              StartsWith("fail: Could not expand type of function"));
+  EXPECT_EQ(apply("decl^type(0) f();"), "int f();");
+  EXPECT_EQ(apply("auto f() -> decl^type(0) { return 0; }"),
+            "auto f() -> int { return 0; }");
+  EXPECT_EQ(apply("template <class = decl^type(0)> class Foo {};"),
+            "template <class = int> class Foo {};");
+  EXPECT_EQ(apply("template <class> class Bar {}; Bar<decl^type(0)> b;"),
+            "template <class> class Bar {}; Bar<int> b;");
+
   ExtraArgs.push_back("-std=c++20");
   EXPECT_UNAVAILABLE("template <au^to X> class Y;");
 
@@ -90,6 +104,9 @@
   // FIXME: should work on constrained auto params, once SourceRange is fixed.
   EXPECT_UNAVAILABLE("template<class> concept C = true;"
                      "auto X = [](C ^auto *){return 0;};");
+
+  EXPECT_UNAVAILABLE("auto f = [](){}; decl^type(f) g;");
+  EXPECT_UNAVAILABLE("decl^type([]{}) f;");
 }
 
 } // namespace
Index: clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
===================================================================
--- clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
+++ clang-tools-extra/clangd/refactor/tweaks/ExpandAutoType.cpp
@@ -29,7 +29,6 @@
 /// After:
 ///    MyClass x = Something();
 ///    ^^^^^^^
-/// FIXME: Handle decltype as well
 class ExpandAutoType : public Tweak {
 public:
   const char *id() const final;
@@ -41,12 +40,15 @@
   std::string title() const override;
 
 private:
-  SourceRange AutoRange;
+  SourceRange Range;
+  bool IsAutoType;
 };
 
 REGISTER_TWEAK(ExpandAutoType)
 
-std::string ExpandAutoType::title() const { return "Expand auto type"; }
+std::string ExpandAutoType::title() const {
+  return IsAutoType ? "Expand auto type" : "Expand decltype";
+}
 
 // Structured bindings must use auto, e.g. `const auto& [a,b,c] = ...;`.
 // Return whether N (an AutoTypeLoc) is such an auto that must not be expanded.
@@ -93,7 +95,7 @@
         if (!isStructuredBindingType(Node) &&
             !isDeducedAsLambda(Node, Result.getBeginLoc()) &&
             !isTemplateParam(Node))
-          AutoRange = Result.getSourceRange();
+          Range = Result.getSourceRange();
       }
       if (auto TTPAuto = TypeNode->getAs<TemplateTypeParmTypeLoc>()) {
         // We exclude concept constraints for now, as the SourceRange is wrong.
@@ -102,41 +104,43 @@
         // TTPAuto->getSourceRange only covers "auto", not "C auto".
         if (TTPAuto.getDecl()->isImplicit() &&
             !TTPAuto.getDecl()->hasTypeConstraint())
-          AutoRange = TTPAuto.getSourceRange();
+          Range = TTPAuto.getSourceRange();
+      }
+      IsAutoType = true;
+
+      if (auto DTTL = TypeNode->getAs<DecltypeTypeLoc>()) {
+        if (!isDeducedAsLambda(Node, DTTL.getBeginLoc()))
+          Range = DTTL.getSourceRange();
+        IsAutoType = false;
       }
     }
   }
 
-  return AutoRange.isValid();
+  return Range.isValid();
 }
 
-Expected<Tweak::Effect> ExpandAutoType::apply(const Selection& Inputs) {
+Expected<Tweak::Effect> ExpandAutoType::apply(const Selection &Inputs) {
   auto &SrcMgr = Inputs.AST->getSourceManager();
 
   std::optional<clang::QualType> DeducedType =
-      getDeducedType(Inputs.AST->getASTContext(), AutoRange.getBegin());
+      getDeducedType(Inputs.AST->getASTContext(), Range.getBegin());
 
   // if we can't resolve the type, return an error message
   if (DeducedType == std::nullopt || (*DeducedType)->isUndeducedAutoType())
     return error("Could not deduce type for 'auto' type");
 
-  // if it's a lambda expression, return an error message
-  if (isa<RecordType>(*DeducedType) &&
-      cast<RecordType>(*DeducedType)->getDecl()->isLambda()) {
-    return error("Could not expand type of lambda expression");
-  }
-
   // if it's a function expression, return an error message
   // naively replacing 'auto' with the type will break declarations.
   // FIXME: there are other types that have similar problems
-  if (DeducedType->getTypePtr()->isFunctionPointerType()) {
-    return error("Could not expand type of function pointer");
+  if (const Type *T = DeducedType->getTypePtr();
+      T->isFunctionType() || T->isFunctionPointerType()) {
+    return error("Could not expand type of function");
   }
 
-  std::string PrettyTypeName = printType(*DeducedType,
-      Inputs.ASTSelection.commonAncestor()->getDeclContext());
+  std::string PrettyTypeName = printType(
+      *DeducedType, Inputs.ASTSelection.commonAncestor()->getDeclContext());
 
-  tooling::Replacement Expansion(SrcMgr, CharSourceRange(AutoRange, true),
+  tooling::Replacement Expansion(SrcMgr, CharSourceRange(Range, true),
                                  PrettyTypeName);
 
   return Effect::mainFileEdit(SrcMgr, tooling::Replacements(Expansion));
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to