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

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140274

Files:
  clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
  clang-tools-extra/clangd/refactor/tweaks/FillStructDesignatedInit.cpp
  clang-tools-extra/clangd/unittests/CMakeLists.txt
  clang-tools-extra/clangd/unittests/tweaks/FillStructDesignatedInitTests.cpp

Index: clang-tools-extra/clangd/unittests/tweaks/FillStructDesignatedInitTests.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/unittests/tweaks/FillStructDesignatedInitTests.cpp
@@ -0,0 +1,126 @@
+//===-- FillStructDesignatedInitTests.cpp -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TweakTesting.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+TWEAK_TEST(FillStructDesignatedInit);
+
+TEST_F(FillStructDesignatedInitTest, AvailableUnavailable) {
+  Header = R"cpp(
+    namespace ns1 {
+      struct Foo {
+        Foo() {}
+      };
+    }
+  )cpp";
+  EXPECT_UNAVAILABLE(R"cpp(
+    namespace ns1 {
+      struct Bar {
+        int x;
+        int y;
+      };
+      void bar(Bar b) {}
+      void foo() {
+        Bar b[[{}]];
+      }
+    }
+  )cpp");
+  ExtraArgs.push_back("-std=c++20");
+  EXPECT_UNAVAILABLE(R"cpp(
+    namespace ns1 {
+      struct Bar : Foo {
+        int x;
+        int y;
+      };
+      void bar(Bar b) {}
+      void foo() {
+        Bar b[[{}]];
+      }
+    }
+  )cpp");
+  EXPECT_AVAILABLE(R"cpp(
+    namespace ns1 {
+      struct Bar {
+        int x;
+        int y;
+      };
+      void bar(Bar b) {}
+      void foo() {
+        Bar b[[{}]];
+        bar([[{}]]);
+      }
+    }
+  )cpp");
+}
+
+TEST_F(FillStructDesignatedInitTest, Apply1) {
+  ExtraArgs.push_back("-std=c++20");
+  EXPECT_EQ(apply(R"cpp(
+    namespace ns1 {
+      struct D1 {
+        int x;
+        int* y;
+      };
+      void foo() {
+        D1 b[[{}]];
+      }
+    }
+  )cpp"),
+            R"cpp(
+    namespace ns1 {
+      struct D1 {
+        int x;
+        int* y;
+      };
+      void foo() {
+        D1 b{.x = int{}, .y = {}};
+      }
+    }
+  )cpp");
+}
+
+TEST_F(FillStructDesignatedInitTest, Apply2) {
+  ExtraArgs.push_back("-std=c++20");
+  Header = R"cpp(
+    namespace ns {
+      struct B1 {
+        int b1;
+      };
+    }
+    namespace ns1 {
+      struct D1 {
+        int* x;
+        ns::B1 b1;
+      };
+    }
+  )cpp";
+  EXPECT_EQ(apply(R"cpp(
+    namespace ns1 {
+      void foo() {
+        D1 b[[{}]];
+      }
+    }
+  )cpp"),
+            R"cpp(
+    namespace ns1 {
+      void foo() {
+        D1 b{.x = {}, .b1 = ns::B1{}};
+      }
+    }
+  )cpp");
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
Index: clang-tools-extra/clangd/unittests/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -118,6 +118,7 @@
   tweaks/ExpandMacroTests.cpp
   tweaks/ExtractFunctionTests.cpp
   tweaks/ExtractVariableTests.cpp
+  tweaks/FillStructDesignatedInitTests.cpp
   tweaks/MemberwiseConstructorTests.cpp
   tweaks/ObjCLocalizeStringLiteralTests.cpp
   tweaks/ObjCMemberwiseInitializerTests.cpp
