Skip to content

Commit

Permalink
support positional arguments in sprintf() constant format inference
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Jun 17, 2022
1 parent 1962fc7 commit 077aae4
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php
Expand Up @@ -33,7 +33,7 @@ public function getTypeFromFunctionCall(
FunctionReflection $functionReflection,
FuncCall $functionCall,
Scope $scope,
): Type
): ?Type
{
$args = $functionCall->getArgs();
if (count($args) === 0) {
Expand All @@ -43,7 +43,13 @@ public function getTypeFromFunctionCall(
$formatType = $scope->getType($args[0]->value);

if ($formatType instanceof ConstantStringType) {
if (preg_match('/^%[0-9]*\.?[0-9]+[bdeEfFgGhHouxX]$/', $formatType->getValue()) === 1) {
// The printf format is %[argnum$][flags][width][.precision]
if (preg_match('/^%([0-9]*\$)?[0-9]*\.?[0-9]+[bdeEfFgGhHouxX]$/', $formatType->getValue(), $matches) === 1) {
// invalid positional argument
if (array_key_exists(1, $matches) && $matches[1] === '0$') {
return null;
}

return new IntersectionType([
new StringType(),
new AccessoryNumericStringType(),
Expand Down
23 changes: 23 additions & 0 deletions tests/PHPStan/Analyser/data/bug-7387.php
Expand Up @@ -42,4 +42,27 @@ public function specifiers(int $i) {
assertType('numeric-string', sprintf('%14X', $i));

}

public function positionalArgs($mixed, int $i, float $f, string $s) {
// https://3v4l.org/vVL0c
assertType('non-empty-string', sprintf('%2$14s', $mixed, $i));

assertType('numeric-string', sprintf('%2$.14F', $mixed, $i));
assertType('numeric-string', sprintf('%2$.14F', $mixed, $f));
assertType('numeric-string', sprintf('%2$.14F', $mixed, $s));

assertType('numeric-string', sprintf('%2$1.14F', $mixed, $i));
assertType('numeric-string', sprintf('%2$2.14F', $mixed, $f));
assertType('numeric-string', sprintf('%2$3.14F', $mixed, $s));

assertType('numeric-string', sprintf('%2$14F', $mixed, $i));
assertType('numeric-string', sprintf('%2$14F', $mixed, $f));
assertType('numeric-string', sprintf('%2$14F', $mixed, $s));

assertType('numeric-string', sprintf('%10$14F', $mixed, $s));
}

public function invalidPositionalArgFormat($mixed, string $s) {
assertType('string', sprintf('%0$14F', $mixed, $s));
}
}

0 comments on commit 077aae4

Please sign in to comment.