From 16cd93f8f41d64589640420faee2eb7e0e012b55 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 17 Nov 2025 07:08:19 +0100 Subject: [PATCH 1/8] De-duplicate phpstan.php errors --- src/Analyser/FileAnalyser.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index af45937bff..2bf1a48477 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -52,7 +52,7 @@ final class FileAnalyser /** @var list */ private array $allPhpErrors = []; - /** @var list */ + /** @var array */ private array $filteredPhpErrors = []; public function __construct( @@ -377,7 +377,8 @@ private function collectErrors(array $analysedFiles): void return true; } - $this->filteredPhpErrors[] = (new Error($errorMessage, $errfile, $errline, $errno === E_USER_DEPRECATED))->withIdentifier('phpstan.php'); + $errorSignature = hash('sha256',md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); + $this->filteredPhpErrors[$errorSignature] = (new Error($errorMessage, $errfile, $errline, $errno === E_USER_DEPRECATED))->withIdentifier('phpstan.php'); return true; }); From 27e88c3f0834b0b6b330ce748c9fe8f3c40daf3b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 17 Nov 2025 07:51:08 +0100 Subject: [PATCH 2/8] Added regression test --- .../Analyser/Bug13813IntegrationTest.php | 53 +++++++++++++++++++ tests/PHPStan/Analyser/Bug13813Rule.php | 29 ++++++++++ tests/PHPStan/Analyser/bug13813.neon | 2 + tests/PHPStan/Analyser/data/bug-13813.php | 7 +++ 4 files changed, 91 insertions(+) create mode 100644 tests/PHPStan/Analyser/Bug13813IntegrationTest.php create mode 100644 tests/PHPStan/Analyser/Bug13813Rule.php create mode 100644 tests/PHPStan/Analyser/bug13813.neon create mode 100644 tests/PHPStan/Analyser/data/bug-13813.php diff --git a/tests/PHPStan/Analyser/Bug13813IntegrationTest.php b/tests/PHPStan/Analyser/Bug13813IntegrationTest.php new file mode 100644 index 0000000000..64123ced66 --- /dev/null +++ b/tests/PHPStan/Analyser/Bug13813IntegrationTest.php @@ -0,0 +1,53 @@ +runAnalyse([ + __DIR__ . '/data/bug-13813.php', + __DIR__ . '/Bug13813Rule.php', + ]); + $this->assertCount(2, $analyzerResult->getAllPhpErrors()); + $this->assertCount(2, $analyzerResult->getFilteredPhpErrors()); + } + + /** + * @param string[] $files + * @return Error[] + */ + private function runAnalyse(array $files): AnalyserResult + { + $files = array_map(fn (string $file): string => $this->getFileHelper()->normalizePath($file), $files); + /** @var Analyser $analyser */ + $analyser = self::getContainer()->getByType(Analyser::class); + + return $analyser->analyse($files); + } + + public static function getAdditionalConfigFiles(): array + { + return array_unique( + array_merge( + parent::getAdditionalConfigFiles(), + [ + __DIR__ . '/bug13813.neon', + ], + ), + ); + } + +} diff --git a/tests/PHPStan/Analyser/Bug13813Rule.php b/tests/PHPStan/Analyser/Bug13813Rule.php new file mode 100644 index 0000000000..0afa81f9f4 --- /dev/null +++ b/tests/PHPStan/Analyser/Bug13813Rule.php @@ -0,0 +1,29 @@ + + */ +class Bug13813Rule implements Rule +{ + + public function getNodeType(): string + { + return Variable::class; + } + + public function processNode(Node $node, Scope $scope): array + { + for ($i = 0; $i < 100; $i++) { + echo $x; // force emit a PHP warning at runtime + } + + return []; + } + +} diff --git a/tests/PHPStan/Analyser/bug13813.neon b/tests/PHPStan/Analyser/bug13813.neon new file mode 100644 index 0000000000..3e5cb699b4 --- /dev/null +++ b/tests/PHPStan/Analyser/bug13813.neon @@ -0,0 +1,2 @@ +rules: + - PHPStan\Analyser\Bug13813Rule diff --git a/tests/PHPStan/Analyser/data/bug-13813.php b/tests/PHPStan/Analyser/data/bug-13813.php new file mode 100644 index 0000000000..68b6418a2d --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-13813.php @@ -0,0 +1,7 @@ + Date: Mon, 17 Nov 2025 07:53:00 +0100 Subject: [PATCH 3/8] fix --- src/Analyser/FileAnalyser.php | 9 +++++---- tests/PHPStan/Analyser/Bug13813IntegrationTest.php | 1 - tests/PHPStan/Analyser/Bug13813Rule.php | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index 2bf1a48477..54d1207a82 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -49,7 +49,7 @@ final class FileAnalyser { - /** @var list */ + /** @var array */ private array $allPhpErrors = []; /** @var array */ @@ -326,8 +326,8 @@ public function analyseFile( return new FileAnalyserResult( $fileErrors, - $this->filteredPhpErrors, - $this->allPhpErrors, + array_values($this->filteredPhpErrors), + array_values($this->allPhpErrors), $locallyIgnoredErrors, $fileCollectedData, array_values(array_unique($fileDependencies)), @@ -367,7 +367,8 @@ private function collectErrors(array $analysedFiles): void $errorMessage = sprintf('%s: %s', $this->getErrorLabel($errno), $errstr); - $this->allPhpErrors[] = (new Error($errorMessage, $errfile, $errline, false))->withIdentifier('phpstan.php'); + $errorSignature = hash('sha256',md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); + $this->allPhpErrors[$errorSignature] = (new Error($errorMessage, $errfile, $errline, false))->withIdentifier('phpstan.php'); if ($errno === E_DEPRECATED) { return true; diff --git a/tests/PHPStan/Analyser/Bug13813IntegrationTest.php b/tests/PHPStan/Analyser/Bug13813IntegrationTest.php index 64123ced66..01c2181714 100644 --- a/tests/PHPStan/Analyser/Bug13813IntegrationTest.php +++ b/tests/PHPStan/Analyser/Bug13813IntegrationTest.php @@ -27,7 +27,6 @@ public function testBug13813(): void /** * @param string[] $files - * @return Error[] */ private function runAnalyse(array $files): AnalyserResult { diff --git a/tests/PHPStan/Analyser/Bug13813Rule.php b/tests/PHPStan/Analyser/Bug13813Rule.php index 0afa81f9f4..d1bfaa1c55 100644 --- a/tests/PHPStan/Analyser/Bug13813Rule.php +++ b/tests/PHPStan/Analyser/Bug13813Rule.php @@ -20,6 +20,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { for ($i = 0; $i < 100; $i++) { + // @phpstan-ignore variable.undefined echo $x; // force emit a PHP warning at runtime } From 99c68b3fba0bcd439df6c3cb65d8a73ca5bef446 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 17 Nov 2025 07:54:15 +0100 Subject: [PATCH 4/8] cs --- src/Analyser/FileAnalyser.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index 54d1207a82..b2e830b803 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -26,8 +26,10 @@ use function count; use function error_reporting; use function get_class; +use function hash; use function is_dir; use function is_file; +use function md5; use function restore_error_handler; use function set_error_handler; use function sprintf; @@ -367,7 +369,7 @@ private function collectErrors(array $analysedFiles): void $errorMessage = sprintf('%s: %s', $this->getErrorLabel($errno), $errstr); - $errorSignature = hash('sha256',md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); + $errorSignature = hash('sha256', md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); $this->allPhpErrors[$errorSignature] = (new Error($errorMessage, $errfile, $errline, false))->withIdentifier('phpstan.php'); if ($errno === E_DEPRECATED) { @@ -378,7 +380,7 @@ private function collectErrors(array $analysedFiles): void return true; } - $errorSignature = hash('sha256',md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); + $errorSignature = hash('sha256', md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); $this->filteredPhpErrors[$errorSignature] = (new Error($errorMessage, $errfile, $errline, $errno === E_USER_DEPRECATED))->withIdentifier('phpstan.php'); return true; From fdac0dcef09253d4c7bd1fff33465c2746255049 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 17 Nov 2025 08:00:20 +0100 Subject: [PATCH 5/8] Update FileAnalyser.php --- src/Analyser/FileAnalyser.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index b2e830b803..72e5c5f56d 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -368,8 +368,8 @@ private function collectErrors(array $analysedFiles): void } $errorMessage = sprintf('%s: %s', $this->getErrorLabel($errno), $errstr); - $errorSignature = hash('sha256', md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); + $this->allPhpErrors[$errorSignature] = (new Error($errorMessage, $errfile, $errline, false))->withIdentifier('phpstan.php'); if ($errno === E_DEPRECATED) { @@ -380,7 +380,6 @@ private function collectErrors(array $analysedFiles): void return true; } - $errorSignature = hash('sha256', md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); $this->filteredPhpErrors[$errorSignature] = (new Error($errorMessage, $errfile, $errline, $errno === E_USER_DEPRECATED))->withIdentifier('phpstan.php'); return true; From fe55662d41973b1729ec05bd1ae0c7829ca105ce Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 17 Nov 2025 08:01:54 +0100 Subject: [PATCH 6/8] Update FileAnalyser.php --- src/Analyser/FileAnalyser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index 72e5c5f56d..78457557ea 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -368,7 +368,7 @@ private function collectErrors(array $analysedFiles): void } $errorMessage = sprintf('%s: %s', $this->getErrorLabel($errno), $errstr); - $errorSignature = hash('sha256', md5(sprintf('%s:%s::%s', $errfile, $errline, $errorMessage))); + $errorSignature = hash('sha256', sprintf('%s:%s::%s', $errfile, $errline, $errorMessage)); $this->allPhpErrors[$errorSignature] = (new Error($errorMessage, $errfile, $errline, false))->withIdentifier('phpstan.php'); From 645045205da4acf622db3f0e55426bd552135c63 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 17 Nov 2025 08:02:18 +0100 Subject: [PATCH 7/8] Update FileAnalyser.php --- src/Analyser/FileAnalyser.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index 78457557ea..9f8f79d226 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -29,7 +29,6 @@ use function hash; use function is_dir; use function is_file; -use function md5; use function restore_error_handler; use function set_error_handler; use function sprintf; From 7abab1d9168bc46957c335dd938e13f11bd1de4a Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 17 Nov 2025 08:03:42 +0100 Subject: [PATCH 8/8] Update Bug13813IntegrationTest.php --- tests/PHPStan/Analyser/Bug13813IntegrationTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/PHPStan/Analyser/Bug13813IntegrationTest.php b/tests/PHPStan/Analyser/Bug13813IntegrationTest.php index 01c2181714..943a17c084 100644 --- a/tests/PHPStan/Analyser/Bug13813IntegrationTest.php +++ b/tests/PHPStan/Analyser/Bug13813IntegrationTest.php @@ -23,6 +23,15 @@ public function testBug13813(): void ]); $this->assertCount(2, $analyzerResult->getAllPhpErrors()); $this->assertCount(2, $analyzerResult->getFilteredPhpErrors()); + + $this->assertSame( + 'Warning: Undefined variable $x', + $analyzerResult->getAllPhpErrors()[0]->getMessage() + ); + $this->assertSame( + 'Warning: Undefined variable $x', + $analyzerResult->getAllPhpErrors()[1]->getMessage() + ); } /**