Skip to content

Commit e4551cc

Browse files
Accept decimal-int-string arguments for %d printf placeholders in strict mode (#5997)
Co-authored-by: VincentLanglet <9052536+VincentLanglet@users.noreply.github.com>
1 parent a861488 commit e4551cc

3 files changed

Lines changed: 50 additions & 1 deletion

File tree

‎src/Rules/Functions/PrintfPlaceholder.php‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Rules\Functions;
44

55
use PHPStan\ShouldNotHappenException;
6+
use PHPStan\Type\Accessory\AccessoryDecimalIntegerStringType;
67
use PHPStan\Type\Accessory\AccessoryNumericStringType;
78
use PHPStan\Type\ErrorType;
89
use PHPStan\Type\FloatType;
@@ -34,7 +35,11 @@ public function doesArgumentTypeMatchPlaceholder(Type $argumentType, bool $stric
3435
return (new IntegerType())->accepts($argumentType, true)->yes();
3536
case 'int':
3637
return $strictPlaceholderTypes
37-
? (new IntegerType())->accepts($argumentType, true)->yes()
38+
? (new UnionType([
39+
new IntegerType(),
40+
// decimal-int-string is allowed because it's printed by %d without any lossy conversion.
41+
new IntersectionType([new StringType(), new AccessoryDecimalIntegerStringType()]),
42+
]))->accepts($argumentType, true)->yes()
3843
: ! $argumentType->toInteger() instanceof ErrorType;
3944
case 'float':
4045
return $strictPlaceholderTypes

‎tests/PHPStan/Rules/Functions/PrintfParameterTypeRuleTest.php‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,22 @@ public function testStrict(): void
238238
'Parameter #2 of function printf is expected to be string by placeholder #1 ("%s"), true given.',
239239
48,
240240
],
241+
[
242+
'Parameter #2 of function printf is expected to be int by placeholder #1 ("%d"), string given.',
243+
88,
244+
],
245+
[
246+
'Parameter #2 of function printf is expected to be int by placeholder #1 ("%d"), string given.',
247+
90,
248+
],
249+
[
250+
'Parameter #2 of function printf is expected to be int by placeholder #1 ("%d"), string given.',
251+
98,
252+
],
253+
[
254+
'Parameter #2 of function printf is expected to be int by placeholder #1 ("%d"), string given.',
255+
99,
256+
],
241257
]);
242258
}
243259

‎tests/PHPStan/Rules/Functions/data/printf-param-types.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,31 @@ public function __toString(): string
7070
printf('%s %2$*s', 'a', 5, 'a');
7171
printf('%1$-+\'X10.2f', 5);
7272
printf('%1$*.*f %s %2$d', 5, 6, new FooStringable()); // 5.000000 foo 6
73+
74+
function testIntString(string $s): void
75+
{
76+
/** @var decimal-int-string $decimalIntString */
77+
$decimalIntString = $s;
78+
/** @var numeric-string $numericString */
79+
$numericString = $s;
80+
/** @var non-decimal-int-string $nonDecimalIntString */
81+
$nonDecimalIntString = $s;
82+
83+
// OK: decimal-int-string is printed by %d without lossy conversion
84+
printf('%d', $decimalIntString);
85+
printf('%f', $decimalIntString);
86+
87+
// Strict error: numeric-string may contain a decimal part
88+
printf('%d', $numericString);
89+
// Strict error: non-decimal-int-string may be trimmed/altered by %d
90+
printf('%d', $nonDecimalIntString);
91+
92+
// OK: constant decimal-int-strings
93+
printf('%d', '42');
94+
printf('%d', '-1');
95+
sprintf('%d', '0');
96+
97+
// Strict error: constant non-decimal-int-strings
98+
printf('%d', '00');
99+
printf('%d', '+1');
100+
}

0 commit comments

Comments
 (0)