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 ;
@@ -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 ,
@@ -351,6 +356,13 @@ public function check(
351356 if ($ this ->checkArgumentTypes ) {
352357 $ parameterType = TypeUtils ::resolveLateResolvableTypes ($ parameter ->getType ());
353358
359+ if (! $ funcCall instanceof Node \Expr \New_) {
360+ $ overriddenType = $ this ->getParameterTypeFromDynamicExtension ($ funcCall , $ calleeReflection , $ parameter , $ scope );
361+ if ($ overriddenType !== null ) {
362+ $ parameterType = $ overriddenType ;
363+ }
364+ }
365+
354366 if (
355367 !$ parameter ->passedByReference ()->createsNewVariable ()
356368 || (!$ isBuiltin && !$ argumentValueType instanceof ErrorType)
@@ -690,4 +702,50 @@ private function describeParameter(ParameterReflection $parameter, int|string|nu
690702 return implode (' ' , $ parts );
691703 }
692704
705+ private function getParameterTypeFromDynamicExtension (
706+ Node \Expr \FuncCall |Node \Expr \MethodCall |Node \Expr \StaticCall $ funcCall ,
707+ MethodReflection |FunctionReflection |null $ calleeReflection ,
708+ ParameterReflection $ parameter ,
709+ Scope $ scope ,
710+ ): ?Type
711+ {
712+ if ($ calleeReflection === null ) {
713+ return null ;
714+ }
715+
716+ if ($ funcCall instanceof Node \Expr \FuncCall && $ calleeReflection instanceof FunctionReflection) {
717+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicFunctionParameterTypeExtensions () as $ extension ) {
718+ if (!$ extension ->isFunctionSupported ($ calleeReflection , $ parameter )) {
719+ continue ;
720+ }
721+ $ type = $ extension ->getTypeFromFunctionCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
722+ if ($ type !== null ) {
723+ return $ type ;
724+ }
725+ }
726+ } elseif ($ funcCall instanceof Node \Expr \StaticCall && $ calleeReflection instanceof MethodReflection) {
727+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicStaticMethodParameterTypeExtensions () as $ extension ) {
728+ if (!$ extension ->isStaticMethodSupported ($ calleeReflection , $ parameter )) {
729+ continue ;
730+ }
731+ $ type = $ extension ->getTypeFromStaticMethodCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
732+ if ($ type !== null ) {
733+ return $ type ;
734+ }
735+ }
736+ } elseif ($ funcCall instanceof Node \Expr \MethodCall && $ calleeReflection instanceof MethodReflection) {
737+ foreach ($ this ->dynamicParameterTypeExtensionProvider ->getDynamicMethodParameterTypeExtensions () as $ extension ) {
738+ if (!$ extension ->isMethodSupported ($ calleeReflection , $ parameter )) {
739+ continue ;
740+ }
741+ $ type = $ extension ->getTypeFromMethodCall ($ calleeReflection , $ funcCall , $ parameter , $ scope );
742+ if ($ type !== null ) {
743+ return $ type ;
744+ }
745+ }
746+ }
747+
748+ return null ;
749+ }
750+
693751}
0 commit comments