diff --git a/src/DeprecatedScope/DeprecationHelperScope.php b/src/DeprecatedScope/DeprecationHelperScope.php index e9f30b28..16c14316 100644 --- a/src/DeprecatedScope/DeprecationHelperScope.php +++ b/src/DeprecatedScope/DeprecationHelperScope.php @@ -9,7 +9,6 @@ use PHPStan\Reflection\MethodReflection; use PHPStan\Rules\Deprecations\DeprecatedScopeResolver; use function class_exists; -use function count; final class DeprecationHelperScope implements DeprecatedScopeResolver { @@ -18,19 +17,19 @@ public function isScopeDeprecated(Scope $scope): bool if (!class_exists(DeprecationHelper::class)) { return false; } - $callStack = $scope->getFunctionCallStackWithParameters(); - if (count($callStack) === 0) { - return false; - } - [$function, $parameter] = $callStack[0]; - if (!$function instanceof MethodReflection) { - return false; - } - if ($function->getName() !== 'backwardsCompatibleCall' - || $function->getDeclaringClass()->getName() !== DeprecationHelper::class - ) { - return false; + foreach ($scope->getFunctionCallStackWithParameters() as [$function, $parameter]) { + if (!$function instanceof MethodReflection) { + continue; + } + if ($function->getName() !== 'backwardsCompatibleCall' + || $function->getDeclaringClass()->getName() !== DeprecationHelper::class + ) { + continue; + } + if ($parameter !== null && $parameter->getName() === 'deprecatedCallable') { + return true; + } } - return $parameter !== null && $parameter->getName() === 'deprecatedCallable'; + return false; } } diff --git a/tests/src/DeprecatedScope/data/deprecation-helper-test.php b/tests/src/DeprecatedScope/data/deprecation-helper-test.php index 0f5d341d..81028d59 100644 --- a/tests/src/DeprecatedScope/data/deprecation-helper-test.php +++ b/tests/src/DeprecatedScope/data/deprecation-helper-test.php @@ -57,6 +57,22 @@ function() { $this->deprecatedCallable(...), $this->currentCallable(...) ); + + // BC wrapper nested inside an outer function call — deprecatedCallable must still be suppressed. + $x = trim(DeprecationHelper::backwardsCompatibleCall( + \Drupal::VERSION, + '10.1.0', + fn() => count([]), + fn() => deprecated_function() + )); + + // BC wrapper 4 levels deep — stack traversal must find backwardsCompatibleCall at any depth. + $y = trim(strrev(strtolower(DeprecationHelper::backwardsCompatibleCall( + \Drupal::VERSION, + '10.1.0', + fn() => '', + fn() => deprecated_function() + )))); } /**