@@ -84,13 +84,13 @@ public function getTypeFromFunctionCall(
8484 }
8585
8686 // The printf format is %[argnum$][flags][width][.precision]specifier.
87- if (preg_match ('/^%([0-9]*\$)?[0-9]*\.?[0-9]*([sbdeEfFgGhHouxX])$/ ' , $ constantString ->getValue (), $ matches ) === 1 ) {
88- if ($ matches [1 ] !== '' ) {
87+ if (preg_match ('/^%(?P<argnum> [0-9]*\$)?(?P<width> [0-9]*) \.?[0-9]*(?P<specifier> [sbdeEfFgGhHouxX])$/ ' , $ constantString ->getValue (), $ matches ) === 1 ) {
88+ if ($ matches [' argnum ' ] !== '' ) {
8989 // invalid positional argument
90- if ($ matches [1 ] === '0$ ' ) {
90+ if ($ matches [' argnum ' ] === '0$ ' ) {
9191 return null ;
9292 }
93- $ checkArg = intval (substr ($ matches [1 ], 0 , -1 ));
93+ $ checkArg = intval (substr ($ matches [' argnum ' ], 0 , -1 ));
9494 } else {
9595 $ checkArg = 1 ;
9696 }
@@ -103,11 +103,13 @@ public function getTypeFromFunctionCall(
103103 // if the format string is just a placeholder and specified an argument
104104 // of stringy type, then the return value will be of the same type
105105 $ checkArgType = $ scope ->getType ($ args [$ checkArg ]->value );
106- if ($ matches [2 ] === 's '
106+ if (
107+ $ matches ['specifier ' ] === 's '
108+ && ($ checkArgType ->isConstantValue ()->no () || $ matches ['width ' ] === '' )
107109 && ($ checkArgType ->isString ()->yes () || $ checkArgType ->isInteger ()->yes ())
108110 ) {
109111 $ singlePlaceholderEarlyReturn = $ checkArgType ->toString ();
110- } elseif ($ matches [2 ] !== 's ' ) {
112+ } elseif ($ matches [' specifier ' ] !== 's ' ) {
111113 $ singlePlaceholderEarlyReturn = new IntersectionType ([
112114 new StringType (),
113115 new AccessoryNumericStringType (),
0 commit comments