Index: clang-tools-extra/clangd/refactor/tweaks/FillStructDesignatedInit.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/refactor/tweaks/FillStructDesignatedInit.cpp
@@ -0,0 +1,128 @@
+//===--- FillStructDesignatedInit.cpp ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "AST.h"
+#include "Selection.h"
+#include "refactor/Tweak.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+// A tweak that fills an aggregate without parents with designated initializers
+//
+// Given:
+//   struct S { int x; unique_ptr<double> y; char* s; };
+// the tweak initializes struct with designated initializers:
+//   void bar() { S s{.x = int{}, .y = unique_ptr<double>{}, .s = {}}; }
+//
+class FillStructDesignatedInit : public Tweak {
+public:
+  const char *id() const final;
+  llvm::StringLiteral kind() const override {
+    return CodeAction::REFACTOR_KIND;
+  }
+  bool prepare(const Selection &Inputs) override;
+  Expected<Effect> apply(const Selection &Inputs) override;
+  std::string title() const override;
+
+private:
+  CXXRecordDecl const *Class;
+  SourceRange InitRange;
+  std::string buildInitCode() const;
+  std::string determineTypeName(FieldDecl const &FD,
+                                DeclContext const &Ctx) const;
+  std::string processRecord(CXXRecordDecl const *RD, DeclContext const &) const;
+};
+
+REGISTER_TWEAK(FillStructDesignatedInit)
+
+std::string FillStructDesignatedInit::title() const {
+  return "Fill struct with designated initializers";
+}
+
+bool FillStructDesignatedInit::prepare(const Selection &Inputs) {
+  if (!Inputs.AST->getLangOpts().CPlusPlus20) {
+    return false;
+  }
+  if (auto *N = Inputs.ASTSelection.commonAncestor()) {
+    if (InitListExpr const *ILE = N->ASTNode.get<InitListExpr>()) {
+      Class = ILE->getType()->getAsCXXRecordDecl();
+      if (Class && Class->isAggregate() && Class->bases().empty()) {
+        InitRange = ILE->getSourceRange();
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+std::string FillStructDesignatedInit::buildInitCode() const {
+  std::string Res;
+  llvm::raw_string_ostream OS(Res);
+
+  OS << processRecord(Class, *Class);
+
+  return Res;
+}
+
+std::string
+FillStructDesignatedInit::determineTypeName(FieldDecl const &FD,
+                                            DeclContext const &Ctx) const {
+  std::string TypeName;
+  if (!FD.getType()->isPointerType()) {
+    TypeName = printType(FD.getType().getLocalUnqualifiedType(), Ctx);
+  }
+  return TypeName;
+}
+
+std::string
+FillStructDesignatedInit::processRecord(CXXRecordDecl const *RD,
+                                        DeclContext const &Ctx) const {
+  std::string Res;
+  llvm::raw_string_ostream OS(Res);
+
+  auto ProcessWithoutParents = [&]() {
+    char const *Sep = " ";
+    for (auto It = RD->field_begin(); It != RD->field_end();) {
+      FieldDecl const *FD = *It;
+      std::string TypeName(determineTypeName(*FD, Ctx));
+      OS << llvm::formatv(".{0} = {1}{{}", (*It)->getName(), TypeName);
+      if (++It == RD->field_end()) {
+        break;
+      }
+      OS << "," << Sep;
+    }
+  };
+
+  OS << "{";
+  ProcessWithoutParents();
+  OS << "}";
+
+  return Res;
+}
+
+Expected<Tweak::Effect>
+FillStructDesignatedInit::apply(const Selection &Inputs) {
+  assert(Class);
+  std::string Code = buildInitCode();
+  auto &SrcMgr = Inputs.AST->getSourceManager();
+  tooling::Replacement Init(SrcMgr, CharSourceRange(InitRange, true), Code);
+  return Effect::mainFileEdit(SrcMgr, tooling::Replacements(Init));
+}
+} // namespace
+} // namespace clangd
+} // namespace clang
Index: clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
+++ clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
@@ -21,6 +21,7 @@
   ExpandMacro.cpp
   ExtractFunction.cpp
   ExtractVariable.cpp
+  FillStructDesignatedInit.cpp
   MemberwiseConstructor.cpp
   ObjCLocalizeStringLiteral.cpp
   ObjCMemberwiseInitializer.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to