From 493903baaeea1efe286b201501f70b6c7ef1a168 Mon Sep 17 00:00:00 2001 From: Dave Liddament Date: Mon, 15 Feb 2021 21:42:46 +0000 Subject: [PATCH 1/4] Fix accepted types for fputcsv fields parameter --- .../NativeFunctionReflectionProvider.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php index ad9c073526..ad85e119d7 100644 --- a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php +++ b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php @@ -6,12 +6,14 @@ use PHPStan\Reflection\Native\NativeFunctionReflection; use PHPStan\Reflection\Native\NativeParameterReflection; use PHPStan\TrinaryLogic; +use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; use PHPStan\Type\FloatType; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\IntegerType; use PHPStan\Type\NullType; use PHPStan\Type\StringAlwaysAcceptingObjectWithToStringType; +use PHPStan\Type\StringType; use PHPStan\Type\UnionType; class NativeFunctionReflectionProvider @@ -63,6 +65,26 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef new BooleanType(), ]); } + + if ( + $parameterSignature->getName() === 'fields' + && $lowerCasedFunctionName === 'fputcsv' + ) { + $type = new ArrayType( + new UnionType([ + new StringType(), + new IntegerType(), + ]), + new UnionType([ + new StringAlwaysAcceptingObjectWithToStringType(), + new IntegerType(), + new FloatType(), + new NullType(), + new BooleanType(), + ]) + ); + } + return new NativeParameterReflection( $parameterSignature->getName(), $parameterSignature->isOptional(), From a02f0b1df2d27bef24bea9e662d8ea97bb18c481 Mon Sep 17 00:00:00 2001 From: Dave Liddament Date: Mon, 15 Feb 2021 22:26:49 +0000 Subject: [PATCH 2/4] ADD test cases for fputcsv parameter --- .../CallToFunctionParametersRuleTest.php | 22 +++++++++++++ .../data/fputcsv-fields-parameter-php8.php | 16 +++++++++ .../data/fputcsv-fields-parameter.php | 33 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php create mode 100644 tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter.php diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 90f2535dfd..0afe5b34fc 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -411,6 +411,28 @@ public function testUnpackOperator(): void ]); } + public function testFputCsv(): void + { + $this->analyse([__DIR__ . '/data/fputcsv-fields-parameter.php'], [ + [ + 'Parameter #2 $fields of function fputcsv expects array, array given.', + 30, + ], + ]); + } + + + public function testPutCsvWithStringable(): void + { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test skipped under 8.0'); + } + + $this->analyse([__DIR__ . '/data/fputcsv-fields-parameter-php8.php'], [ + // No issues expected + ]); + } + public function testFunctionWithNumericParameterThatCreatedByAddition(): void { $this->analyse([__DIR__ . '/data/function-with-int-parameter-that-created-by-addition.php'], [ diff --git a/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php b/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php new file mode 100644 index 0000000000..4cecd971e9 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php @@ -0,0 +1,16 @@ + "bar", ]); + +fputcsv($handle, [ new Person, ]); // Problem on this line + +// This is valid. PersonWithToString should be cast to string by fputcsv +fputcsv($handle, [new PersonWithToString()]); From e6a0547d47233ac642fffa636bfbba4c2557d038 Mon Sep 17 00:00:00 2001 From: Dave Liddament Date: Tue, 16 Feb 2021 23:13:18 +0000 Subject: [PATCH 3/4] Update tests to remove any executable code --- .../CallToFunctionParametersRuleTest.php | 4 +- .../data/fputcsv-fields-parameter-php8.php | 17 +++--- .../data/fputcsv-fields-parameter.php | 59 ++++++++++--------- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 0afe5b34fc..20b5c3d502 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -415,8 +415,8 @@ public function testFputCsv(): void { $this->analyse([__DIR__ . '/data/fputcsv-fields-parameter.php'], [ [ - 'Parameter #2 $fields of function fputcsv expects array, array given.', - 30, + 'Parameter #2 $fields of function fputcsv expects array, array given.', + 33, ], ]); } diff --git a/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php b/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php index 4cecd971e9..0d694f0af6 100644 --- a/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php +++ b/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php @@ -1,16 +1,17 @@ "bar", ]); - -fputcsv($handle, [ new Person, ]); // Problem on this line - -// This is valid. PersonWithToString should be cast to string by fputcsv -fputcsv($handle, [new PersonWithToString()]); +class CsvWriter +{ + /** @param resource $handle */ + public function writeCsv($handle): void + { + // These are all valid scalers + fputcsv($handle, [ + "string", + 1, + 3.5, + true, + false, + null, // Yes this is accepted by fputcsv, + ]); + + // Arrays can have string for keys (which are ignored) + fputcsv($handle, ["foo" => "bar",]); + + fputcsv($handle, [new Person,]); // Problem on this line + + // This is valid. PersonWithToString should be cast to string by fputcsv + fputcsv($handle, [new PersonWithToString()]); + } +} From 9fc147a4b6c121b811306261d9b58a632d4de63a Mon Sep 17 00:00:00 2001 From: Dave Liddament Date: Wed, 17 Feb 2021 21:52:11 +0000 Subject: [PATCH 4/4] Fix, action review comments. Put test cases in namespace --- .../Rules/Functions/CallToFunctionParametersRuleTest.php | 6 +++--- .../Rules/Functions/data/fputcsv-fields-parameter-php8.php | 2 ++ .../Rules/Functions/data/fputcsv-fields-parameter.php | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 20b5c3d502..bd3c950f1d 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -415,8 +415,8 @@ public function testFputCsv(): void { $this->analyse([__DIR__ . '/data/fputcsv-fields-parameter.php'], [ [ - 'Parameter #2 $fields of function fputcsv expects array, array given.', - 33, + 'Parameter #2 $fields of function fputcsv expects array, array given.', + 35, ], ]); } @@ -425,7 +425,7 @@ public function testFputCsv(): void public function testPutCsvWithStringable(): void { if (PHP_VERSION_ID < 80000) { - $this->markTestSkipped('Test skipped under 8.0'); + $this->markTestSkipped('Test skipped on lower version than 8.0 (needs Stringable interface, added in PHP8)'); } $this->analyse([__DIR__ . '/data/fputcsv-fields-parameter-php8.php'], [ diff --git a/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php b/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php index 0d694f0af6..d084b89087 100644 --- a/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php +++ b/tests/PHPStan/Rules/Functions/data/fputcsv-fields-parameter-php8.php @@ -1,5 +1,7 @@