Skip to content

Commit 74f53f1

Browse files
committed
fix: apply dynamic parameter type extensions in FunctionCallParametersCheck
1 parent a842243 commit 74f53f1

26 files changed

Lines changed: 101 additions & 9 deletions

‎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/FunctionCallParametersCheck.php‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
use PHPStan\Analyser\Scope;
1111
use PHPStan\DependencyInjection\AutowiredParameter;
1212
use PHPStan\DependencyInjection\AutowiredService;
13+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
1314
use PHPStan\Reflection\ConstantReflection;
1415
use PHPStan\Reflection\ExtendedParameterReflection;
16+
use PHPStan\Reflection\FunctionReflection;
17+
use PHPStan\Reflection\MethodReflection;
1518
use PHPStan\Reflection\ParameterReflection;
1619
use PHPStan\Reflection\ParametersAcceptor;
1720
use PHPStan\Reflection\ReflectionProvider;
@@ -55,6 +58,7 @@ public function __construct(
5558
private UnresolvableTypeHelper $unresolvableTypeHelper,
5659
private PropertyReflectionFinder $propertyReflectionFinder,
5760
private ReflectionProvider $reflectionProvider,
61+
private DynamicParameterTypeExtensionProvider $dynamicParameterTypeExtensionProvider,
5862
#[AutowiredParameter(ref: '%checkFunctionArgumentTypes%')]
5963
private bool $checkArgumentTypes,
6064
#[AutowiredParameter]
@@ -98,6 +102,7 @@ public function check(
98102
string $exclusiveConstantsMessage,
99103
string $bitmaskNotAllowedMessage,
100104
?array $renamedNamedArgumentParameterData,
105+
MethodReflection|FunctionReflection|null $calleeReflection = null,
101106
): array
102107
{
103108
if ($funcCall instanceof Node\Expr\MethodCall || $funcCall instanceof Node\Expr\StaticCall || $funcCall instanceof Node\Expr\FuncCall) {
@@ -391,6 +396,13 @@ public function check(
391396
if ($this->checkArgumentTypes) {
392397
$parameterType = TypeUtils::resolveLateResolvableTypes($parameter->getType());
393398

399+
if (! $funcCall instanceof Node\Expr\New_) {
400+
$overriddenType = $this->getParameterTypeFromDynamicExtension($funcCall, $calleeReflection, $parameter, $scope);
401+
if ($overriddenType !== null) {
402+
$parameterType = $overriddenType;
403+
}
404+
}
405+
394406
if (
395407
!$parameter->passedByReference()->createsNewVariable()
396408
|| (!$isBuiltin && !$argumentValueType instanceof ErrorType)
@@ -895,4 +907,50 @@ private function callReturnsByReference(Expr $expr, Scope $scope): bool
895907
return false;
896908
}
897909

910+
private function getParameterTypeFromDynamicExtension(
911+
Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall $funcCall,
912+
MethodReflection|FunctionReflection|null $calleeReflection,
913+
ParameterReflection $parameter,
914+
Scope $scope,
915+
): ?Type
916+
{
917+
if ($calleeReflection === null) {
918+
return null;
919+
}
920+
921+
if ($funcCall instanceof Node\Expr\FuncCall && $calleeReflection instanceof FunctionReflection) {
922+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicFunctionParameterTypeExtensions() as $extension) {
923+
if (!$extension->isFunctionSupported($calleeReflection, $parameter)) {
924+
continue;
925+
}
926+
$type = $extension->getTypeFromFunctionCall($calleeReflection, $funcCall, $parameter, $scope);
927+
if ($type !== null) {
928+
return $type;
929+
}
930+
}
931+
} elseif ($funcCall instanceof Node\Expr\StaticCall && $calleeReflection instanceof MethodReflection) {
932+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicStaticMethodParameterTypeExtensions() as $extension) {
933+
if (!$extension->isStaticMethodSupported($calleeReflection, $parameter)) {
934+
continue;
935+
}
936+
$type = $extension->getTypeFromStaticMethodCall($calleeReflection, $funcCall, $parameter, $scope);
937+
if ($type !== null) {
938+
return $type;
939+
}
940+
}
941+
} elseif ($funcCall instanceof Node\Expr\MethodCall && $calleeReflection instanceof MethodReflection) {
942+
foreach ($this->dynamicParameterTypeExtensionProvider->getDynamicMethodParameterTypeExtensions() as $extension) {
943+
if (!$extension->isMethodSupported($calleeReflection, $parameter)) {
944+
continue;
945+
}
946+
$type = $extension->getTypeFromMethodCall($calleeReflection, $funcCall, $parameter, $scope);
947+
if ($type !== null) {
948+
return $type;
949+
}
950+
}
951+
}
952+
953+
return null;
954+
}
955+
898956
}

‎src/Rules/Functions/CallToFunctionParametersRule.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public function processNode(Node $node, Scope&NodeCallbackInvoker&CollectedDataE
7474
'Constants %s cannot be combined for %s of function ' . $functionName . '.',
7575
'Combining constants with | is not allowed for %s of function ' . $functionName . '.',
7676
null,
77+
$function,
7778
);
7879
}
7980

‎src/Rules/Methods/CallMethodsRule.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ private function processSingleMethodCall(Scope&NodeCallbackInvoker&CollectedData
108108
$declaringClass->getName(),
109109
$methodReflection->getName(),
110110
] : null,
111+
$methodReflection,
111112
));
112113
}
113114

