88use PHPStan \Analyser \Scope ;
99use PHPStan \DependencyInjection \AutowiredParameter ;
1010use PHPStan \DependencyInjection \AutowiredService ;
11+ use PHPStan \DependencyInjection \Type \DynamicParameterTypeExtensionProvider ;
1112use PHPStan \Reflection \ExtendedParameterReflection ;
13+ use PHPStan \Reflection \FunctionReflection ;
14+ use PHPStan \Reflection \MethodReflection ;
1215use PHPStan \Reflection \ParameterReflection ;
1316use PHPStan \Reflection \ParametersAcceptor ;
1417use 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)
@@ -688,4 +700,50 @@ private function describeParameter(ParameterReflection $parameter, int|string|nu
688700 return implode (' ' , $ parts );
689701 }
690702
703+ private function getParameterTypeFromDynamicExtension (
704+ Node \Expr \FuncCall |Node \Expr \MethodCall |Node \Expr \StaticCall $ funcCall ,
705+ MethodReflection |FunctionReflection |null $ calleeReflection ,
706+ ParameterReflection $ parameter ,
707+ Scope $ scope ,
708+ ): ?Type
709+ {
710+ if ($ calleeReflection === null ) {
711+ return null ;
712+ }
713+
714+ if ($ funcCall instanceof Node \Expr \FuncCall && $ calleeReflection instanceof FunctionReflection) {
715+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicFunctionParameterTypeExtensions () as $ extension ) {
716+ if (!$ extension ->isFunctionSupported ($ calleeReflection , $ parameter )) {
717+ continue ;
718+ }
719+ $ type = $ extension ->getTypeFromFunctionCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
720+ if ($ type !== null ) {
721+ return $ type ;
722+ }
723+ }
724+ } elseif ($ funcCall instanceof Node \Expr \StaticCall && $ calleeReflection instanceof MethodReflection) {
725+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicStaticMethodParameterTypeExtensions () as $ extension ) {
726+ if (!$ extension ->isStaticMethodSupported ($ calleeReflection , $ parameter )) {
727+ continue ;
728+ }
729+ $ type = $ extension ->getTypeFromStaticMethodCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
730+ if ($ type !== null ) {
731+ return $ type ;
732+ }
733+ }
734+ } elseif ($ funcCall instanceof Node \Expr \MethodCall && $ calleeReflection instanceof MethodReflection) {
735+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicMethodParameterTypeExtensions () as $ extension ) {
736+ if (!$ extension ->isMethodSupported ($ calleeReflection , $ parameter )) {
737+ continue ;
738+ }
739+ $ type = $ extension ->getTypeFromMethodCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
740+ if ($ type !== null ) {
741+ return $ type ;
742+ }
743+ }
744+ }
745+
746+ return null ;
747+ }
748+
691749}
0 commit comments