diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodParameterRector/Fixture/remove_with_array_callable_of_other_class.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodParameterRector/Fixture/remove_with_array_callable_of_other_class.php.inc new file mode 100644 index 00000000000..8c0fda45193 --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodParameterRector/Fixture/remove_with_array_callable_of_other_class.php.inc @@ -0,0 +1,41 @@ +format('unused', 'value'); + + return [\DateTime::class, 'format']; + } + + private function format(string $unused, string $value): string + { + return $value; + } +} + +?> +----- +format('value'); + + return [\DateTime::class, 'format']; + } + + private function format(string $value): string + { + return $value; + } +} + +?> diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodParameterRector/Fixture/skip_with_array_callable_dynamic_method.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodParameterRector/Fixture/skip_with_array_callable_dynamic_method.php.inc new file mode 100644 index 00000000000..1b6a4d33298 --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodParameterRector/Fixture/skip_with_array_callable_dynamic_method.php.inc @@ -0,0 +1,16 @@ +isUsedAsArrayCallable($class, $classMethod)) { + return false; + } + $keysArg = array_keys($paramsToRemove); $classObjectType = new ObjectType((string) $this->nodeNameResolver->getName($class)); @@ -112,6 +123,33 @@ private function removeCallerArgs(Class_ $class, ClassMethod $classMethod, array return true; } + private function isUsedAsArrayCallable(Class_ $class, ClassMethod $classMethod): bool + { + $scope = ScopeFetcher::fetch($class); + $methodName = $this->nodeNameResolver->getName($classMethod); + + /** @var Array_[] $arrays */ + $arrays = $this->betterNodeFinder->findInstanceOf($class, Array_::class); + + foreach ($arrays as $array) { + $arrayCallable = $this->arrayCallableMethodMatcher->match($array, $scope, $methodName); + if ($arrayCallable instanceof ArrayCallableDynamicMethod) { + return true; + } + + if (! $arrayCallable instanceof ArrayCallable) { + continue; + } + + if ($this->nodeNameResolver->isName($class, $arrayCallable->getClass()) + && $this->nodeNameResolver->isName($classMethod, $arrayCallable->getMethod())) { + return true; + } + } + + return false; + } + /** * @param int[] $keysArg */ diff --git a/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php b/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php index 46a8b7a4e47..7e510d472e8 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php +++ b/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php @@ -382,10 +382,6 @@ private function nodeScopeResolverProcessNodes( private function processCallLike(CallLike $callLike, MutatingScope $mutatingScope): void { - if ($callLike->isFirstClassCallable()) { - return; - } - if ($callLike instanceof StaticCall) { $callLike->class->setAttribute(AttributeKey::SCOPE, $mutatingScope); $callLike->name->setAttribute(AttributeKey::SCOPE, $mutatingScope); @@ -398,6 +394,10 @@ private function processCallLike(CallLike $callLike, MutatingScope $mutatingScop $callLike->class->setAttribute(AttributeKey::SCOPE, $mutatingScope); } + if ($callLike->isFirstClassCallable()) { + return; + } + foreach ($callLike->getArgs() as $arg) { $arg->value->setAttribute(AttributeKey::SCOPE, $mutatingScope); }