diff --git a/src/Rules/Functions/PrintfPlaceholder.php b/src/Rules/Functions/PrintfPlaceholder.php index 4bdeb156d6..c151395308 100644 --- a/src/Rules/Functions/PrintfPlaceholder.php +++ b/src/Rules/Functions/PrintfPlaceholder.php @@ -3,10 +3,14 @@ namespace PHPStan\Rules\Functions; use PHPStan\ShouldNotHappenException; +use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\ErrorType; use PHPStan\Type\FloatType; use PHPStan\Type\IntegerType; +use PHPStan\Type\IntersectionType; +use PHPStan\Type\NullType; use PHPStan\Type\StringAlwaysAcceptingObjectWithToStringType; +use PHPStan\Type\StringType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; @@ -34,7 +38,11 @@ public function doesArgumentTypeMatchPlaceholder(Type $argumentType, bool $stric : ! $argumentType->toInteger() instanceof ErrorType; case 'float': return $strictPlaceholderTypes - ? (new FloatType())->accepts($argumentType, true)->yes() + ? TypeCombinator::union( + new FloatType(), + // numeric-string is allowed for consistency with phpstan-strict-rules. + new IntersectionType([new StringType(), new AccessoryNumericStringType()]), + )->accepts($argumentType, true)->yes() : ! $argumentType->toFloat() instanceof ErrorType; case 'string': case 'mixed': @@ -46,6 +54,8 @@ public function doesArgumentTypeMatchPlaceholder(Type $argumentType, bool $stric new StringAlwaysAcceptingObjectWithToStringType(), // float also accepts int. new FloatType(), + // null is allowed for consistency with phpstan-strict-rules (e.g. $string . $null). + new NullType(), )->accepts($argumentType, true)->yes(); // Without this PHPStan with PHP 7.4 reports "...should return bool but return statement is missing." // Presumably, because promoted properties are turned into regular properties and the phpdoc isn't applied to the property. diff --git a/tests/PHPStan/Rules/Functions/PrintfParameterTypeRuleTest.php b/tests/PHPStan/Rules/Functions/PrintfParameterTypeRuleTest.php index 06e34b998c..835700921c 100644 --- a/tests/PHPStan/Rules/Functions/PrintfParameterTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/PrintfParameterTypeRuleTest.php @@ -222,10 +222,6 @@ public function testStrict(): void 'Parameter #2 of function printf is expected to be int by placeholder #1 ("%d"), SimpleXMLElement given.', 40, ], - [ - 'Parameter #2 of function printf is expected to be float by placeholder #1 ("%f"), string given.', - 42, - ], [ 'Parameter #2 of function printf is expected to be float by placeholder #1 ("%f"), null given.', 43, @@ -238,10 +234,6 @@ public function testStrict(): void 'Parameter #2 of function printf is expected to be float by placeholder #1 ("%f"), SimpleXMLElement given.', 45, ], - [ - 'Parameter #2 of function printf is expected to be string by placeholder #1 ("%s"), null given.', - 47, - ], [ 'Parameter #2 of function printf is expected to be string by placeholder #1 ("%s"), true given.', 48, diff --git a/tests/PHPStan/Rules/Functions/data/printf-param-types.php b/tests/PHPStan/Rules/Functions/data/printf-param-types.php index 32b8f7b366..f3c54c77d7 100644 --- a/tests/PHPStan/Rules/Functions/data/printf-param-types.php +++ b/tests/PHPStan/Rules/Functions/data/printf-param-types.php @@ -39,12 +39,12 @@ public function __toString(): string printf('%d', true); printf('%d', new \SimpleXMLElement('aaa')); -printf('%f', '1.2345678901234567890123456789013245678901234567989'); + printf('%f', null); printf('%f', true); printf('%f', new \SimpleXMLElement('aaa')); -printf('%s', null); + printf('%s', true); // Error, but already reported by CallToFunctionParametersRule @@ -55,6 +55,10 @@ public function __toString(): string printf('%s'); printf('%s', 1, 2); +// Arguable +printf('%f', '1.2345678901234567890123456789013245678901234567989'); +printf('%s', null); + // OK printf('%s', 'a'); printf('%s', new FooStringable());