Skip to content

Commit f9ae282

Browse files
committed
fix: apply dynamic parameter type extensions in FunctionCallParametersCheck
1 parent 4cb7082 commit f9ae282

29 files changed

+103
-15
lines changed

e2e/parameter-type-extension/phpstan-baseline.neon

Lines changed: 0 additions & 7 deletions
This file was deleted.

e2e/parameter-type-extension/phpstan.neon.dist

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
includes:
2-
- phpstan-baseline.neon
31
parameters:
42
level: 9
53
paths:

src/Rules/AttributesCheck.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ public function check(
139139
),
140140
$scope,
141141
$attributeConstructor->getDeclaringClass()->isBuiltin(),
142+
null,
142143
new New_($attribute->name, $attribute->args, $nodeAttributes),
143144
'attribute',
144145
$attributeConstructor->acceptsNamedArguments(),

src/Rules/Classes/InstantiationRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $
238238
),
239239
$scope,
240240
$constructorReflection->getDeclaringClass()->isBuiltin(),
241+
null,
241242
$node,
242243
'new',
243244
$constructorReflection->acceptsNamedArguments(),

src/Rules/FunctionCallParametersCheck.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
use PHPStan\Analyser\Scope;
99
use PHPStan\DependencyInjection\AutowiredParameter;
1010
use PHPStan\DependencyInjection\AutowiredService;
11+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
1112
use PHPStan\Reflection\ExtendedParameterReflection;
13+
use PHPStan\Reflection\FunctionReflection;
14+
use PHPStan\Reflection\MethodReflection;
1215
use PHPStan\Reflection\ParameterReflection;
1316
use PHPStan\Reflection\ParametersAcceptor;
1417
use PHPStan\Reflection\ResolvedFunctionVariant;
@@ -46,6 +49,7 @@ public function __construct(
4649
private NullsafeCheck $nullsafeCheck,
4750
private UnresolvableTypeHelper $unresolvableTypeHelper,
4851
private PropertyReflectionFinder $propertyReflectionFinder,
52+
private DynamicParameterTypeExtensionProvider $dynamicParameterTypeExtensionProvider,
4953
#[AutowiredParameter(ref: '%checkFunctionArgumentTypes%')]
5054
private bool $checkArgumentTypes,
5155
#[AutowiredParameter]
@@ -66,6 +70,7 @@ public function check(
6670
ParametersAcceptor $parametersAcceptor,
6771
Scope $scope,
6872
bool $isBuiltin,
73+
MethodReflection|FunctionReflection|null $calleeReflection,
6974
Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall,
7075
string $nodeType,
7176
TrinaryLogic $acceptsNamedArguments,
@@ -349,6 +354,13 @@ public function check(
349354
if ($this->checkArgumentTypes) {
350355
$parameterType = TypeUtils::resolveLateResolvableTypes($parameter->getType());
351356

357+
if (! $funcCall instanceof Node\Expr\New_) {
358+
$overriddenType = $this->getParameterTypeFromDynamicExtension($funcCall, $calleeReflection, $parameter, $scope);
359+
if ($overriddenType !== null) {
360+
$parameterType = $overriddenType;
361+
}
362+
}
363+
352364
if (
353365
!$parameter->passedByReference()->createsNewVariable()
354366
|| (!$isBuiltin && !$argumentValueType instanceof ErrorType)
@@ -681,4 +693,50 @@ private function describeParameter(ParameterReflection $parameter, int|string|nu
681693
return implode(' ', $parts);
682694
}
683695

696+
private function getParameterTypeFromDynamicExtension(
697+
Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall $funcCall,
698+
MethodReflection|FunctionReflection|null $calleeReflection,
699+
ParameterReflection $parameter,
700+
Scope $scope,
701+
): ?Type
702+
{
703+
if ($calleeReflection === null) {
704+
return null;
705+
}
706+
707+
if ($funcCall instanceof Node\Expr\FuncCall && $calleeReflection instanceof FunctionReflection) {
708+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicFunctionParameterTypeExtensions() as $extension) {
709+
if (!$extension->isFunctionSupported($calleeReflection, $parameter)) {
710+
continue;
711+
}
712+
$type = $extension->getTypeFromFunctionCall($calleeReflection, $funcCall, $parameter, $scope);
713+
if ($type !== null) {
714+
return $type;
715+
}
716+
}
717+
} elseif ($funcCall instanceof Node\Expr\StaticCall && $calleeReflection instanceof MethodReflection) {
718+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicStaticMethodParameterTypeExtensions() as $extension) {
719+
if (!$extension->isStaticMethodSupported($calleeReflection, $parameter)) {
720+
continue;
721+
}
722+
$type = $extension->getTypeFromStaticMethodCall($calleeReflection, $funcCall, $parameter, $scope);
723+
if ($type !== null) {
724+
return $type;
725+
}
726+
}
727+
} elseif ($funcCall instanceof Node\Expr\MethodCall && $calleeReflection instanceof MethodReflection) {
728+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicMethodParameterTypeExtensions() as $extension) {
729+
if (!$extension->isMethodSupported($calleeReflection, $parameter)) {
730+
continue;
731+
}
732+
$type = $extension->getTypeFromMethodCall($calleeReflection, $funcCall, $parameter, $scope);
733+
if ($type !== null) {
734+
return $type;
735+
}
736+
}
737+
}
738+
739+
return null;
740+
}
741+
684742
}

src/Rules/Functions/CallCallablesRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ public function processNode(
121121
$parametersAcceptor,
122122
$scope,
123123
false,
124+
null,
124125
$node,
125126
'callable',
126127
$acceptsNamedArguments,

src/Rules/Functions/CallToFunctionParametersRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public function processNode(Node $node, Scope $scope): array
5050
),
5151
$scope,
5252
$function->isBuiltin(),
53+
$function,
5354
$node,
5455
'function',
5556
$function->acceptsNamedArguments(),

src/Rules/Functions/CallUserFuncRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public function processNode(Node $node, Scope $scope): array
6666
$parametersAcceptor,
6767
$scope,
6868
false,
69+
null,
6970
$funcCall,
7071
'function',
7172
$acceptsNamedArguments,

src/Rules/Methods/CallMethodsRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ private function processSingleMethodCall(Scope $scope, MethodCall $node, string
8181
),
8282
$scope,
8383
$declaringClass->isBuiltin(),
84+
$methodReflection,
8485
$node,
8586
'method',
8687
$methodReflection->acceptsNamedArguments(),

src/Rules/Methods/CallStaticMethodsRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ private function processSingleMethodCall(Scope $scope, StaticCall $node, string
9090
),
9191
$scope,
9292
$method->getDeclaringClass()->isBuiltin(),
93+
$method,
9394
$node,
9495
'staticMethod',
9596
$method->acceptsNamedArguments(),

0 commit comments

Comments
 (0)