[DowngradePhp74] Add DowngradePreviouslyImplementedInterfaceRector (#1159)

This commit is contained in:
Abdul Malik Ikhsan 2021-11-06 05:22:41 +07:00 committed by GitHub
parent e79aa9d760
commit b218e334ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 259 additions and 2 deletions

View File

@ -1,4 +1,4 @@
# 476 Rules Overview
# 477 Rules Overview
<br>
@ -32,7 +32,7 @@
- [DowngradePhp73](#downgradephp73) (6)
- [DowngradePhp74](#downgradephp74) (10)
- [DowngradePhp74](#downgradephp74) (11)
- [DowngradePhp80](#downgradephp80) (18)
@ -4921,6 +4921,25 @@ Remove "_" as thousands separator in numbers
<br>
### DowngradePreviouslyImplementedInterfaceRector
Downgrade previously implemented interface
- class: [`Rector\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector`](../rules/DowngradePhp74/Rector/Interface_/DowngradePreviouslyImplementedInterfaceRector.php)
```diff
interface ContainerExceptionInterface extends Throwable
{
}
-interface ExceptionInterface extends ContainerExceptionInterface, Throwable
+interface ExceptionInterface extends ContainerExceptionInterface
{
}
```
<br>
### DowngradeStripTagsCallWithArrayRector
Convert 2nd param to `strip_tags` from array to string

View File

@ -12,6 +12,7 @@ use Rector\DowngradePhp74\Rector\Coalesce\DowngradeNullCoalescingOperatorRector;
use Rector\DowngradePhp74\Rector\FuncCall\DowngradeArrayMergeCallWithoutArgumentsRector;
use Rector\DowngradePhp74\Rector\FuncCall\DowngradeStripTagsCallWithArrayRector;
use Rector\DowngradePhp74\Rector\Identical\DowngradeFreadFwriteFalsyToNegationRector;
use Rector\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector;
use Rector\DowngradePhp74\Rector\LNumber\DowngradeNumericLiteralSeparatorRector;
use Rector\DowngradePhp74\Rector\Property\DowngradeTypedPropertyRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
@ -31,4 +32,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(DowngradeArraySpreadRector::class);
$services->set(DowngradeArrayMergeCallWithoutArgumentsRector::class);
$services->set(DowngradeFreadFwriteFalsyToNegationRector::class);
$services->set(DowngradePreviouslyImplementedInterfaceRector::class);
};

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DowngradePreviouslyImplementedInterfaceRectorTest extends AbstractRectorTestCase
{
/**
* @requires PHP 7.4
* @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';
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Fixture;
use Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source\ContainerExceptionInterface;
interface ExceptionInterface extends ContainerExceptionInterface, \Throwable
{
}
?>
-----
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Fixture;
use Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source\ContainerExceptionInterface;
interface ExceptionInterface extends ContainerExceptionInterface
{
}
?>

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Fixture;
use Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source\ContainerInterface;
use Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source\FooInterface;
interface SkipExtendNoRelation extends ContainerInterface, FooInterface
{
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Fixture;
use Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source\ContainerInterface;
interface SkipExtendSingle extends ContainerInterface
{
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Fixture;
interface SkipNoExtends
{
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source;
interface ContainerExceptionInterface extends \Throwable
{
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source;
interface ContainerInterface
{
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\Source;
interface FooInterface
{
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
use Rector\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(DowngradePreviouslyImplementedInterfaceRector::class);
};

View File

@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
namespace Rector\DowngradePhp74\Rector\Interface_;
use PhpParser\Node;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Interface_;
use Rector\Core\Rector\AbstractRector;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\DowngradePhp74\Rector\Interface_\DowngradePreviouslyImplementedInterfaceRector\DowngradePreviouslyImplementedInterfaceRectorTest
*/
final class DowngradePreviouslyImplementedInterfaceRector extends AbstractRector
{
public function __construct(
private FamilyRelationsAnalyzer $familyRelationsAnalyzer
) {
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Downgrade previously implemented interface',
[
new CodeSample(
<<<'CODE_SAMPLE'
interface ContainerExceptionInterface extends Throwable
{
}
interface ExceptionInterface extends ContainerExceptionInterface, Throwable
{
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
interface ContainerExceptionInterface extends Throwable
{
}
interface ExceptionInterface extends ContainerExceptionInterface
{
}
CODE_SAMPLE
),
]
);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Interface_::class];
}
/**
* @param Interface_ $node
*/
public function refactor(Node $node): ?Node
{
$extends = $node->extends;
if ($extends === []) {
return null;
}
if (count($extends) === 1) {
return null;
}
$collectInterfaces = [];
$isCleaned = false;
foreach ($extends as $key => $extend) {
if (! $extend instanceof FullyQualified) {
continue;
}
if (in_array($extend->toString(), $collectInterfaces, true)) {
unset($extends[$key]);
$isCleaned = true;
continue;
}
$collectInterfaces = array_merge(
$collectInterfaces,
$this->familyRelationsAnalyzer->getClassLikeAncestorNames($extend)
);
}
if (! $isCleaned) {
return null;
}
$node->extends = $extends;
return $node;
}
}