99use PHPStan \Analyser \Scope ;
1010use PHPStan \DependencyInjection \AutowiredParameter ;
1111use PHPStan \DependencyInjection \AutowiredService ;
12+ use PHPStan \DependencyInjection \Type \DynamicParameterTypeExtensionProvider ;
1213use PHPStan \Reflection \ExtendedParameterReflection ;
14+ use PHPStan \Reflection \FunctionReflection ;
15+ use PHPStan \Reflection \MethodReflection ;
1316use PHPStan \Reflection \ParameterReflection ;
1417use PHPStan \Reflection \ParametersAcceptor ;
1518use PHPStan \Reflection \ResolvedFunctionVariant ;
@@ -47,6 +50,7 @@ public function __construct(
4750 private NullsafeCheck $ nullsafeCheck ,
4851 private UnresolvableTypeHelper $ unresolvableTypeHelper ,
4952 private PropertyReflectionFinder $ propertyReflectionFinder ,
53+ private DynamicParameterTypeExtensionProvider $ dynamicParameterTypeExtensionProvider ,
5054 #[AutowiredParameter(ref: '%checkFunctionArgumentTypes% ' )]
5155 private bool $ checkArgumentTypes ,
5256 #[AutowiredParameter]
@@ -67,6 +71,7 @@ public function check(
6771 ParametersAcceptor $ parametersAcceptor ,
6872 Scope $ scope ,
6973 bool $ isBuiltin ,
74+ MethodReflection |FunctionReflection |null $ calleeReflection ,
7075 Node \Expr \FuncCall |Node \Expr \MethodCall |Node \Expr \StaticCall |Node \Expr \New_ $ funcCall ,
7176 string $ nodeType ,
7277 TrinaryLogic $ acceptsNamedArguments ,
@@ -350,6 +355,13 @@ public function check(
350355 if ($ this ->checkArgumentTypes ) {
351356 $ parameterType = TypeUtils::resolveLateResolvableTypes ($ parameter ->getType ());
352357
358+ if (! $ funcCall instanceof Node \Expr \New_) {
359+ $ overriddenType = $ this ->getParameterTypeFromDynamicExtension ($ funcCall , $ calleeReflection , $ parameter , $ scope );
360+ if ($ overriddenType !== null ) {
361+ $ parameterType = $ overriddenType ;
362+ }
363+ }
364+
353365 if (
354366 !$ parameter ->passedByReference ()->createsNewVariable ()
355367 || (!$ isBuiltin && !$ argumentValueType instanceof ErrorType)
@@ -689,4 +701,50 @@ private function describeParameter(ParameterReflection $parameter, int|string|nu
689701 return implode (' ' , $ parts );
690702 }
691703
704+ private function getParameterTypeFromDynamicExtension (
705+ Node \Expr \FuncCall |Node \Expr \MethodCall |Node \Expr \StaticCall $ funcCall ,
706+ MethodReflection |FunctionReflection |null $ calleeReflection ,
707+ ParameterReflection $ parameter ,
708+ Scope $ scope ,
709+ ): ?Type
710+ {
711+ if ($ calleeReflection === null ) {
712+ return null ;
713+ }
714+
715+ if ($ funcCall instanceof Node \Expr \FuncCall && $ calleeReflection instanceof FunctionReflection) {
716+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicFunctionParameterTypeExtensions () as $ extension ) {
717+ if (!$ extension ->isFunctionSupported ($ calleeReflection , $ parameter )) {
718+ continue ;
719+ }
720+ $ type = $ extension ->getTypeFromFunctionCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
721+ if ($ type !== null ) {
722+ return $ type ;
723+ }
724+ }
725+ } elseif ($ funcCall instanceof Node \Expr \StaticCall && $ calleeReflection instanceof MethodReflection) {
726+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicStaticMethodParameterTypeExtensions () as $ extension ) {
727+ if (!$ extension ->isStaticMethodSupported ($ calleeReflection , $ parameter )) {
728+ continue ;
729+ }
730+ $ type = $ extension ->getTypeFromStaticMethodCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
731+ if ($ type !== null ) {
732+ return $ type ;
733+ }
734+ }
735+ } elseif ($ funcCall instanceof Node \Expr \MethodCall && $ calleeReflection instanceof MethodReflection) {
736+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicMethodParameterTypeExtensions () as $ extension ) {
737+ if (!$ extension ->isMethodSupported ($ calleeReflection , $ parameter )) {
738+ continue ;
739+ }
740+ $ type = $ extension ->getTypeFromMethodCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
741+ if ($ type !== null ) {
742+ return $ type ;
743+ }
744+ }
745+ }
746+
747+ return null ;
748+ }
749+
692750}
0 commit comments