Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector;

use Iterator;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class BinaryOpStandaloneAssignsToDirectRectorTest extends AbstractRectorTestCase
{
#[DataProvider('provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public static function provideData(): Iterator
{
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture;

final class SkipDifferentOrder
{
public function run()
{
$first = 100;
$second = 200;

return $second ** $first;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture;

final class SkipMethodCallsToKeepReadability
{
public function run()
{
$first = $this->createLongValue(100);
$second = $this->createLongValue(200);

return $first <=> $second;
}

private function createLongValue($value)
{
return $value . ' is long';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture;

final class SkipNonVariableAssign
{
private $number;

public function run()
{
$first = 100;
$this->number = 200;

return $first <=> $this->number;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture;

final class SomeSeparatedAssign
{
public function run()
{
$first = 100;
$second = 200;

return $first <=> $second;
}
}

?>
-----
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture;

final class SomeSeparatedAssign
{
public function run()
{
return 100 <=> 200;
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

use Rector\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
->withRules([BinaryOpStandaloneAssignsToDirectRector::class]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php

declare(strict_types=1);

namespace Rector\CodingStyle\Rector\ClassMethod;

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
use Rector\CodingStyle\ValueObject\VariableAndExprAssign;
use Rector\Rector\AbstractRector;
use Rector\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\BinaryOpStandaloneAssignsToDirectRectorTest
*/
final class BinaryOpStandaloneAssignsToDirectRector extends AbstractRector implements MinPhpVersionInterface
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change 2 standalone assigns to variable then binary op to direct binary op', [
new CodeSample(
<<<'CODE_SAMPLE'
function run()
{
$value = 100;
$anotherValue = 200;

return 100 <=> 200;
}
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
function run()
{
return 100 <=> 200;
}
CODE_SAMPLE
),
]);
}

/**
* @return array<class-string<Node>>
*/
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);
}
}
27 changes: 27 additions & 0 deletions rules/CodingStyle/ValueObject/VariableAndExprAssign.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Rector\CodingStyle\ValueObject;

use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Variable;

final readonly class VariableAndExprAssign
{
public function __construct(
private Variable $variable,
private Expr $expr,
) {
}

public function getVariable(): Variable
{
return $this->variable;
}

public function getExpr(): Expr
{
return $this->expr;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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, '@');
}
}
2 changes: 2 additions & 0 deletions src/Config/Level/CodingStyleLevel.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -77,6 +78,7 @@ final class CodingStyleLevel
SplitGroupedClassConstantsRector::class,
ExplicitPublicClassMethodRector::class,
RemoveUselessAliasInUseStatementRector::class,
BinaryOpStandaloneAssignsToDirectRector::class,
];

/**
Expand Down