Skip to content

Commit

Permalink
[CodeQuality] Add DoWhileBreakFalseToIfElseRector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Nov 13, 2021
1 parent 305c524 commit aaf1a43
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class DoWhileBreakFalseToIfElseRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}

/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->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,35 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

do {
if (mt_rand(0, 1)) {
$value = 5;
break;
}

if (mt_rand(0, 2)) {
$value = 10;
break;
}

$value = 25;
} while (false);

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

if (mt_rand(0, 1)) {
$value = 5;
} else {
if (mt_rand(0, 2)) {
$value = 10;
} else {
$value = 25;
}
}

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

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

do {
if (mt_rand(0, 1)) {
$value = 5;
break;
} else {
$value = 10;
}
} while (false);

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

if (mt_rand(0, 1)) {
$value = 5;
} else {
$value = 10;
}

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

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

do {
if (mt_rand(0, 1)) {
$value = 5;
break;
}
} while (false);

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

if (mt_rand(0, 1)) {
$value = 5;
}

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

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

do {
if (mt_rand(0, 1)) {
$value = 5;
break;
}

$value = 10;
} while (false);

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\Fixture;

if (mt_rand(0, 1)) {
$value = 5;
} else {
$value = 10;
}

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

declare(strict_types=1);

use Rector\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(DoWhileBreakFalseToIfElseRector::class);
};
117 changes: 117 additions & 0 deletions rules/CodeQuality/Rector/Do_/DoWhileBreakFalseToIfElseRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

declare(strict_types=1);

namespace Rector\CodeQuality\Rector\Do_;

use PhpParser\Node;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Break_;
use PhpParser\Node\Stmt\Do_;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\If_;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\CodeQuality\Rector\Do_\DoWhileBreakFalseToIfElseRector\DoWhileBreakFalseToIfElseRectorTest
*/
final class DoWhileBreakFalseToIfElseRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Replace do (...} while (false); with more readable if/else conditions', [
new CodeSample(
<<<'CODE_SAMPLE'
do {
if (mt_rand(0, 1)) {
$value = 5;
break;
}
$value = 10;
} while (false);
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
if (mt_rand(0, 1)) {
$value = 5;
} else {
$value = 10;
}
CODE_SAMPLE
),
]);
}

/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Do_::class];
}

/**
* @param Do_ $node
*/
public function refactor(Node $node)
{
if (! $this->valueResolver->isFalse($node->cond)) {
return null;
}

$currentStmts = $node->stmts;
return $this->resolveNewStmts($currentStmts);
}

/**
* @param Stmt[] $currentStmts
* @return Stmt[]
*/
private function resolveNewStmts(array $currentStmts): array
{
$foundBreak = $this->betterNodeFinder->findFirstInstanceOf($currentStmts, Break_::class);
if (! $foundBreak instanceof Break_) {
return $currentStmts;
}

$newStmts = [];

foreach ($currentStmts as $key => $currentStmt) {
$foundBreak = $this->betterNodeFinder->findFirstInstanceOf($currentStmt, Break_::class);
if (! $foundBreak instanceof Break_) {
continue;
}

$this->removeNode($foundBreak);

// collect rest of nodes
$restOfStmts = array_slice($currentStmts, $key + 1, count($currentStmts));

$currentIf = $currentStmt instanceof If_
? $currentStmt
: $this->betterNodeFinder->findInstanceOf($currentStmt, If_::class);

if (! $currentIf instanceof If_) {
continue;
}

// reprint new tokens
$currentIf->setAttribute(AttributeKey::ORIGINAL_NODE, null);

if ($restOfStmts !== []) {
$restOfStmts = $this->resolveNewStmts($restOfStmts);
$currentIf->else = new Else_($restOfStmts);
}

$newStmts[] = $currentStmt;
break;
}

return $newStmts;
}
}

0 comments on commit aaf1a43

Please sign in to comment.