[clang-tools-extra] [llvm] [clangd] Add CodeAction to swap operands to binary operators (PR #78999)
Tor Shepherd via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 23 16:46:39 PDT 2024
https://github.com/torshepherd updated https://github.com/llvm/llvm-project/pull/78999
>From 718e26db063980e2296f3817381befc119294b64 Mon Sep 17 00:00:00 2001
From: Tor Shepherd <tor.aksel.shepherd at gmail.com>
Date: Sun, 21 Jan 2024 17:53:31 -0500
Subject: [PATCH 1/3] [clangd] Swap binary operands
---
.../clangd/refactor/tweaks/CMakeLists.txt | 1 +
.../refactor/tweaks/SwapBinaryOperands.cpp | 210 ++++++++++++++++++
.../clangd/unittests/CMakeLists.txt | 1 +
.../tweaks/SwapBinaryOperandsTests.cpp | 38 ++++
.../clangd/refactor/tweaks/BUILD.gn | 1 +
.../clangd/unittests/BUILD.gn | 1 +
6 files changed, 252 insertions(+)
create mode 100644 clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp
create mode 100644 clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp
diff --git a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
index 2e948c23569f68..59475b0dfd3d22 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
+++ b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
@@ -29,6 +29,7 @@ add_clang_library(clangDaemonTweaks OBJECT
RemoveUsingNamespace.cpp
ScopifyEnum.cpp
SpecialMembers.cpp
+ SwapBinaryOperands.cpp
SwapIfBranches.cpp
LINK_LIBS
diff --git a/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp
new file mode 100644
index 00000000000000..2241b0ac37b52a
--- /dev/null
+++ b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp
@@ -0,0 +1,210 @@
+//===--- SwapBinaryOperands.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 "ParsedAST.h"
+#include "SourceCode.h"
+#include "refactor/Tweak.h"
+#include "support/Logger.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+/// Check whether it makes logical sense to swap operands to an operator.
+/// Assignment or member access operators are rarely swappable
+/// while keeping the meaning intact, whereas comparison operators, mathematical
+/// operators, etc. are often desired to be swappable for readability, avoiding
+/// bugs by assigning to nullptr when comparison was desired, etc.
+auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool {
+ switch (Opcode) {
+ case BinaryOperatorKind::BO_Mul:
+ case BinaryOperatorKind::BO_Add:
+ case BinaryOperatorKind::BO_Cmp:
+ case BinaryOperatorKind::BO_LT:
+ case BinaryOperatorKind::BO_GT:
+ case BinaryOperatorKind::BO_LE:
+ case BinaryOperatorKind::BO_GE:
+ case BinaryOperatorKind::BO_EQ:
+ case BinaryOperatorKind::BO_NE:
+ case BinaryOperatorKind::BO_And:
+ case BinaryOperatorKind::BO_Xor:
+ case BinaryOperatorKind::BO_Or:
+ case BinaryOperatorKind::BO_LAnd:
+ case BinaryOperatorKind::BO_LOr:
+ case BinaryOperatorKind::BO_Comma:
+ return true;
+ // Noncommutative operators:
+ case BinaryOperatorKind::BO_Div:
+ case BinaryOperatorKind::BO_Sub:
+ case BinaryOperatorKind::BO_Shl:
+ case BinaryOperatorKind::BO_Shr:
+ case BinaryOperatorKind::BO_Rem:
+ // Member access:
+ case BinaryOperatorKind::BO_PtrMemD:
+ case BinaryOperatorKind::BO_PtrMemI:
+ // Assignment:
+ case BinaryOperatorKind::BO_Assign:
+ case BinaryOperatorKind::BO_MulAssign:
+ case BinaryOperatorKind::BO_DivAssign:
+ case BinaryOperatorKind::BO_RemAssign:
+ case BinaryOperatorKind::BO_AddAssign:
+ case BinaryOperatorKind::BO_SubAssign:
+ case BinaryOperatorKind::BO_ShlAssign:
+ case BinaryOperatorKind::BO_ShrAssign:
+ case BinaryOperatorKind::BO_AndAssign:
+ case BinaryOperatorKind::BO_XorAssign:
+ case BinaryOperatorKind::BO_OrAssign:
+ return false;
+ }
+ return false;
+}
+
+/// Some operators are asymmetric and need to be flipped when swapping their
+/// operands
+/// @param[out] Opcode the opcode to potentially swap
+/// If the opcode does not need to be swapped or is not swappable, does nothing
+void swapOperator(BinaryOperatorKind &Opcode) {
+ switch (Opcode) {
+ case BinaryOperatorKind::BO_LT:
+ Opcode = BinaryOperatorKind::BO_GT;
+ return;
+ case BinaryOperatorKind::BO_GT:
+ Opcode = BinaryOperatorKind::BO_LT;
+ return;
+ case BinaryOperatorKind::BO_LE:
+ Opcode = BinaryOperatorKind::BO_GE;
+ return;
+ case BinaryOperatorKind::BO_GE:
+ Opcode = BinaryOperatorKind::BO_LE;
+ return;
+ case BinaryOperatorKind::BO_Mul:
+ case BinaryOperatorKind::BO_Add:
+ case BinaryOperatorKind::BO_Cmp:
+ case BinaryOperatorKind::BO_EQ:
+ case BinaryOperatorKind::BO_NE:
+ case BinaryOperatorKind::BO_And:
+ case BinaryOperatorKind::BO_Xor:
+ case BinaryOperatorKind::BO_Or:
+ case BinaryOperatorKind::BO_LAnd:
+ case BinaryOperatorKind::BO_LOr:
+ case BinaryOperatorKind::BO_Comma:
+ case BinaryOperatorKind::BO_Div:
+ case BinaryOperatorKind::BO_Sub:
+ case BinaryOperatorKind::BO_Shl:
+ case BinaryOperatorKind::BO_Shr:
+ case BinaryOperatorKind::BO_Rem:
+ case BinaryOperatorKind::BO_PtrMemD:
+ case BinaryOperatorKind::BO_PtrMemI:
+ case BinaryOperatorKind::BO_Assign:
+ case BinaryOperatorKind::BO_MulAssign:
+ case BinaryOperatorKind::BO_DivAssign:
+ case BinaryOperatorKind::BO_RemAssign:
+ case BinaryOperatorKind::BO_AddAssign:
+ case BinaryOperatorKind::BO_SubAssign:
+ case BinaryOperatorKind::BO_ShlAssign:
+ case BinaryOperatorKind::BO_ShrAssign:
+ case BinaryOperatorKind::BO_AndAssign:
+ case BinaryOperatorKind::BO_XorAssign:
+ case BinaryOperatorKind::BO_OrAssign:
+ return;
+ }
+}
+
+/// Swaps the operands to a binary operator
+/// Before:
+/// x != nullptr
+/// ^ ^^^^^^^
+/// After:
+/// nullptr != x
+class SwapBinaryOperands : public Tweak {
+public:
+ const char *id() const final;
+
+ bool prepare(const Selection &Inputs) override;
+ Expected<Effect> apply(const Selection &Inputs) override;
+ std::string title() const override {
+ return llvm::formatv("Swap operands to {0}",
+ Op ? Op->getOpcodeStr() : "binary operator");
+ }
+ llvm::StringLiteral kind() const override {
+ return CodeAction::REFACTOR_KIND;
+ }
+ bool hidden() const override { return false; }
+
+private:
+ const BinaryOperator *Op;
+};
+
+REGISTER_TWEAK(SwapBinaryOperands)
+
+bool SwapBinaryOperands::prepare(const Selection &Inputs) {
+ for (const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();
+ N && !Op; N = N->Parent) {
+ // Stop once we hit a block, e.g. a lambda in the if condition.
+ if (llvm::isa_and_nonnull<CompoundStmt>(N->ASTNode.get<Stmt>()))
+ return false;
+ Op = dyn_cast_or_null<BinaryOperator>(N->ASTNode.get<Stmt>());
+ // If we hit upon a nonswappable binary operator, ignore and keep going
+ if (Op && !isOpSwappable(Op->getOpcode())) {
+ Op = nullptr;
+ }
+ }
+ return Op != nullptr;
+}
+
+Expected<Tweak::Effect> SwapBinaryOperands::apply(const Selection &Inputs) {
+ auto &Ctx = Inputs.AST->getASTContext();
+ auto &SrcMgr = Inputs.AST->getSourceManager();
+
+ auto LHSRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
+ Op->getLHS()->getSourceRange());
+ if (!LHSRng)
+ return error(
+ "Could not obtain range of the 'lhs' of the operator. Macros?");
+ auto RHSRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
+ Op->getRHS()->getSourceRange());
+ if (!RHSRng)
+ return error(
+ "Could not obtain range of the 'rhs' of the operator. Macros?");
+ auto OpRng =
+ toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(), Op->getOperatorLoc());
+ if (!OpRng)
+ return error("Could not obtain range of the operator itself. Macros?");
+
+ auto LHSCode = toSourceCode(SrcMgr, *LHSRng);
+ auto RHSCode = toSourceCode(SrcMgr, *RHSRng);
+ auto OperatorCode = toSourceCode(SrcMgr, *OpRng);
+
+ tooling::Replacements Result;
+ if (auto Err = Result.add(tooling::Replacement(
+ Ctx.getSourceManager(), LHSRng->getBegin(), LHSCode.size(), RHSCode)))
+ return std::move(Err);
+ if (auto Err = Result.add(tooling::Replacement(
+ Ctx.getSourceManager(), RHSRng->getBegin(), RHSCode.size(), LHSCode)))
+ return std::move(Err);
+ auto SwappedOperator = Op->getOpcode();
+ swapOperator(SwappedOperator);
+ if (auto Err = Result.add(tooling::Replacement(
+ Ctx.getSourceManager(), OpRng->getBegin(), OperatorCode.size(),
+ Op->getOpcodeStr(SwappedOperator))))
+ return std::move(Err);
+ return Effect::mainFileEdit(SrcMgr, std::move(Result));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt
index 4fa9f18407ae9e..dffdcd5d014ca9 100644
--- a/clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -137,6 +137,7 @@ add_unittest(ClangdUnitTests ClangdTests
tweaks/ScopifyEnumTests.cpp
tweaks/ShowSelectionTreeTests.cpp
tweaks/SpecialMembersTests.cpp
+ tweaks/SwapBinaryOperandsTests.cpp
tweaks/SwapIfBranchesTests.cpp
tweaks/TweakTesting.cpp
tweaks/TweakTests.cpp
diff --git a/clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp
new file mode 100644
index 00000000000000..bbb2a576af6eb9
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp
@@ -0,0 +1,38 @@
+//===-- SwapBinaryOperandsTests.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-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+TWEAK_TEST(SwapBinaryOperands);
+
+TEST_F(SwapBinaryOperandsTest, Test) {
+ Context = Function;
+ EXPECT_EQ(apply("int *p = nullptr; bool c = ^p == nullptr;"),
+ "int *p = nullptr; bool c = nullptr == p;");
+ EXPECT_EQ(apply("int *p = nullptr; bool c = p ^== nullptr;"),
+ "int *p = nullptr; bool c = nullptr == p;");
+ EXPECT_EQ(apply("int x = 3; bool c = ^x >= 5;"),
+ "int x = 3; bool c = 5 <= x;");
+ EXPECT_EQ(apply("int x = 3; bool c = x >^= 5;"),
+ "int x = 3; bool c = 5 <= x;");
+ EXPECT_EQ(apply("int x = 3; bool c = x >=^ 5;"),
+ "int x = 3; bool c = 5 <= x;");
+ EXPECT_EQ(apply("int x = 3; bool c = x >=^ 5;"),
+ "int x = 3; bool c = 5 <= x;");
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clangd/refactor/tweaks/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clangd/refactor/tweaks/BUILD.gn
index 255dca3a6015a5..8d19295b4d3d84 100644
--- a/llvm/utils/gn/secondary/clang-tools-extra/clangd/refactor/tweaks/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang-tools-extra/clangd/refactor/tweaks/BUILD.gn
@@ -35,6 +35,7 @@ source_set("tweaks") {
"RemoveUsingNamespace.cpp",
"ScopifyEnum.cpp",
"SpecialMembers.cpp",
+ "SwapBinaryOperands.cpp",
"SwapIfBranches.cpp",
]
}
diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn
index b46bac97b41fa9..7deefe9dc06137 100644
--- a/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn
@@ -150,6 +150,7 @@ unittest("ClangdTests") {
"tweaks/ScopifyEnumTests.cpp",
"tweaks/ShowSelectionTreeTests.cpp",
"tweaks/SpecialMembersTests.cpp",
+ "tweaks/SwapBinaryOperandsTests.cpp",
"tweaks/SwapIfBranchesTests.cpp",
"tweaks/TweakTesting.cpp",
"tweaks/TweakTests.cpp",
>From 328e57a825c909d81fe866663d4551688567e67c Mon Sep 17 00:00:00 2001
From: Tor Shepherd <tor.aksel.shepherd at gmail.com>
Date: Mon, 23 Sep 2024 19:35:11 -0400
Subject: [PATCH 2/3] Schmidti comments
---
.../refactor/tweaks/SwapBinaryOperands.cpp | 62 ++++++++++---------
.../tweaks/SwapBinaryOperandsTests.cpp | 54 ++++++++++++++++
2 files changed, 88 insertions(+), 28 deletions(-)
diff --git a/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp
index 2241b0ac37b52a..1602093e3d2893 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/SwapBinaryOperands.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
#include "ParsedAST.h"
+#include "Protocol.h"
+#include "Selection.h"
#include "SourceCode.h"
#include "refactor/Tweak.h"
#include "support/Logger.h"
@@ -13,13 +15,14 @@
#include "clang/AST/Expr.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Stmt.h"
-#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/SourceManager.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/FormatVariadic.h"
+#include <string>
+#include <utility>
namespace clang {
namespace clangd {
@@ -29,11 +32,10 @@ namespace {
/// while keeping the meaning intact, whereas comparison operators, mathematical
/// operators, etc. are often desired to be swappable for readability, avoiding
/// bugs by assigning to nullptr when comparison was desired, etc.
-auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool {
+bool isOpSwappable(const BinaryOperatorKind Opcode) {
switch (Opcode) {
case BinaryOperatorKind::BO_Mul:
case BinaryOperatorKind::BO_Add:
- case BinaryOperatorKind::BO_Cmp:
case BinaryOperatorKind::BO_LT:
case BinaryOperatorKind::BO_GT:
case BinaryOperatorKind::BO_LE:
@@ -53,6 +55,8 @@ auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool {
case BinaryOperatorKind::BO_Shl:
case BinaryOperatorKind::BO_Shr:
case BinaryOperatorKind::BO_Rem:
+ // <=> is noncommutative
+ case BinaryOperatorKind::BO_Cmp:
// Member access:
case BinaryOperatorKind::BO_PtrMemD:
case BinaryOperatorKind::BO_PtrMemI:
@@ -77,20 +81,20 @@ auto isOpSwappable(const BinaryOperatorKind Opcode) -> bool {
/// operands
/// @param[out] Opcode the opcode to potentially swap
/// If the opcode does not need to be swapped or is not swappable, does nothing
-void swapOperator(BinaryOperatorKind &Opcode) {
+BinaryOperatorKind swapOperator(const BinaryOperatorKind Opcode) {
switch (Opcode) {
case BinaryOperatorKind::BO_LT:
- Opcode = BinaryOperatorKind::BO_GT;
- return;
+ return BinaryOperatorKind::BO_GT;
+
case BinaryOperatorKind::BO_GT:
- Opcode = BinaryOperatorKind::BO_LT;
- return;
+ return BinaryOperatorKind::BO_LT;
+
case BinaryOperatorKind::BO_LE:
- Opcode = BinaryOperatorKind::BO_GE;
- return;
+ return BinaryOperatorKind::BO_GE;
+
case BinaryOperatorKind::BO_GE:
- Opcode = BinaryOperatorKind::BO_LE;
- return;
+ return BinaryOperatorKind::BO_LE;
+
case BinaryOperatorKind::BO_Mul:
case BinaryOperatorKind::BO_Add:
case BinaryOperatorKind::BO_Cmp:
@@ -120,7 +124,7 @@ void swapOperator(BinaryOperatorKind &Opcode) {
case BinaryOperatorKind::BO_AndAssign:
case BinaryOperatorKind::BO_XorAssign:
case BinaryOperatorKind::BO_OrAssign:
- return;
+ return Opcode;
}
}
@@ -154,7 +158,10 @@ REGISTER_TWEAK(SwapBinaryOperands)
bool SwapBinaryOperands::prepare(const Selection &Inputs) {
for (const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();
N && !Op; N = N->Parent) {
- // Stop once we hit a block, e.g. a lambda in the if condition.
+ // Stop once we hit a block, e.g. a lambda in one of the operands.
+ // This makes sure that the selection point is in the 'scope' of the binary
+ // operator, not from somewhere inside a lambda for example
+ // (5 < [](){ ^return 1; })
if (llvm::isa_and_nonnull<CompoundStmt>(N->ASTNode.get<Stmt>()))
return false;
Op = dyn_cast_or_null<BinaryOperator>(N->ASTNode.get<Stmt>());
@@ -167,27 +174,27 @@ bool SwapBinaryOperands::prepare(const Selection &Inputs) {
}
Expected<Tweak::Effect> SwapBinaryOperands::apply(const Selection &Inputs) {
- auto &Ctx = Inputs.AST->getASTContext();
- auto &SrcMgr = Inputs.AST->getSourceManager();
+ const auto &Ctx = Inputs.AST->getASTContext();
+ const auto &SrcMgr = Inputs.AST->getSourceManager();
- auto LHSRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
- Op->getLHS()->getSourceRange());
+ const auto LHSRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
+ Op->getLHS()->getSourceRange());
if (!LHSRng)
return error(
"Could not obtain range of the 'lhs' of the operator. Macros?");
- auto RHSRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
- Op->getRHS()->getSourceRange());
+ const auto RHSRng = toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(),
+ Op->getRHS()->getSourceRange());
if (!RHSRng)
return error(
"Could not obtain range of the 'rhs' of the operator. Macros?");
- auto OpRng =
+ const auto OpRng =
toHalfOpenFileRange(SrcMgr, Ctx.getLangOpts(), Op->getOperatorLoc());
if (!OpRng)
return error("Could not obtain range of the operator itself. Macros?");
- auto LHSCode = toSourceCode(SrcMgr, *LHSRng);
- auto RHSCode = toSourceCode(SrcMgr, *RHSRng);
- auto OperatorCode = toSourceCode(SrcMgr, *OpRng);
+ const auto LHSCode = toSourceCode(SrcMgr, *LHSRng);
+ const auto RHSCode = toSourceCode(SrcMgr, *RHSRng);
+ const auto OperatorCode = toSourceCode(SrcMgr, *OpRng);
tooling::Replacements Result;
if (auto Err = Result.add(tooling::Replacement(
@@ -196,8 +203,7 @@ Expected<Tweak::Effect> SwapBinaryOperands::apply(const Selection &Inputs) {
if (auto Err = Result.add(tooling::Replacement(
Ctx.getSourceManager(), RHSRng->getBegin(), RHSCode.size(), LHSCode)))
return std::move(Err);
- auto SwappedOperator = Op->getOpcode();
- swapOperator(SwappedOperator);
+ const auto SwappedOperator = swapOperator(Op->getOpcode());
if (auto Err = Result.add(tooling::Replacement(
Ctx.getSourceManager(), OpRng->getBegin(), OperatorCode.size(),
Op->getOpcodeStr(SwappedOperator))))
diff --git a/clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp
index bbb2a576af6eb9..e157bbefbdaaf7 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/SwapBinaryOperandsTests.cpp
@@ -31,6 +31,60 @@ TEST_F(SwapBinaryOperandsTest, Test) {
"int x = 3; bool c = 5 <= x;");
EXPECT_EQ(apply("int x = 3; bool c = x >=^ 5;"),
"int x = 3; bool c = 5 <= x;");
+ EXPECT_EQ(apply("int f(); int x = 3; bool c = x >=^ f();"),
+ "int f(); int x = 3; bool c = f() <= x;");
+ EXPECT_EQ(apply(R"cpp(
+ int f();
+ #define F f
+ int x = 3; bool c = x >=^ F();
+ )cpp"),
+ R"cpp(
+ int f();
+ #define F f
+ int x = 3; bool c = F() <= x;
+ )cpp");
+ EXPECT_EQ(apply(R"cpp(
+ int f();
+ #define F f()
+ int x = 3; bool c = x >=^ F;
+ )cpp"),
+ R"cpp(
+ int f();
+ #define F f()
+ int x = 3; bool c = F <= x;
+ )cpp");
+ EXPECT_EQ(apply(R"cpp(
+ int f(bool);
+ #define F(v) f(v)
+ int x = 0;
+ bool c = F(x^ < 5);
+ )cpp"),
+ R"cpp(
+ int f(bool);
+ #define F(v) f(v)
+ int x = 0;
+ bool c = F(5 > x);
+ )cpp");
+ ExtraArgs = {"-std=c++20"};
+ Context = CodeContext::File;
+ EXPECT_UNAVAILABLE(R"cpp(
+ namespace std {
+ struct strong_ordering {
+ int val;
+ static const strong_ordering less;
+ static const strong_ordering equivalent;
+ static const strong_ordering equal;
+ static const strong_ordering greater;
+ };
+ inline constexpr strong_ordering strong_ordering::less {-1};
+ inline constexpr strong_ordering strong_ordering::equivalent {0};
+ inline constexpr strong_ordering strong_ordering::equal {0};
+ inline constexpr strong_ordering strong_ordering::greater {1};
+ };
+ #define F(v) v
+ int x = 0;
+ auto c = F(5^ <=> x);
+ )cpp");
}
} // namespace
>From b9120726aca7a2c5234f063795d75548b290a7ab Mon Sep 17 00:00:00 2001
From: Tor Shepherd <tor.aksel.shepherd at gmail.com>
Date: Mon, 23 Sep 2024 19:46:27 -0400
Subject: [PATCH 3/3] Trying my hand at rel notes
---
clang-tools-extra/docs/ReleaseNotes.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8f7b0b5333f3a1..ff287da2cd3cc4 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -74,6 +74,8 @@ Code completion
Code actions
^^^^^^^^^^^^
+- Added `Swap operands` tweak for certain binary operators.
+
Signature help
^^^^^^^^^^^^^^
More information about the llvm-commits
mailing list