Skip to content

Commit

Permalink
[DeadCode] Fix array callable with constructor args (#5770)
Browse files Browse the repository at this point in the history
* run fix-cs

* [DeadCode] Skip Array Callable dynamic method while defining a constructor without default args on RemoveUnusedPrivateMethodRector

* use hasNativeMethod (get information about native methods)
  • Loading branch information
hogejiro committed Mar 24, 2024
1 parent 25f3af6 commit fc250dd
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector\Fixture;

final class SkipArrayCallablesFqnWithConstuctor
{
private $args;

public function __construct(...$args)
{
$this->args = $args;
}

public function run()
{
$array = [3, 2, 1];

usort($array, [SkipArrayCallablesFqnWithConstuctor::class, 'sort']);

return $array;
}

private function sort($a, $b)
{
return $a <=> $b;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector\Fixture;

final class SkipArrayCallablesSelfWithConstructor
{
private $args;

public function __construct(...$args)
{
$this->args = $args;
}

public function run()
{
$array = [3, 2, 1];

usort($array, [self::class, 'sort']);

return $array;
}

private function sort($a, $b)
{
return $a <=> $b;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector\Fixture;

final class SkipArrayCallablesStaticWithConstructor
{
private $args;

public function __construct(...$args)
{
$this->args = $args;
}

public function run()
{
$array = [3, 2, 1];

usort($array, [static::class, 'sort']);

return $array;
}

private function sort($a, $b)
{
return $a <=> $b;
}
}
3 changes: 2 additions & 1 deletion rules/DeadCode/NodeAnalyzer/IsClassMethodUsedAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,14 @@ private function isClassMethodCalledInLocalArrayCall(Class_ $class, ClassMethod
{
/** @var Array_[] $arrays */
$arrays = $this->betterNodeFinder->findInstanceOf($class, Array_::class);
$classMethodName = $this->nodeNameResolver->getName($classMethod);

foreach ($arrays as $array) {
if ($this->isInArrayMap($class, $array)) {
return true;
}

$arrayCallable = $this->arrayCallableMethodMatcher->match($array, $scope);
$arrayCallable = $this->arrayCallableMethodMatcher->match($array, $scope, $classMethodName);
if ($arrayCallable instanceof ArrayCallableDynamicMethod) {
return true;
}
Expand Down
24 changes: 17 additions & 7 deletions src/NodeCollector/NodeAnalyzer/ArrayCallableMethodMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ public function __construct(
* @see https://github.com/rectorphp/rector-src/pull/908
* @see https://github.com/rectorphp/rector-src/pull/909
*/
public function match(Array_ $array, Scope $scope): null | ArrayCallableDynamicMethod | ArrayCallable
{
public function match(
Array_ $array,
Scope $scope,
?string $classMethodName = null
): null | ArrayCallableDynamicMethod | ArrayCallable {
if (count($array->items) !== 2) {
return null;
}
Expand All @@ -59,7 +62,7 @@ public function match(Array_ $array, Scope $scope): null | ArrayCallableDynamicM
// $this, self, static, FQN
$firstItemValue = $items[0]->value;

$callerType = $this->resolveCallerType($firstItemValue, $scope);
$callerType = $this->resolveCallerType($firstItemValue, $scope, $classMethodName);
if (! $callerType instanceof TypeWithClassName) {
return null;
}
Expand Down Expand Up @@ -133,8 +136,11 @@ private function isCallbackAtFunctionNames(Array_ $array, array $functionNames):
return in_array($fromFuncCallName, $functionNames, true);
}

private function resolveClassConstFetchType(ClassConstFetch $classConstFetch, Scope $scope): MixedType | ObjectType
{
private function resolveClassConstFetchType(
ClassConstFetch $classConstFetch,
Scope $scope,
?string $classMethodName
): MixedType | ObjectType {
$classConstantReference = $this->valueResolver->getValue($classConstFetch);

if ($classConstantReference === ObjectReference::STATIC) {
Expand Down Expand Up @@ -162,6 +168,10 @@ private function resolveClassConstFetchType(ClassConstFetch $classConstFetch, Sc
return new ObjectType($classConstantReference, null, $classReflection);
}

if (is_string($classMethodName) && $classReflection->hasNativeMethod($classMethodName)) {
return new ObjectType($classConstantReference, null, $classReflection);
}

$extendedMethodReflection = $classReflection->getMethod(MethodName::CONSTRUCT, $scope);
$parametersAcceptorWithPhpDocs = ParametersAcceptorSelector::selectSingle(
$extendedMethodReflection->getVariants()
Expand All @@ -176,11 +186,11 @@ private function resolveClassConstFetchType(ClassConstFetch $classConstFetch, Sc
return new ObjectType($classConstantReference, null, $classReflection);
}

private function resolveCallerType(Expr $expr, Scope $scope): Type
private function resolveCallerType(Expr $expr, Scope $scope, ?string $classMethodName): Type
{
if ($expr instanceof ClassConstFetch) {
// static ::class reference?
$callerType = $this->resolveClassConstFetchType($expr, $scope);
$callerType = $this->resolveClassConstFetchType($expr, $scope, $classMethodName);
} else {
$callerType = $this->nodeTypeResolver->getType($expr);
}
Expand Down

0 comments on commit fc250dd

Please sign in to comment.