Skip to content

Commit

Permalink
[CodeQuality] Add SwitchTrueToIfRector (#3535)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Mar 29, 2023
1 parent 8ff7747 commit 26e570f
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 5 deletions.
2 changes: 2 additions & 0 deletions config/set/code-quality.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
use Rector\CodeQuality\Rector\NotEqual\CommonNotEqualRector;
use Rector\CodeQuality\Rector\PropertyFetch\ExplicitMethodCallOverMagicGetSetRector;
use Rector\CodeQuality\Rector\Switch_\SingularSwitchToIfRector;
use Rector\CodeQuality\Rector\Switch_\SwitchTrueToIfRector;
use Rector\CodeQuality\Rector\Ternary\ArrayKeyExistsTernaryThenValueToCoalescingRector;
use Rector\CodeQuality\Rector\Ternary\SimplifyTautologyTernaryRector;
use Rector\CodeQuality\Rector\Ternary\SwitchNegatedTernaryRector;
Expand Down Expand Up @@ -199,5 +200,6 @@
TernaryEmptyArrayArrayDimFetchToCoalesceRector::class,
OptionalParametersAfterRequiredRector::class,
SimplifyEmptyCheckOnEmptyArrayRector::class,
SwitchTrueToIfRector::class,
]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Switch_\SwitchTrueToIfRector\Fixture;

class SkipFalse
{
public function run()
{
switch (false) {
case $value === 0:
return 'no';
case $value === 1:
return 'yes';
case $value === 2:
return 'maybe';
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Switch_\SwitchTrueToIfRector\Fixture;

class SomeClass
{
public function run()
{
switch (true) {
case $value === 0:
return 'no';
case $value === 1:
return 'yes';
case $value === 2:
return 'maybe';
};
}
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Switch_\SwitchTrueToIfRector\Fixture;

class SomeClass
{
public function run()
{
if ($value === 0) {
return 'no';
}
if ($value === 1) {
return 'yes';
}
if ($value === 2) {
return 'maybe';
}
}
}

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

namespace Rector\Tests\CodeQuality\Rector\Switch_\SwitchTrueToIfRector\Fixture;

class WithDefault
{
public function run()
{
switch (true) {
case $value === 0:
return 'no';
case $value === 1:
return 'yes';
case $value === 2:
return 'maybe';
default:
return 'nevermind';
};
}
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Switch_\SwitchTrueToIfRector\Fixture;

class WithDefault
{
public function run()
{
if ($value === 0) {
return 'no';
}
if ($value === 1) {
return 'yes';
}
if ($value === 2) {
return 'maybe';
}
return 'nevermind';
}
}

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

declare(strict_types=1);

namespace Rector\Tests\CodeQuality\Rector\Switch_\SwitchTrueToIfRector;

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

final class SwitchTrueToIfRectorTest 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,10 @@
<?php

declare(strict_types=1);

use Rector\CodeQuality\Rector\Switch_\SwitchTrueToIfRector;
use Rector\Config\RectorConfig;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(SwitchTrueToIfRector::class);
};
107 changes: 107 additions & 0 deletions rules/CodeQuality/Rector/Switch_/SwitchTrueToIfRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace Rector\CodeQuality\Rector\Switch_;

use PhpParser\Node\Expr;
use PhpParser\Node;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Switch_;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\CodeQuality\Rector\Switch_\SwitchTrueToIfRector\SwitchTrueToIfRectorTest
*/
final class SwitchTrueToIfRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change switch (true) to if statements', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
switch (true) {
case $value === 0:
return 'no';
case $value === 1:
return 'yes';
case $value === 2:
return 'maybe';
};
}
}
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
if ($value === 0) {
return 'no';
}
if ($value === 1) {
return 'yes';
}
if ($value === 2) {
return 'maybe';
}
}
}
CODE_SAMPLE
),
]);
}

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

/**
* @param Switch_ $node
* @return Stmt[]|null
*/
public function refactor(Node $node): ?array
{
if (! $this->valueResolver->isTrue($node->cond)) {
return null;
}

$newStmts = [];

$defaultCase = null;

foreach ($node->cases as $case) {
if (! $case->cond instanceof Expr) {
$defaultCase = $case;
continue;
}

$if = new If_($case->cond);
$if->stmts = $case->stmts;

$newStmts[] = $if;
}

if ($defaultCase instanceof Case_) {
return array_merge($newStmts, $defaultCase->stmts);
}

return $newStmts;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ public function refactor(Node $node): ?Node
if (! $node->isFinal()) {
return null;
}

$classReflection = $this->reflectionResolver->resolveClassAndAnonymousClass($node);
$hasChanged = false;

foreach ($node->getMethods() as $classMethod) {
if ($this->shouldSkipClassMethod($classMethod)) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion src/PhpParser/NodeTraverser/NodeConnectingTraverser.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ final class NodeConnectingTraverser extends NodeTraverser
public function __construct()
{
parent::__construct();

$this->addVisitor(new NodeConnectingVisitor());
}
}
5 changes: 3 additions & 2 deletions src/PhpParser/Parser/SimplePhpParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ final class SimplePhpParser
{
private readonly Parser $phpParser;

public function __construct(private readonly NodeConnectingTraverser $nodeConnectingTraverser)
{
public function __construct(
private readonly NodeConnectingTraverser $nodeConnectingTraverser
) {
$parserFactory = new ParserFactory();
$this->phpParser = $parserFactory->create(ParserFactory::PREFER_PHP7);
}
Expand Down

0 comments on commit 26e570f

Please sign in to comment.