[CodeQuality] Skip class with constructor parameter for ClassConstFetch on CallableThisArraToAnonymousFunctionRector (#581)

Co-authored-by: Zing <zingimmick@outlook.com>
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Abdul Malik Ikhsan 2021-08-03 17:11:45 +07:00 committed by GitHub
parent 2e7256bde8
commit 0888a92985
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 221 additions and 5 deletions

View File

@ -9,11 +9,13 @@ use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Scalar\String_;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\TypeWithClassName;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeCollector\ValueObject\ArrayCallable;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -47,14 +49,15 @@ final class ArrayCallableMethodMatcher
return null;
}
// $this, self, static, FQN
$firstItemValue = $array->items[0]->value;
$secondItemValue = $array->items[1]->value;
if (! $secondItemValue instanceof String_) {
return null;
}
// $this, self, static, FQN
$firstItemValue = $array->items[0]->value;
// static ::class reference?
if ($firstItemValue instanceof ClassConstFetch) {
$calleeType = $this->resolveClassConstFetchType($firstItemValue);
@ -66,13 +69,12 @@ final class ArrayCallableMethodMatcher
return null;
}
$className = $calleeType->getClassName();
$methodName = $secondItemValue->value;
if ($this->isCallbackAtFunctionNames($array, ['register_shutdown_function', 'forward_static_call'])) {
return null;
}
$className = $calleeType->getClassName();
$methodName = $secondItemValue->value;
return new ArrayCallable($firstItemValue, $className, $methodName);
}
@ -111,6 +113,20 @@ final class ArrayCallableMethodMatcher
}
$classReflection = $this->reflectionProvider->getClass($classConstantReference);
$scope = $classConstFetch->getAttribute(AttributeKey::SCOPE);
$hasConstruct = $classReflection->hasMethod(MethodName::CONSTRUCT);
if ($hasConstruct) {
$methodReflection = $classReflection->getMethod(MethodName::CONSTRUCT, $scope);
$parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants());
foreach ($parametersAcceptor->getParameters() as $parameterReflection) {
if ($parameterReflection->getDefaultValue() === null) {
return new MixedType();
}
}
}
return new ObjectType($classConstantReference, null, $classReflection);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
use Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source\OtherClass3;
final class HasConstructWithDefaultValueParameter
{
public function run()
{
return [OtherClass3::class, 'someMethod'];
}
}
?>
-----
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
use Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source\OtherClass3;
final class HasConstructWithDefaultValueParameter
{
public function run()
{
return function () {
return (new \Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source\OtherClass3())->someMethod();
};
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
use Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source\OtherClass2;
final class OtherClassNotHasConstructParameter
{
public function run()
{
return [OtherClass2::class, 'someMethod'];
}
}
?>
-----
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
use Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source\OtherClass2;
final class OtherClassNotHasConstructParameter
{
public function run()
{
return function () {
return (new \Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source\OtherClass2())->someMethod();
};
}
}
?>

View File

@ -0,0 +1,45 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
final class SameClassNotHasConstructParameter
{
public function __construct()
{
}
public function run()
{
return [SameClassNotHasConstructParameter::class, 'someMethod'];
}
public function someMethod()
{
}
}
?>
-----
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
final class SameClassNotHasConstructParameter
{
public function __construct()
{
}
public function run()
{
return function () {
return (new \Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture\SameClassNotHasConstructParameter())->someMethod();
};
}
public function someMethod()
{
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
use Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source\OtherClass;
final class SkipOtherClassHasConstructParameter
{
public function run()
{
return [OtherClass::class, 'someMethod'];
}
}
?>

View File

@ -0,0 +1,24 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Fixture;
final class SkipSameClassHasConstructParameter
{
private $property;
public function __construct($property)
{
$this->property = $property;
}
public function run()
{
return [SkipSameClassHasConstructParameter::class, 'someMethod'];
}
public function someMethod()
{
}
}
?>

View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source;
final class OtherClass
{
private $property;
public function __construct($property)
{
$this->property = $property;
}
public function someMethod()
{
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source;
final class OtherClass2
{
public function __construct()
{
}
public function someMethod()
{
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector\Source;
final class OtherClass3
{
public function __construct($property = null)
{
}
public function someMethod()
{
}
}