diff --git a/bin/functionMetadata_original.php b/bin/functionMetadata_original.php index 17be4631a9..50ba6b3ab4 100644 --- a/bin/functionMetadata_original.php +++ b/bin/functionMetadata_original.php @@ -18,6 +18,7 @@ 'array_diff_ukey' => ['hasSideEffects' => false], 'array_fill' => ['hasSideEffects' => false], 'array_fill_keys' => ['hasSideEffects' => false], + 'array_filter' => ['hasSideEffects' => false], 'array_flip' => ['hasSideEffects' => false], 'array_intersect' => ['hasSideEffects' => false], 'array_intersect_assoc' => ['hasSideEffects' => false], @@ -28,6 +29,7 @@ 'array_key_last' => ['hasSideEffects' => false], 'array_key_exists' => ['hasSideEffects' => false], 'array_keys' => ['hasSideEffects' => false], + 'array_map' => ['hasSideEffects' => false], 'array_merge' => ['hasSideEffects' => false], 'array_merge_recursive' => ['hasSideEffects' => false], 'array_pad' => ['hasSideEffects' => false], @@ -35,6 +37,7 @@ 'array_product' => ['hasSideEffects' => false], 'array_push' => ['hasSideEffects' => true], 'array_rand' => ['hasSideEffects' => false], + 'array_reduce' => ['hasSideEffects' => false], 'array_replace' => ['hasSideEffects' => false], 'array_replace_recursive' => ['hasSideEffects' => false], 'array_reverse' => ['hasSideEffects' => false], diff --git a/resources/functionMetadata.php b/resources/functionMetadata.php index a01a7181a6..6dd24442d8 100644 --- a/resources/functionMetadata.php +++ b/resources/functionMetadata.php @@ -724,6 +724,7 @@ 'array_diff_ukey' => ['hasSideEffects' => false], 'array_fill' => ['hasSideEffects' => false], 'array_fill_keys' => ['hasSideEffects' => false], + 'array_filter' => ['hasSideEffects' => false], 'array_first' => ['hasSideEffects' => false], 'array_flip' => ['hasSideEffects' => false], 'array_intersect' => ['hasSideEffects' => false], @@ -737,6 +738,7 @@ 'array_key_last' => ['hasSideEffects' => false], 'array_keys' => ['hasSideEffects' => false], 'array_last' => ['hasSideEffects' => false], + 'array_map' => ['hasSideEffects' => false], 'array_merge' => ['hasSideEffects' => false], 'array_merge_recursive' => ['hasSideEffects' => false], 'array_pad' => ['hasSideEffects' => false], @@ -744,6 +746,7 @@ 'array_product' => ['hasSideEffects' => false], 'array_push' => ['hasSideEffects' => true], 'array_rand' => ['hasSideEffects' => false], + 'array_reduce' => ['hasSideEffects' => false], 'array_replace' => ['hasSideEffects' => false], 'array_replace_recursive' => ['hasSideEffects' => false], 'array_reverse' => ['hasSideEffects' => false], diff --git a/tests/PHPStan/Command/data/file-without-errors.php b/tests/PHPStan/Command/data/file-without-errors.php index 08929907d3..c6d0a42c3a 100644 --- a/tests/PHPStan/Command/data/file-without-errors.php +++ b/tests/PHPStan/Command/data/file-without-errors.php @@ -1,3 +1,3 @@ analyse([__DIR__ . '/data/bug-3770.php'], [ + [ + 'Call to function array_map() on a separate line has no effect.', + 8, + ], + [ + 'Call to function array_map() on a separate line has no effect.', + 15, + ], + [ + 'Call to function array_map() on a separate line has no effect.', + 23, + ], + ]); + } + + public function testBug11317(): void + { + $this->analyse([__DIR__ . '/data/bug-11317.php'], [ + [ + 'Call to function array_map() on a separate line has no effect.', + 12, + ], + ]); + } + + public function testBug11101(): void + { + $this->analyse([__DIR__ . '/data/bug-11101.php'], [ + [ + 'Call to function array_filter() on a separate line has no effect.', + 11, + ], + [ + 'Call to function array_map() on a separate line has no effect.', + 12, + ], + [ + 'Call to function array_reduce() on a separate line has no effect.', + 13, + ], + ]); + } + #[RequiresPhp('>= 8.5')] public function testPipeOperator(): void { diff --git a/tests/PHPStan/Rules/Functions/data/bug-11101.php b/tests/PHPStan/Rules/Functions/data/bug-11101.php new file mode 100644 index 0000000000..161714aa0a --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-11101.php @@ -0,0 +1,23 @@ + $array + */ +function doFoo(array $array): void +{ + // These should all be reported as having no effect + array_filter($array, 'is_string'); // line 11 + array_map('is_string', $array); // line 12 + array_reduce($array, function ($carry, $item) { // line 13 + return $carry + $item; + }, 0); + + // These are fine - using the return value + $a = array_filter($array, 'is_string'); + $b = array_map('is_string', $array); + $c = array_reduce($array, function ($carry, $item) { + return $carry + $item; + }, 0); +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-11317.php b/tests/PHPStan/Rules/Functions/data/bug-11317.php new file mode 100644 index 0000000000..be633f78ee --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-11317.php @@ -0,0 +1,16 @@ + $a + */ + public function sayHello(array $a): void + { + array_map(function ($i) { + return $i; + }, $a); + } +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-3770.php b/tests/PHPStan/Rules/Functions/data/bug-3770.php new file mode 100644 index 0000000000..c5781f5a34 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-3770.php @@ -0,0 +1,27 @@ + $numbers */ +$numbers = []; + +array_map( + function ($value) { + return $value; + }, + $numbers, +); + +array_map( + /** @param 1|2|3 $value */ + function ($value) { + return $value; + }, + $numbers, +); + +array_map( + /** @param 1|2|3 $value */ + fn($value) => $value, + $numbers, +); diff --git a/tests/PHPStan/Rules/Pure/PureMethodRuleTest.php b/tests/PHPStan/Rules/Pure/PureMethodRuleTest.php index 0aa586868e..c8464ee419 100644 --- a/tests/PHPStan/Rules/Pure/PureMethodRuleTest.php +++ b/tests/PHPStan/Rules/Pure/PureMethodRuleTest.php @@ -279,6 +279,12 @@ public function testAllMethodsArePure(): void ]); } + public function testBug11100(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-11100.php'], []); + } + public function testBug12382(): void { $this->treatPhpDocTypesAsCertain = true; diff --git a/tests/PHPStan/Rules/Pure/data/bug-11100.php b/tests/PHPStan/Rules/Pure/data/bug-11100.php new file mode 100644 index 0000000000..a0e3f5f384 --- /dev/null +++ b/tests/PHPStan/Rules/Pure/data/bug-11100.php @@ -0,0 +1,30 @@ += 8.0 + +namespace Bug11100; + +final class FooClass +{ + /** + * @param array $getParams + * + * @phpstan-pure + */ + public function build(array $getParams, string $trailingSlash, bool $useSlashSeparator): string + { + if ($getParams === []) { + return ''; + } + + if ($useSlashSeparator) { + return '/' . implode('/', array_map( + static function (string $key, string|int $value): string { + return rawurlencode($key) . '/' . rawurlencode((string) $value); + }, + array_keys($getParams), + $getParams + )) . $trailingSlash; + } + + return $trailingSlash . '?' . http_build_query($getParams); + } +}