mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 22:08:00 +01:00
[PHP] Add ReservedObjectRector
This commit is contained in:
parent
0c65b0e09a
commit
2ffb04a229
@ -1,2 +1,5 @@
|
|||||||
services:
|
services:
|
||||||
Rector\Php\Rector\BinaryOp\IsIterableRector: ~
|
Rector\Php\Rector\BinaryOp\IsIterableRector: ~
|
||||||
|
Rector\Php\Rector\Name\ReservedObjectRector:
|
||||||
|
$reservedKeywordsToReplacements:
|
||||||
|
Object: 'BaseObject'
|
||||||
|
110
packages/Php/src/Rector/Name/ReservedObjectRector.php
Normal file
110
packages/Php/src/Rector/Name/ReservedObjectRector.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Php\Rector\Name;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Stmt\Namespace_;
|
||||||
|
use Rector\NodeTypeResolver\Node\Attribute;
|
||||||
|
use Rector\Rector\AbstractRector;
|
||||||
|
use Rector\RectorDefinition\CodeSample;
|
||||||
|
use Rector\RectorDefinition\RectorDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://wiki.php.net/rfc/object-typehint
|
||||||
|
*
|
||||||
|
* @see https://github.com/cebe/yii2/commit/9548a212ecf6e50fcdb0e5ba6daad88019cfc544
|
||||||
|
*/
|
||||||
|
final class ReservedObjectRector extends AbstractRector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $reservedKeywordsToReplacements = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $reservedKeywordsToReplacements
|
||||||
|
*/
|
||||||
|
public function __construct(array $reservedKeywordsToReplacements)
|
||||||
|
{
|
||||||
|
$this->reservedKeywordsToReplacements = $reservedKeywordsToReplacements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefinition(): RectorDefinition
|
||||||
|
{
|
||||||
|
return new RectorDefinition(
|
||||||
|
'Changes reserved "Object" name to "<Smart>Object" where <Smart> can be configured',
|
||||||
|
[
|
||||||
|
new CodeSample(
|
||||||
|
<<<'CODE_SAMPLE'
|
||||||
|
class Object
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CODE_SAMPLE
|
||||||
|
,
|
||||||
|
<<<'CODE_SAMPLE'
|
||||||
|
class SmartObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CODE_SAMPLE
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getNodeTypes(): array
|
||||||
|
{
|
||||||
|
return [Identifier::class, Name::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Identifier|Name $node
|
||||||
|
*/
|
||||||
|
public function refactor(Node $node): ?Node
|
||||||
|
{
|
||||||
|
if ($node instanceof Identifier) {
|
||||||
|
return $this->processIdentifier($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node instanceof Name) {
|
||||||
|
return $this->processName($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processIdentifier(Identifier $identifierNode): Identifier
|
||||||
|
{
|
||||||
|
foreach ($this->reservedKeywordsToReplacements as $reservedKeyword => $replacement) {
|
||||||
|
if (strtolower($identifierNode->name) === strtolower($reservedKeyword)) {
|
||||||
|
$identifierNode->name = $replacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $identifierNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processName(Name $nameNode): Name
|
||||||
|
{
|
||||||
|
// we look for "extends <Name>"
|
||||||
|
$parentNode = $nameNode->getAttribute(Attribute::PARENT_NODE);
|
||||||
|
// "Object" can part of namespace name
|
||||||
|
if ($parentNode instanceof Namespace_) {
|
||||||
|
return $nameNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process lass part
|
||||||
|
foreach ($this->reservedKeywordsToReplacements as $reservedKeyword => $replacement) {
|
||||||
|
if (strtolower($nameNode->getLast()) === strtolower($reservedKeyword)) {
|
||||||
|
$nameNode->parts[count($nameNode->parts) - 1] = $replacement;
|
||||||
|
$nameNode->setAttribute(Attribute::ORIGINAL_NODE, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nameNode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong;
|
||||||
|
|
||||||
|
class SmartObject
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChildObject extends \Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong\SmartObject
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$some = new ChildObject();
|
||||||
|
if ($some instanceof \Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong\SmartObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_subclass_of($some, \Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong\SmartObject::class);
|
||||||
|
|
||||||
|
is_a($some, \Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong\SmartObject::class);
|
||||||
|
|
||||||
|
function someFunction(\Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong\SmartObject $reservedObject): \Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong\SmartObject {
|
||||||
|
return $reservedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
$someObject = new \Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong\SmartObject;
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Php\Tests\Rector\Name\ReservedObjectRector;
|
||||||
|
|
||||||
|
use Iterator;
|
||||||
|
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Rector\Php\Rector\Name\ReservedObjectRector
|
||||||
|
*/
|
||||||
|
final class ReservedObjectRectorTest extends AbstractRectorTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider provideWrongToFixedFiles()
|
||||||
|
*/
|
||||||
|
public function test(string $wrong, string $fixed): void
|
||||||
|
{
|
||||||
|
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideWrongToFixedFiles(): Iterator
|
||||||
|
{
|
||||||
|
// it needs to have different name, since in PHP 7.1 it already reserved
|
||||||
|
yield [__DIR__ . '/Wrong/ReservedObject.php', __DIR__ . '/Correct/correct.php.inc'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function provideConfig(): string
|
||||||
|
{
|
||||||
|
return __DIR__ . '/config.yml';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Php\Tests\Rector\Name\ReservedObjectRector\Wrong;
|
||||||
|
|
||||||
|
class ReservedObject
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChildObject extends ReservedObject
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$some = new ChildObject();
|
||||||
|
if ($some instanceof ReservedObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_subclass_of($some, ReservedObject::class);
|
||||||
|
|
||||||
|
is_a($some, ReservedObject::class);
|
||||||
|
|
||||||
|
function someFunction(ReservedObject $reservedObject): ReservedObject {
|
||||||
|
return $reservedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
$someObject = new ReservedObject;
|
@ -0,0 +1,5 @@
|
|||||||
|
services:
|
||||||
|
Rector\Php\Rector\Name\ReservedObjectRector:
|
||||||
|
# todo make work even without these explicit variables
|
||||||
|
$reservedKeywordsToReplacements:
|
||||||
|
'ReservedObject': 'SmartObject'
|
Loading…
x
Reference in New Issue
Block a user