‎src/Rules/Methods/CallStaticMethodsRule.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ private function processSingleMethodCall(Scope&NodeCallbackInvoker&CollectedData
114114
'Constants %s cannot be combined for %s of ' . $lowercasedMethodName . '.',
115115
'Combining constants with | is not allowed for %s of ' . $lowercasedMethodName . '.',
116116
null,
117+
$method,
117118
));
118119

119120
return $errors;

‎tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Analyser;
44

5+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
56
use PHPStan\Rules\FunctionCallParametersCheck;
67
use PHPStan\Rules\Methods\CallMethodsRule;
78
use PHPStan\Rules\Methods\MethodCallCheck;
@@ -44,6 +45,7 @@ protected function getRule(): Rule
4445
new UnresolvableTypeHelper(),
4546
new PropertyReflectionFinder(),
4647
$reflectionProvider,
48+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
4749
checkArgumentTypes: true,
4850
checkArgumentsPassedByReference: true,
4951
checkExtraArguments: true,

‎tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Rules\Classes;
44

55
use PHPStan\Classes\ForbiddenClassNameExtension;
6+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
67
use PHPStan\Rules\AttributesCheck;
78
use PHPStan\Rules\ClassCaseSensitivityCheck;
89
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -49,6 +50,7 @@ protected function getRule(): Rule
4950
new UnresolvableTypeHelper(),
5051
new PropertyReflectionFinder(),
5152
$reflectionProvider,
53+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
5254
checkArgumentTypes: true,
5355
checkArgumentsPassedByReference: true,
5456
checkExtraArguments: true,

‎tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Rules\Classes;
44

55
use PHPStan\Classes\ForbiddenClassNameExtension;
6+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
67
use PHPStan\Rules\AttributesCheck;
78
use PHPStan\Rules\ClassCaseSensitivityCheck;
89
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -44,6 +45,7 @@ protected function getRule(): Rule
4445
new UnresolvableTypeHelper(),
4546
new PropertyReflectionFinder(),
4647
$reflectionProvider,
48+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
4749
checkArgumentTypes: true,
4850
checkArgumentsPassedByReference: true,
4951
checkExtraArguments: true,

‎tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Rules\Classes;
44

55
use PHPStan\Classes\ForbiddenClassNameExtension;
6+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
67
use PHPStan\Rules\ClassCaseSensitivityCheck;
78
use PHPStan\Rules\ClassForbiddenNameCheck;
89
use PHPStan\Rules\ClassNameCheck;
@@ -46,6 +47,7 @@ protected function getRule(): Rule
4647
new UnresolvableTypeHelper(),
4748
new PropertyReflectionFinder(),
4849
$reflectionProvider,
50+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
4951
checkArgumentTypes: true,
5052
checkArgumentsPassedByReference: true,
5153
checkExtraArguments: true,

0 commit comments

Comments
 (0)