mirror of https://github.com/rectorphp/rector.git
[CodeQuality] Add InlineIsAInstanceOfRector (#2364)
This commit is contained in:
parent
3da22b0231
commit
f5a06553ce
|
@ -32,6 +32,7 @@ use Rector\CodeQuality\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector;
|
|||
use Rector\CodeQuality\Rector\FuncCall\CallUserFuncWithArrowFunctionToInlineRector;
|
||||
use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector;
|
||||
use Rector\CodeQuality\Rector\FuncCall\CompactToVariablesRector;
|
||||
use Rector\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector;
|
||||
use Rector\CodeQuality\Rector\FuncCall\IntvalToTypeCastRector;
|
||||
use Rector\CodeQuality\Rector\FuncCall\IsAWithStringWithThirdArgumentRector;
|
||||
use Rector\CodeQuality\Rector\FuncCall\RemoveSoleValueSprintfRector;
|
||||
|
@ -162,23 +163,27 @@ return static function (RectorConfig $rectorConfig): void {
|
|||
'mbstrrpos' => 'mb_strrpos',
|
||||
'mbsubstr' => 'mb_substr',
|
||||
]);
|
||||
$rectorConfig->rule(SetTypeToCastRector::class);
|
||||
$rectorConfig->rule(LogicalToBooleanRector::class);
|
||||
$rectorConfig->rule(VarToPublicPropertyRector::class);
|
||||
$rectorConfig->rule(IssetOnPropertyObjectToPropertyExistsRector::class);
|
||||
$rectorConfig->rule(NewStaticToNewSelfRector::class);
|
||||
$rectorConfig->rule(DateTimeToDateTimeInterfaceRector::class);
|
||||
$rectorConfig->rule(UnwrapSprintfOneArgumentRector::class);
|
||||
$rectorConfig->rule(SwitchNegatedTernaryRector::class);
|
||||
$rectorConfig->rule(SingularSwitchToIfRector::class);
|
||||
$rectorConfig->rule(SimplifyIfNullableReturnRector::class);
|
||||
$rectorConfig->rule(NarrowUnionTypeDocRector::class);
|
||||
$rectorConfig->rule(FuncGetArgsToVariadicParamRector::class);
|
||||
$rectorConfig->rule(CallUserFuncToMethodCallRector::class);
|
||||
$rectorConfig->rule(CallUserFuncWithArrowFunctionToInlineRector::class);
|
||||
$rectorConfig->rule(CountArrayToEmptyArrayComparisonRector::class);
|
||||
$rectorConfig->rule(FlipTypeControlToUseExclusiveTypeRector::class);
|
||||
$rectorConfig->rule(ExplicitMethodCallOverMagicGetSetRector::class);
|
||||
$rectorConfig->rule(DoWhileBreakFalseToIfElseRector::class);
|
||||
$rectorConfig->rule(InlineArrayReturnAssignRector::class);
|
||||
|
||||
$rectorConfig->rules([
|
||||
SetTypeToCastRector::class,
|
||||
LogicalToBooleanRector::class,
|
||||
VarToPublicPropertyRector::class,
|
||||
IssetOnPropertyObjectToPropertyExistsRector::class,
|
||||
NewStaticToNewSelfRector::class,
|
||||
DateTimeToDateTimeInterfaceRector::class,
|
||||
UnwrapSprintfOneArgumentRector::class,
|
||||
SwitchNegatedTernaryRector::class,
|
||||
SingularSwitchToIfRector::class,
|
||||
SimplifyIfNullableReturnRector::class,
|
||||
NarrowUnionTypeDocRector::class,
|
||||
FuncGetArgsToVariadicParamRector::class,
|
||||
CallUserFuncToMethodCallRector::class,
|
||||
CallUserFuncWithArrowFunctionToInlineRector::class,
|
||||
CountArrayToEmptyArrayComparisonRector::class,
|
||||
FlipTypeControlToUseExclusiveTypeRector::class,
|
||||
ExplicitMethodCallOverMagicGetSetRector::class,
|
||||
DoWhileBreakFalseToIfElseRector::class,
|
||||
InlineArrayReturnAssignRector::class,
|
||||
InlineIsAInstanceOfRector::class,
|
||||
]);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Fixture;
|
||||
|
||||
use Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Source\SomeType;
|
||||
|
||||
final class SkipCheckedTypeString
|
||||
{
|
||||
public function run(string $stringType)
|
||||
{
|
||||
return is_a($stringType, SomeType::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Fixture;
|
||||
|
||||
final class SkipString
|
||||
{
|
||||
public function run(object $object)
|
||||
{
|
||||
return is_a($object, 'SomeType');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Fixture;
|
||||
|
||||
use Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Source\SomeType;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run(object $object)
|
||||
{
|
||||
return is_a($object, SomeType::class);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Fixture;
|
||||
|
||||
use Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Source\SomeType;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run(object $object)
|
||||
{
|
||||
return $object instanceof \Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Source\SomeType;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class InlineIsAInstanceOfRectorTest 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';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\Source;
|
||||
|
||||
final class SomeType
|
||||
{
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector;
|
||||
use Rector\Config\RectorConfig;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->rule(InlineIsAInstanceOfRector::class);
|
||||
};
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQuality\Rector\FuncCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Instanceof_;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PHPStan\Type\Generic\GenericClassStringType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\ObjectWithoutClassType;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector\InlineIsAInstanceOfRectorTest
|
||||
*/
|
||||
final class InlineIsAInstanceOfRector extends AbstractRector
|
||||
{
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Change is_a() with object and class name check to instanceof', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run(object $object)
|
||||
{
|
||||
return is_a($object, SomeType::class);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run(object $object)
|
||||
{
|
||||
return $object instanceof SomeType;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [FuncCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isName($node->name, 'is_a')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$args = $node->getArgs();
|
||||
$firstArgValue = $args[0]->value;
|
||||
|
||||
if (! $this->isFirstObjectType($firstArgValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$className = $this->resolveClassName($args[1]->value);
|
||||
if ($className === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Instanceof_($firstArgValue, new FullyQualified($className));
|
||||
}
|
||||
|
||||
private function resolveClassName(Expr $expr): ?string
|
||||
{
|
||||
if (! $expr instanceof ClassConstFetch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = $this->getType($expr);
|
||||
|
||||
if ($type instanceof GenericClassStringType) {
|
||||
$type = $type->getGenericType();
|
||||
}
|
||||
|
||||
if (! $type instanceof TypeWithClassName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $type->getClassName();
|
||||
}
|
||||
|
||||
private function isFirstObjectType(Expr $expr): bool
|
||||
{
|
||||
$exprType = $this->getType($expr);
|
||||
if ($exprType instanceof ObjectWithoutClassType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $exprType instanceof ObjectType;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue