diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/BinaryOpStandaloneAssignsToDirectRectorTest.php b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/BinaryOpStandaloneAssignsToDirectRectorTest.php new file mode 100644 index 00000000000..66dba79b1ac --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/BinaryOpStandaloneAssignsToDirectRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_different_order.php.inc b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_different_order.php.inc new file mode 100644 index 00000000000..063f1eff01b --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_different_order.php.inc @@ -0,0 +1,14 @@ +createLongValue(100); + $second = $this->createLongValue(200); + + return $first <=> $second; + } + + private function createLongValue($value) + { + return $value . ' is long'; + } +} diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_non_variable_assign.php.inc b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_non_variable_assign.php.inc new file mode 100644 index 00000000000..f5097685fdd --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_non_variable_assign.php.inc @@ -0,0 +1,16 @@ +number = 200; + + return $first <=> $this->number; + } +} diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/some_separated_assign.php.inc b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/some_separated_assign.php.inc new file mode 100644 index 00000000000..de72da9b732 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/some_separated_assign.php.inc @@ -0,0 +1,30 @@ + $second; + } +} + +?> +----- + 200; + } +} + +?> diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/config/configured_rule.php b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/config/configured_rule.php new file mode 100644 index 00000000000..6fc5475f4f8 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/config/configured_rule.php @@ -0,0 +1,9 @@ +withRules([BinaryOpStandaloneAssignsToDirectRector::class]); diff --git a/rules/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector.php b/rules/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector.php new file mode 100644 index 00000000000..4a796e1bf53 --- /dev/null +++ b/rules/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector.php @@ -0,0 +1,142 @@ + 200; +} +CODE_SAMPLE + + , + <<<'CODE_SAMPLE' +function run() +{ + return 100 <=> 200; +} +CODE_SAMPLE + ), + ]); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [ClassMethod::class, Function_::class, Closure::class]; + } + + /** + * @param ClassMethod|Function_|Closure $node + */ + public function refactor(Node $node): ?Node + { + if ($node->stmts === null) { + return null; + } + + if (count($node->stmts) !== 3) { + return null; + } + + $firstStmt = $node->stmts[0]; + $secondStmt = $node->stmts[1]; + $thirdStmt = $node->stmts[2]; + + if (! $thirdStmt instanceof Return_) { + return null; + } + + $firstVariableAndExprAssign = $this->matchToVariableAssignExpr($firstStmt); + if (! $firstVariableAndExprAssign instanceof VariableAndExprAssign) { + return null; + } + + $secondVariableAndExprAssign = $this->matchToVariableAssignExpr($secondStmt); + if (! $secondVariableAndExprAssign instanceof VariableAndExprAssign) { + return null; + } + + if (! $thirdStmt->expr instanceof BinaryOp) { + return null; + } + + $binaryOp = $thirdStmt->expr; + + if (! $this->nodeComparator->areNodesEqual($binaryOp->left, $firstVariableAndExprAssign->getVariable())) { + return null; + } + + if (! $this->nodeComparator->areNodesEqual($binaryOp->right, $secondVariableAndExprAssign->getVariable())) { + return null; + } + + $binaryOp->left = $firstVariableAndExprAssign->getExpr(); + $binaryOp->right = $secondVariableAndExprAssign->getExpr(); + + $node->stmts = [$thirdStmt]; + return $node; + } + + public function provideMinPhpVersion(): int + { + return PhpVersionFeature::VARIADIC_PARAM; + } + + private function matchToVariableAssignExpr(Stmt $stmt): ?VariableAndExprAssign + { + if (! $stmt instanceof Expression) { + return null; + } + + if (! $stmt->expr instanceof Assign) { + return null; + } + + $assign = $stmt->expr; + if (! $assign->var instanceof Variable) { + return null; + } + + // skip complex cases + if ($assign->expr instanceof MethodCall) { + return null; + } + + return new VariableAndExprAssign($assign->var, $assign->expr); + } +} diff --git a/rules/CodingStyle/ValueObject/VariableAndExprAssign.php b/rules/CodingStyle/ValueObject/VariableAndExprAssign.php new file mode 100644 index 00000000000..dc5bb7295e9 --- /dev/null +++ b/rules/CodingStyle/ValueObject/VariableAndExprAssign.php @@ -0,0 +1,27 @@ +variable; + } + + public function getExpr(): Expr + { + return $this->expr; + } +} diff --git a/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTagRemover.php b/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTagRemover.php index dc30d22f725..d808b41ca95 100644 --- a/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTagRemover.php +++ b/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTagRemover.php @@ -66,9 +66,6 @@ public function removeTagValueFromNode(PhpDocInfo $phpDocInfo, Node $desiredNode private function areAnnotationNamesEqual(string $firstAnnotationName, string $secondAnnotationName): bool { - $firstAnnotationName = trim($firstAnnotationName, '@'); - $secondAnnotationName = trim($secondAnnotationName, '@'); - - return $firstAnnotationName === $secondAnnotationName; + return trim($firstAnnotationName, '@') === trim($secondAnnotationName, '@'); } } diff --git a/src/Config/Level/CodingStyleLevel.php b/src/Config/Level/CodingStyleLevel.php index 70310ea85b5..3c3ad692ee5 100644 --- a/src/Config/Level/CodingStyleLevel.php +++ b/src/Config/Level/CodingStyleLevel.php @@ -8,6 +8,7 @@ use Rector\CodingStyle\Rector\Catch_\CatchExceptionNameMatchingTypeRector; use Rector\CodingStyle\Rector\ClassConst\RemoveFinalFromConstRector; use Rector\CodingStyle\Rector\ClassConst\SplitGroupedClassConstantsRector; +use Rector\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector; use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector; use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector; use Rector\CodingStyle\Rector\ClassMethod\NewlineBeforeNewAssignSetRector; @@ -77,6 +78,7 @@ final class CodingStyleLevel SplitGroupedClassConstantsRector::class, ExplicitPublicClassMethodRector::class, RemoveUselessAliasInUseStatementRector::class, + BinaryOpStandaloneAssignsToDirectRector::class, ]; /**