Skip to content

Commit 80d52e5

Browse files
committed
fix: apply dynamic parameter type extensions in FunctionCallParametersCheck
1 parent 134da44 commit 80d52e5

26 files changed

+101
-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/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]
@@ -87,6 +91,7 @@ public function check(
8791
string $unresolvableReturnTypeMessage,
8892
string $unresolvableParameterTypeMessage,
8993
string $namedArgumentMessage,
94+
MethodReflection|FunctionReflection|null $calleeReflection = null,
9095
): array
9196
{
9297
if ($funcCall instanceof Node\Expr\MethodCall || $funcCall instanceof Node\Expr\StaticCall || $funcCall instanceof Node\Expr\FuncCall) {
@@ -359,6 +364,13 @@ public function check(
359364
if ($this->checkArgumentTypes) {
360365
$parameterType = TypeUtils::resolveLateResolvableTypes($parameter->getType());
361366

367+
if (! $funcCall instanceof Node\Expr\New_) {
368+
$overriddenType = $this->getParameterTypeFromDynamicExtension($funcCall, $calleeReflection, $parameter, $scope);
369+
if ($overriddenType !== null) {
370+
$parameterType = $overriddenType;
371+
}
372+
}
373+
362374
if (
363375
!$parameter->passedByReference()->createsNewVariable()
364376
|| (!$isBuiltin && !$argumentValueType instanceof ErrorType)
@@ -744,4 +756,50 @@ private function callReturnsByReference(Expr $expr, Scope $scope): bool
744756
return false;
745757
}
746758

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

src/Rules/Functions/CallToFunctionParametersRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public function processNode(Node $node, Scope $scope): array
6868
'Return type of call to function ' . $functionName . ' contains unresolvable type.',
6969
'%s of function ' . $functionName . ' contains unresolvable type.',
7070
'Function ' . $functionName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.',
71+
$function,
7172
);
7273
}
7374

src/Rules/Methods/CallMethodsRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ private function processSingleMethodCall(Scope $scope, MethodCall $node, string
9999
'Return type of call to method ' . $messagesMethodName . ' contains unresolvable type.',
100100
'%s of method ' . $messagesMethodName . ' contains unresolvable type.',
101101
'Method ' . $messagesMethodName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.',
102+
$methodReflection,
102103
));
103104
}
104105

src/Rules/Methods/CallStaticMethodsRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ private function processSingleMethodCall(Scope $scope, StaticCall $node, string
108108
'Return type of call to ' . $lowercasedMethodName . ' contains unresolvable type.',
109109
'%s of ' . $lowercasedMethodName . ' contains unresolvable type.',
110110
$displayMethodName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.',
111+
$method,
111112
));
112113

113114
return $errors;

tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php

Lines changed: 2 additions & 1 deletion
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;
@@ -24,7 +25,7 @@ protected function getRule(): Rule
2425
$ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false, true);
2526
return new CallMethodsRule(
2627
new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true),
27-
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, true, true, true, true),
28+
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class), true, true, true, true),
2829
);
2930
}
3031

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;
@@ -38,6 +39,7 @@ protected function getRule(): Rule
3839
new UnresolvableTypeHelper(),
3940
new PropertyReflectionFinder(),
4041
$reflectionProvider,
42+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
4143
true,
4244
true,
4345
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;
@@ -33,6 +34,7 @@ protected function getRule(): Rule
3334
new UnresolvableTypeHelper(),
3435
new PropertyReflectionFinder(),
3536
$reflectionProvider,
37+
self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class),
3638
true,
3739
true,
3840
true,

tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php

Lines changed: 2 additions & 1 deletion
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;
@@ -27,7 +28,7 @@ protected function getRule(): Rule
2728
return new InstantiationRule(
2829
$container,
2930
$reflectionProvider,
30-
new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, true, true, true, true),
31+
new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, self::getContainer()->getByType(DynamicParameterTypeExtensionProvider::class), true, true, true, true),
3132
new ClassNameCheck(
3233
new ClassCaseSensitivityCheck($reflectionProvider, true),
3334
new ClassForbiddenNameCheck($container),

0 commit comments

Comments
 (0)