Skip to content

Commit ae932be

Browse files
committed
fix: apply dynamic parameter type extensions in FunctionCallParametersCheck
1 parent e6876b3 commit ae932be

26 files changed

Lines changed: 101 additions & 16 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 & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,7 @@ private function processSingleMethodCall(Scope&NodeCallbackInvoker&CollectedData
101101
'Return type of call to method ' . $messagesMethodName . ' contains unresolvable type.',
102102
'%s of method ' . $messagesMethodName . ' contains unresolvable type.',
103103
'Method ' . $messagesMethodName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.',
104-
'Constant %s is not allowed for %s of method ' . $messagesMethodName . '.',
105-
'Constants %s cannot be combined for %s of method ' . $messagesMethodName . '.',
106-
'Combining constants with | is not allowed for %s of method ' . $messagesMethodName . '.',
107-
!$methodReflection->isPrivate() && !$declaringClass->isFinal() ? [
108-
$declaringClass->getName(),
109-
$methodReflection->getName(),
110-
] : null,
104+
$methodReflection,
111105
));
112106
}
113107

‎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
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\Classes;
44

5+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
56
use PHPStan\Rules\AttributesCheck;
67
use PHPStan\Rules\ClassCaseSensitivityCheck;
78
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -47,6 +48,7 @@ protected function getRule(): Rule
4748
new UnresolvableTypeHelper(),
4849
new PropertyReflectionFinder(),
4950
$reflectionProvider,
51+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
5052
checkArgumentTypes: true,
5153
checkArgumentsPassedByReference: true,
5254
checkExtraArguments: true,

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

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

33
namespace PHPStan\Rules\Classes;
44

5+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
56
use PHPStan\Rules\AttributesCheck;
67
use PHPStan\Rules\ClassCaseSensitivityCheck;
78
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -42,6 +43,7 @@ protected function getRule(): Rule
4243
new UnresolvableTypeHelper(),
4344
new PropertyReflectionFinder(),
4445
$reflectionProvider,
46+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
4547
checkArgumentTypes: true,
4648
checkArgumentsPassedByReference: true,
4749
checkExtraArguments: true,

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

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

33
namespace PHPStan\Rules\Classes;
44

5+
use PHPStan\DependencyInjection\Type\DynamicParameterTypeExtensionProvider;
56
use PHPStan\Rules\ClassCaseSensitivityCheck;
67
use PHPStan\Rules\ClassForbiddenNameCheck;
78
use PHPStan\Rules\ClassNameCheck;
@@ -43,6 +44,7 @@ protected function getRule(): Rule
4344
new UnresolvableTypeHelper(),
4445
new PropertyReflectionFinder(),
4546
$reflectionProvider,
47+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
4648
checkArgumentTypes: true,
4749
checkArgumentsPassedByReference: true,
4850
checkExtraArguments: true,

0 commit comments

Comments
 (0)