mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-10 21:22:21 +00:00
[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\CallUserFuncWithArrowFunctionToInlineRector;
|
||||||
use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector;
|
use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector;
|
||||||
use Rector\CodeQuality\Rector\FuncCall\CompactToVariablesRector;
|
use Rector\CodeQuality\Rector\FuncCall\CompactToVariablesRector;
|
||||||
|
use Rector\CodeQuality\Rector\FuncCall\InlineIsAInstanceOfRector;
|
||||||
use Rector\CodeQuality\Rector\FuncCall\IntvalToTypeCastRector;
|
use Rector\CodeQuality\Rector\FuncCall\IntvalToTypeCastRector;
|
||||||
use Rector\CodeQuality\Rector\FuncCall\IsAWithStringWithThirdArgumentRector;
|
use Rector\CodeQuality\Rector\FuncCall\IsAWithStringWithThirdArgumentRector;
|
||||||
use Rector\CodeQuality\Rector\FuncCall\RemoveSoleValueSprintfRector;
|
use Rector\CodeQuality\Rector\FuncCall\RemoveSoleValueSprintfRector;
|
||||||
|
@ -162,23 +163,27 @@ return static function (RectorConfig $rectorConfig): void {
|
||||||
'mbstrrpos' => 'mb_strrpos',
|
'mbstrrpos' => 'mb_strrpos',
|
||||||
'mbsubstr' => 'mb_substr',
|
'mbsubstr' => 'mb_substr',
|
||||||
]);
|
]);
|
||||||
$rectorConfig->rule(SetTypeToCastRector::class);
|
|
||||||
$rectorConfig->rule(LogicalToBooleanRector::class);
|
$rectorConfig->rules([
|
||||||
$rectorConfig->rule(VarToPublicPropertyRector::class);
|
SetTypeToCastRector::class,
|
||||||
$rectorConfig->rule(IssetOnPropertyObjectToPropertyExistsRector::class);
|
LogicalToBooleanRector::class,
|
||||||
$rectorConfig->rule(NewStaticToNewSelfRector::class);
|
VarToPublicPropertyRector::class,
|
||||||
$rectorConfig->rule(DateTimeToDateTimeInterfaceRector::class);
|
IssetOnPropertyObjectToPropertyExistsRector::class,
|
||||||
$rectorConfig->rule(UnwrapSprintfOneArgumentRector::class);
|
NewStaticToNewSelfRector::class,
|
||||||
$rectorConfig->rule(SwitchNegatedTernaryRector::class);
|
DateTimeToDateTimeInterfaceRector::class,
|
||||||
$rectorConfig->rule(SingularSwitchToIfRector::class);
|
UnwrapSprintfOneArgumentRector::class,
|
||||||
$rectorConfig->rule(SimplifyIfNullableReturnRector::class);
|
SwitchNegatedTernaryRector::class,
|
||||||
$rectorConfig->rule(NarrowUnionTypeDocRector::class);
|
SingularSwitchToIfRector::class,
|
||||||
$rectorConfig->rule(FuncGetArgsToVariadicParamRector::class);
|
SimplifyIfNullableReturnRector::class,
|
||||||
$rectorConfig->rule(CallUserFuncToMethodCallRector::class);
|
NarrowUnionTypeDocRector::class,
|
||||||
$rectorConfig->rule(CallUserFuncWithArrowFunctionToInlineRector::class);
|
FuncGetArgsToVariadicParamRector::class,
|
||||||
$rectorConfig->rule(CountArrayToEmptyArrayComparisonRector::class);
|
CallUserFuncToMethodCallRector::class,
|
||||||
$rectorConfig->rule(FlipTypeControlToUseExclusiveTypeRector::class);
|
CallUserFuncWithArrowFunctionToInlineRector::class,
|
||||||
$rectorConfig->rule(ExplicitMethodCallOverMagicGetSetRector::class);
|
CountArrayToEmptyArrayComparisonRector::class,
|
||||||
$rectorConfig->rule(DoWhileBreakFalseToIfElseRector::class);
|
FlipTypeControlToUseExclusiveTypeRector::class,
|
||||||
$rectorConfig->rule(InlineArrayReturnAssignRector::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);
|
||||||
|
};
|
113
rules/CodeQuality/Rector/FuncCall/InlineIsAInstanceOfRector.php
Normal file
113
rules/CodeQuality/Rector/FuncCall/InlineIsAInstanceOfRector.php
Normal file
|
@ -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
Block a user