Skip to content

Commit 9d0b69e

Browse files
committed
fix: apply dynamic parameter type extensions in FunctionCallParametersCheck
1 parent b972349 commit 9d0b69e

30 files changed

+105
-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
@@ -240,6 +240,7 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $
240240
),
241241
$scope,
242242
$constructorReflection->getDeclaringClass()->isBuiltin(),
243+
null,
243244
$node,
244245
'new',
245246
$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\ReflectionProvider;
@@ -49,6 +52,7 @@ public function __construct(
4952
private UnresolvableTypeHelper $unresolvableTypeHelper,
5053
private PropertyReflectionFinder $propertyReflectionFinder,
5154
private ReflectionProvider $reflectionProvider,
55+
private DynamicParameterTypeExtensionProvider $dynamicParameterTypeExtensionProvider,
5256
#[AutowiredParameter(ref: '%checkFunctionArgumentTypes%')]
5357
private bool $checkArgumentTypes,
5458
#[AutowiredParameter]
@@ -69,6 +73,7 @@ public function check(
6973
ParametersAcceptor $parametersAcceptor,
7074
Scope $scope,
7175
bool $isBuiltin,
76+
MethodReflection|FunctionReflection|null $calleeReflection,
7277
Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall,
7378
string $nodeType,
7479
TrinaryLogic $acceptsNamedArguments,
@@ -353,6 +358,13 @@ public function check(
353358
if ($this->checkArgumentTypes) {
354359
$parameterType = TypeUtils::resolveLateResolvableTypes($parameter->getType());
355360

361+
if (! $funcCall instanceof Node\Expr\New_) {
362+
$overriddenType = $this->getParameterTypeFromDynamicExtension($funcCall, $calleeReflection, $parameter, $scope);
363+
if ($overriddenType !== null) {
364+
$parameterType = $overriddenType;
365+
}
366+
}
367+
356368
if (
357369
!$parameter->passedByReference()->createsNewVariable()
358370
|| (!$isBuiltin && !$argumentValueType instanceof ErrorType)
@@ -738,4 +750,50 @@ private function callReturnsByReference(Expr $expr, Scope $scope): bool
738750
return false;
739751
}
740752

753+
private function getParameterTypeFromDynamicExtension(
754+
Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall $funcCall,
755+
MethodReflection|FunctionReflection|null $calleeReflection,
756+
ParameterReflection $parameter,
757+
Scope $scope,
758+
): ?Type
759+
{
760+
if ($calleeReflection === null) {
761+
return null;
762+
}
763+
764+
if ($funcCall instanceof Node\Expr\FuncCall && $calleeReflection instanceof FunctionReflection) {
765+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicFunctionParameterTypeExtensions() as $extension) {
766+
if (!$extension->isFunctionSupported($calleeReflection, $parameter)) {
767+
continue;
768+
}
769+
$type = $extension->getTypeFromFunctionCall($calleeReflection, $funcCall, $parameter, $scope);
770+
if ($type !== null) {
771+
return $type;
772+
}
773+
}
774+
} elseif ($funcCall instanceof Node\Expr\StaticCall && $calleeReflection instanceof MethodReflection) {
775+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicStaticMethodParameterTypeExtensions() as $extension) {
776+
if (!$extension->isStaticMethodSupported($calleeReflection, $parameter)) {
777+
continue;
778+
}
779+
$type = $extension->getTypeFromStaticMethodCall($calleeReflection, $funcCall, $parameter, $scope);
780+
if ($type !== null) {
781+
return $type;
782+
}
783+
}
784+
} elseif ($funcCall instanceof Node\Expr\MethodCall && $calleeReflection instanceof MethodReflection) {
785+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicMethodParameterTypeExtensions() as $extension) {
786+
if (!$extension->isMethodSupported($calleeReflection, $parameter)) {
787+
continue;
788+
}
789+
$type = $extension->getTypeFromMethodCall($calleeReflection, $funcCall, $parameter, $scope);
790+
if ($type !== null) {
791+
return $type;
792+
}
793+
}
794+
}
795+
796+
return null;
797+
}
798+
741799
}

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)