From 65d23fb8ae9241b8d92a3053dc67d88a8fabd95e Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 03:56:22 +0000 Subject: [PATCH 01/24] Apply fix diffs in a single linear pass Patcher re-diffed the whole accumulated file against the original for every diff, which is quadratic in file size times number of fixes and made --fix hang on files with hundreds of fixable errors. All diffs share the same base, so their change runs can be spliced into the original in one pass. A diff overlapping an already accepted one is now skipped on its own instead of discarding every fix in the file, and the summary no longer counts skipped errors as fixed. This removes the ondrejmirtes/php-merge dependency. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- .github/workflows/phar.yml | 6 +- build/php-85.neon | 6 - composer.json | 1 - composer.lock | 60 +------ phpstan-baseline.neon | 18 -- src/Command/AnalyseCommand.php | 13 +- src/Fixable/MergeConflictException.php | 10 -- src/Fixable/Patcher.php | 233 ++++++++++++++----------- src/Testing/RuleTestCase.php | 5 +- 9 files changed, 143 insertions(+), 209 deletions(-) delete mode 100644 src/Fixable/MergeConflictException.php diff --git a/.github/workflows/phar.yml b/.github/workflows/phar.yml index 8fc1d8aa7e2..9ccc5ef72b4 100644 --- a/.github/workflows/phar.yml +++ b/.github/workflows/phar.yml @@ -70,8 +70,12 @@ jobs: ignore-cache: true # only sebastian/diff ^4 supports PHP 7.4 so we need that in the PHAR + # it stays in require, the PHAR is built without dev dependencies and the fixer needs it - name: "Downgrade PHPUnit" - run: "composer require --dev phpunit/phpunit:^9.6 sebastian/diff:^4.0 doctrine/instantiator:^1.0 --update-with-dependencies --ignore-platform-reqs" + run: | + composer require --no-update sebastian/diff:^4.0 + composer require --dev --no-update phpunit/phpunit:^9.6 doctrine/instantiator:^1.0 + composer update phpunit/phpunit sebastian/diff doctrine/instantiator --with-all-dependencies --ignore-platform-reqs - name: "Install compiler dependencies" uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # v4.0.0 diff --git a/build/php-85.neon b/build/php-85.neon index 41c64921f3f..1184ba16da9 100644 --- a/build/php-85.neon +++ b/build/php-85.neon @@ -1,11 +1,5 @@ parameters: ignoreErrors: - - - rawMessage: 'Call to deprecated method setAccessible() of class ReflectionMethod.' - identifier: method.deprecated - count: 1 - path: ../src/Fixable/Patcher.php - - rawMessage: 'Call to deprecated method setAccessible() of class ReflectionProperty.' identifier: method.deprecated diff --git a/composer.json b/composer.json index f8114f00410..56f370f1f97 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,6 @@ "ondram/ci-detector": "^4.0", "ondrejmirtes/better-reflection": "6.75.0.4", "ondrejmirtes/composer-attribute-collector": "^1.2.0", - "ondrejmirtes/php-merge": "^4.1", "ondrejmirtes/phplrt-runtime": "4.2.4.1", "phpstan/php-8-stubs": "0.4.43", "phpstan/phpdoc-parser": "2.4.1", diff --git a/composer.lock b/composer.lock index 71d8e2207b8..281258870e9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b4aec40b93330400ac2e7427e2d76f11", + "content-hash": "a8d2789a6b389b1d8f79dd929b0d5cba", "packages": [ { "name": "clue/ndjson-react", @@ -1477,64 +1477,6 @@ }, "time": "2026-07-23T20:44:20+00:00" }, - { - "name": "ondrejmirtes/php-merge", - "version": "4.1.2", - "source": { - "type": "git", - "url": "https://github.com/ondrejmirtes/php-merge.git", - "reference": "0c661fbe3efde0619f3652688862ed65f1f34dd1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ondrejmirtes/php-merge/zipball/0c661fbe3efde0619f3652688862ed65f1f34dd1", - "reference": "0c661fbe3efde0619f3652688862ed65f1f34dd1", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0", - "sebastian/diff": "^2.0|^3.0|^4.0|^5.0|^6.0|^7.0" - }, - "require-dev": { - "escapestudios/symfony2-coding-standard": "^3.5", - "phpstan/phpstan": "~1", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpunit/phpunit": "~6|~7|~8|~9|~10|~11|~12", - "squizlabs/php_codesniffer": "~3", - "symplify/git-wrapper": "^9.1|^10.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "PhpMerge": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabian Bircher", - "email": "opensource@fabianbircher.com" - }, - { - "name": "Ondrej Mirtes", - "email": "ondrej@mirtes.cz" - } - ], - "description": "A PHP merge utility using the Diff php library or the command line git.", - "homepage": "https://github.com/bircher/php-merge", - "keywords": [ - "git", - "merge", - "php-merge" - ], - "support": { - "source": "https://github.com/ondrejmirtes/php-merge/tree/4.1.2" - }, - "time": "2025-12-09T08:32:19+00:00" - }, { "name": "ondrejmirtes/phplrt-runtime", "version": "4.2.4.1", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3aa2c134904..fcc988632b3 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -265,24 +265,6 @@ parameters: count: 1 path: src/DependencyInjection/NeonAdapter.php - - - rawMessage: 'Call to method getContent() of internal class PhpMerge\internal\Line from outside its root namespace PhpMerge.' - identifier: method.internalClass - count: 2 - path: src/Fixable/Patcher.php - - - - rawMessage: 'Call to static method createArray() of internal class PhpMerge\internal\Hunk from outside its root namespace PhpMerge.' - identifier: staticMethod.internalClass - count: 2 - path: src/Fixable/Patcher.php - - - - rawMessage: 'Call to static method createArray() of internal class PhpMerge\internal\Line from outside its root namespace PhpMerge.' - identifier: staticMethod.internalClass - count: 5 - path: src/Fixable/Patcher.php - - rawMessage: 'Call to method getTokenCode() of internal class PhpParser\Internal\TokenStream from outside its root namespace PhpParser.' identifier: method.internalClass diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index b8a93670725..07fc64e40f5 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -21,7 +21,6 @@ use PHPStan\File\PathNotFoundException; use PHPStan\File\RelativePathHelper; use PHPStan\Fixable\FileChangedException; -use PHPStan\Fixable\MergeConflictException; use PHPStan\Fixable\Patcher; use PHPStan\Internal\AgentDetector; use PHPStan\Internal\BytesHelper; @@ -584,24 +583,26 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($diffsByFile as $file => $diffs) { $diffsCount = count($diffs); try { - $finalFileContents = $patcher->applyDiffs($file, $diffs); + $patchResult = $patcher->applyDiffs($file, $diffs); + $skippedCount += $patchResult['skippedCount']; $errorOutput->getStyle()->progressAdvance($diffsCount); - } catch (FileChangedException | MergeConflictException) { + } catch (FileChangedException) { $skippedCount += $diffsCount; $errorOutput->getStyle()->progressAdvance($diffsCount); continue; } - FileWriter::write($file, $finalFileContents); + FileWriter::write($file, $patchResult['contents']); } $errorOutput->getStyle()->progressFinish(); if ($skippedCount > 0) { + $fixedCount = $fixableErrorsCount - $skippedCount; $inceptionResult->getStdOutput()->getStyle()->warning(sprintf( '%d %s fixed, %d %s skipped', - $fixableErrorsCount, - $fixableErrorsCount === 1 ? 'error' : 'errors', + $fixedCount, + $fixedCount === 1 ? 'error' : 'errors', $skippedCount, $skippedCount === 1 ? 'error' : 'errors', )); diff --git a/src/Fixable/MergeConflictException.php b/src/Fixable/MergeConflictException.php deleted file mode 100644 index e1f377f66e6..00000000000 --- a/src/Fixable/MergeConflictException.php +++ /dev/null @@ -1,10 +0,0 @@ -differ = new Differ(new UnifiedDiffOutputBuilder()); - } - /** * @param FixedErrorDiff[] $diffs + * @return array{contents: string, skippedCount: int} * @throws FileChangedException - * @throws MergeConflictException */ - public function applyDiffs(string $fileName, array $diffs): string + public function applyDiffs(string $fileName, array $diffs): array { $fileContents = FileReader::read($fileName); $fileHash = hash('sha256', $fileContents); - $diffHunks = []; foreach ($diffs as $diff) { if ($diff->originalHash !== $fileHash) { throw new FileChangedException(); } - - $diffHunks[] = Hunk::createArray(Line::createArray($this->reconstructFullDiff($fileContents, $diff->diff))); } - if (count($diffHunks) === 0) { - return $fileContents; - } - - $baseLines = Line::createArray(array_map( - static fn ($l) => [$l, Differ::OLD], - self::splitStringByLines($fileContents), - )); + /** @var list}> $acceptedRuns sorted by start, non-overlapping */ + $acceptedRuns = []; + $skippedCount = 0; + foreach ($diffs as $diff) { + $insertions = []; + foreach (self::parseChangeRuns($diff->diff) as $run) { + $index = self::findInsertionIndex($acceptedRuns, $run); + if ($index === null) { + $skippedCount++; + continue 2; + } + if (isset($acceptedRuns[$index]) && $acceptedRuns[$index] === $run) { + // another diff makes the exact same change + continue; + } + $insertions[] = [$index, $run]; + } - $refMerge = new ReflectionClass(PhpMerge::class); - $refMergeMethod = $refMerge->getMethod('mergeHunks'); - if (PHP_VERSION_ID < 80100) { - $refMergeMethod->setAccessible(true); + // runs of a single diff are ordered and non-overlapping, + // inserting from the last one keeps the earlier indexes valid + for ($i = count($insertions) - 1; $i >= 0; $i--) { + array_splice($acceptedRuns, $insertions[$i][0], 0, [$insertions[$i][1]]); + } } - $result = Line::createArray(array_map( - static fn ($l) => [$l, Differ::OLD], - $refMergeMethod->invokeArgs(null, [ - $baseLines, - $diffHunks[0], - [], - ]), - )); - - for ($i = 0; $i < count($diffHunks); $i++) { - /** @var MergeConflict[] $conflicts */ - $conflicts = []; - $merged = $refMergeMethod->invokeArgs(null, [ - $baseLines, - Hunk::createArray(Line::createArray($this->differ->diffToArray($fileContents, implode('', array_map(static fn ($l) => $l->getContent(), $result))))), - $diffHunks[$i], - &$conflicts, - ]); - if (count($conflicts) > 0) { - throw new MergeConflictException(); + $baseLines = self::splitStringByLines($fileContents); + $result = []; + $position = 0; + foreach ($acceptedRuns as [$start, $removedCount, $addedLines]) { + for (; $position < $start; $position++) { + $result[] = $baseLines[$position]; } - - $result = Line::createArray(array_map( - static fn ($l) => [$l, Differ::OLD], - $merged, - )); - + foreach ($addedLines as $addedLine) { + $result[] = $addedLine; + } + $position += $removedCount; + } + for ($baseLinesCount = count($baseLines); $position < $baseLinesCount; $position++) { + $result[] = $baseLines[$position]; } - return implode('', array_map(static fn ($l) => $l->getContent(), $result)); + return [ + 'contents' => implode('', $result), + 'skippedCount' => $skippedCount, + ]; } /** - * @return array + * Returns the index in $acceptedRuns where $run belongs, or null when it conflicts with an accepted run. + * When the run at the returned index is identical to $run, the change is already accepted. + * + * @param list}> $acceptedRuns + * @param array{int, int, list} $run */ - private function reconstructFullDiff(string $originalText, string $unifiedDiff): array + private static function findInsertionIndex(array $acceptedRuns, array $run): ?int { - $originalLines = self::splitStringByLines($originalText); - $diffLines = self::splitStringByLines($unifiedDiff); - $result = []; + // lower bound by [start, removedCount] - insertions come before replacements starting at the same line + $low = 0; + $high = count($acceptedRuns); + while ($low < $high) { + $mid = intdiv($low + $high, 2); + if ([$acceptedRuns[$mid][0], $acceptedRuns[$mid][1]] < [$run[0], $run[1]]) { + $low = $mid + 1; + } else { + $high = $mid; + } + } - $origLineNo = 0; - $diffPos = 0; + if (isset($acceptedRuns[$low]) && $acceptedRuns[$low] === $run) { + return $low; + } + if ($low > 0 && !self::isBefore($acceptedRuns[$low - 1], $run)) { + return null; + } + if (isset($acceptedRuns[$low]) && !self::isBefore($run, $acceptedRuns[$low])) { + return null; + } - while ($diffPos < count($diffLines)) { - $line = $diffLines[$diffPos]; + return $low; + } + + /** + * @param array{int, int, list} $a + * @param array{int, int, list} $b + */ + private static function isBefore(array $a, array $b): bool + { + if ($a[1] === 0 && $b[1] === 0 && $a[0] === $b[0]) { + // two different insertions at the same line - their order is ambiguous + return false; + } - $matches = Strings::match($line, '/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/'); - if ($matches !== null) { - // Parse hunk header - $origStart = (int) $matches[1] - 1; // 0-based - $diffPos++; + return $a[0] + $a[1] <= $b[0]; + } - // Emit kept lines before hunk - while ($origLineNo < $origStart) { - $result[] = [$originalLines[$origLineNo], Differ::OLD]; - $origLineNo++; + /** + * @return list}> [0-based start line in the original file, number of removed lines, added lines] + */ + private static function parseChangeRuns(string $unifiedDiff): array + { + $runs = []; + $run = null; + $originalLine = 0; + foreach (self::splitStringByLines($unifiedDiff) as $line) { + if (str_starts_with($line, '@@')) { + if ($run !== null) { + $runs[] = $run; + $run = null; + } + $matches = Strings::match($line, '/^@@ -(\d+)/'); + if ($matches !== null) { + $originalLine = (int) $matches[1] - 1; } + continue; + } - // Process hunk - while ($diffPos < count($diffLines)) { - $line = $diffLines[$diffPos]; - if (str_starts_with($line, '@@')) { - break; // next hunk - } - - $prefix = $line[0] ?? ''; - $content = substr($line, 1); - - if ($prefix === ' ') { - $result[] = [$content, Differ::OLD]; - $origLineNo++; - } elseif ($prefix === '-') { - $result[] = [$content, Differ::REMOVED]; - $origLineNo++; - } elseif ($prefix === '+') { - $result[] = [$content, Differ::ADDED]; - } - - $diffPos++; + $prefix = $line[0]; + if ($prefix === '-') { + $run ??= [$originalLine, 0, []]; + $run[1]++; + $originalLine++; + } elseif ($prefix === '+') { + $run ??= [$originalLine, 0, []]; + $run[2][] = substr($line, 1); + } elseif ($prefix === ' ') { + if ($run !== null) { + $runs[] = $run; + $run = null; } - } else { - $diffPos++; + $originalLine++; } } - // Emit remaining lines as kept - while ($origLineNo < count($originalLines)) { - $result[] = [$originalLines[$origLineNo], Differ::OLD]; - $origLineNo++; + if ($run !== null) { + $runs[] = $run; } - return $result; + return $runs; } /** diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 99f8770e99c..5523d0b6b33 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -244,11 +244,12 @@ public function fix(string $file, string $expectedFile): void } $patcher = self::getContainer()->getByType(Patcher::class); - $newFileContents = $patcher->applyDiffs($file, $diffs); // @phpstan-ignore missingType.checkedException, missingType.checkedException + $patchResult = $patcher->applyDiffs($file, $diffs); // @phpstan-ignore missingType.checkedException + $this->assertSame(0, $patchResult['skippedCount'], 'Some fixes overlap and could not be applied together.'); $fixedFileContents = FileReader::read($expectedFile); - $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($newFileContents)); + $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($patchResult['contents'])); } private function normalizeLineEndings(string $string): string From 31e428faa3049e55124be24e7f3d2516a620b47c Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 03:56:43 +0000 Subject: [PATCH 02/24] Compute fix diffs without quadratic suffix trimming sebastian/diff strips the common trailing lines by prepending to an array, which is quadratic, so a one-line fix near the top of an 11k-line file took 0.7 s to diff. Trim the common prefix and suffix in linear time and only diff the changed middle. The output is byte-identical. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Analyser/RuleErrorTransformer.php | 72 ++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index 44fba3671e4..717e808e14b 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -30,11 +30,16 @@ use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; use function array_key_exists; use function array_shift; +use function array_slice; use function count; use function get_class; use function hash; +use function min; +use function preg_split; use function str_contains; use function str_repeat; +use const PREG_SPLIT_DELIM_CAPTURE; +use const PREG_SPLIT_NO_EMPTY; #[AutowiredService] final class RuleErrorTransformer @@ -46,6 +51,8 @@ final class RuleErrorTransformer private Differ $differ; + private UnifiedDiffOutputBuilder $diffOutputBuilder; + /** @var array */ private array $parsedFiles = []; @@ -57,7 +64,8 @@ public function __construct( private Parser $parser, ) { - $this->differ = new Differ(new UnifiedDiffOutputBuilder('', addLineNumbers: true)); + $this->diffOutputBuilder = new UnifiedDiffOutputBuilder('', addLineNumbers: true); + $this->differ = new Differ($this->diffOutputBuilder); } /** @@ -197,7 +205,67 @@ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, c return null; } - return new FixedErrorDiff($parsedFile['hash'], $this->differ->diff($parsedFile['code'], $newCode)); + return new FixedErrorDiff($parsedFile['hash'], $this->diff($parsedFile['code'], $newCode)); + } + + /** + * Same output as Differ::diff(), but the common leading and trailing lines are found here in linear time. + * Differ strips them too, but in quadratic time, which made each fix in a large file cost up to a second. + * The middle part is usually just the fixed node. + */ + private function diff(string $from, string $to): string + { + $fromLines = self::splitStringByLines($from); + $toLines = self::splitStringByLines($to); + $fromCount = count($fromLines); + $toCount = count($toLines); + $minCount = min($fromCount, $toCount); + + $startCount = 0; + while ($startCount < $minCount && $fromLines[$startCount] === $toLines[$startCount]) { + $startCount++; + } + + $endCount = 0; + while ( + $endCount < $minCount - $startCount + && $fromLines[$fromCount - 1 - $endCount] === $toLines[$toCount - 1 - $endCount] + ) { + $endCount++; + } + + $diff = []; + for ($i = 0; $i < $startCount; $i++) { + $diff[] = [$fromLines[$i], Differ::OLD]; + } + foreach ($this->differ->diffToArray( + array_slice($fromLines, $startCount, $fromCount - $startCount - $endCount), + array_slice($toLines, $startCount, $toCount - $startCount - $endCount), + ) as $entry) { + if ($entry[1] === Differ::DIFF_LINE_END_WARNING) { + // the warning would be printed as a context line and shift the line numbers in Patcher + continue; + } + $diff[] = $entry; + } + for ($i = $fromCount - $endCount; $i < $fromCount; $i++) { + $diff[] = [$fromLines[$i], Differ::OLD]; + } + + return $this->diffOutputBuilder->getDiff($diff); + } + + /** + * @return list + */ + private static function splitStringByLines(string $input): array + { + $lines = preg_split('/(.*\R)/', $input, flags: PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + if ($lines === false) { + throw new ShouldNotHappenException(); + } + + return $lines; } /** From 11d920924b140cb5b8c5cde7e79e05b242e2c6be Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 03:56:43 +0000 Subject: [PATCH 03/24] Show fixable errors in table output again Reverts 62a123380 now that --fix no longer hangs on many fixes in one file. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Command/ErrorFormatter/TableErrorFormatter.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Command/ErrorFormatter/TableErrorFormatter.php b/src/Command/ErrorFormatter/TableErrorFormatter.php index cfc3cb33a0c..b36fc8a4507 100644 --- a/src/Command/ErrorFormatter/TableErrorFormatter.php +++ b/src/Command/ErrorFormatter/TableErrorFormatter.php @@ -95,7 +95,11 @@ public function formatErrors( /** @var array $fileErrors */ $fileErrors = []; + $fixableErrorsCount = 0; foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { + if ($fileSpecificError->getFixedErrorDiff() !== null) { + $fixableErrorsCount++; + } if (!isset($fileErrors[$fileSpecificError->getFile()])) { $fileErrors[$fileSpecificError->getFile()] = []; } @@ -116,6 +120,9 @@ public function formatErrors( ) { $message = '' . OutputFormatter::escape($message) . ''; } + if ($error->getFixedErrorDiff() !== null) { + $message .= ' 🔧'; + } if ($error->getIdentifier() !== null) { $message .= "\n"; $message .= '🪪 ' . $error->getIdentifier(); @@ -214,6 +221,11 @@ public function formatErrors( } } + if ($fixableErrorsCount > 0) { + $output->writeLineFormatted(sprintf('🔧 %d %s can be fixed automatically. Run PHPStan again with --fix.', $fixableErrorsCount, $fixableErrorsCount === 1 ? 'error' : 'errors')); + $output->writeLineFormatted(''); + } + return $analysisResult->getTotalErrorsCount() > 0 ? 1 : 0; } From 5b859be6d916bee3e1f3ad57afac0b7bc7380798 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 03:56:45 +0000 Subject: [PATCH 04/24] Support fixNode() in CollectedDataNode rules Errors of CollectedDataNode rules come without the file AST, so the fix is computed on the file parsed by the cached analysis parser. The rule has to take the fixed node from the same parser so that it is found by identity. A reused CollectedDataNode rule result is discarded when a file it fixes has changed, otherwise its diffs would never apply. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Analyser/AnalyserResultFinalizer.php | 15 +++++ src/Analyser/RuleErrorTransformer.php | 23 ++++++- .../Analyser/CollectedDataRuleReuseTest.php | 27 ++++++++ .../Fixable/FixCollectedFuncCallRule.php | 62 +++++++++++++++++++ .../Fixable/FixCollectedFuncCallRuleTest.php | 29 +++++++++ .../PHPStan/Fixable/FooFuncCallCollector.php | 31 ++++++++++ .../Fixable/data/collected-func-call.php | 19 ++++++ .../data/collected-func-call.php.fixed | 19 ++++++ 8 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Fixable/FixCollectedFuncCallRule.php create mode 100644 tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php create mode 100644 tests/PHPStan/Fixable/FooFuncCallCollector.php create mode 100644 tests/PHPStan/Fixable/data/collected-func-call.php create mode 100644 tests/PHPStan/Fixable/data/collected-func-call.php.fixed diff --git a/src/Analyser/AnalyserResultFinalizer.php b/src/Analyser/AnalyserResultFinalizer.php index 93826adf642..d905d7d584f 100644 --- a/src/Analyser/AnalyserResultFinalizer.php +++ b/src/Analyser/AnalyserResultFinalizer.php @@ -20,6 +20,8 @@ use function array_merge; use function count; use function get_class; +use function hash_file; +use function is_file; use function ksort; use function md5; use function serialize; @@ -307,6 +309,19 @@ private function canReuse(CollectedDataRuleResult $previousResult, bool $onlyFil } } + // a fix is a diff against the file contents, which can change without changing the collected data + foreach ($previousResult->getErrors() as $error) { + $fixedErrorDiff = $error->getFixedErrorDiff(); + if ($fixedErrorDiff === null) { + continue; + } + + $fixedFile = $error->getTraitFilePath() ?? $error->getFilePath(); + if (!is_file($fixedFile) || hash_file('sha256', $fixedFile) !== $fixedErrorDiff->originalHash) { + return false; + } + } + return true; } diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index 717e808e14b..26399846209 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -16,6 +16,8 @@ use PHPStan\Fixable\PhpPrinterIndentationDetectorVisitor; use PHPStan\Fixable\ReplacingNodeVisitor; use PHPStan\Node\VirtualNode; +use PHPStan\Parser\Parser as AnalysisParser; +use PHPStan\Parser\ParserErrorsException; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -34,6 +36,7 @@ use function count; use function get_class; use function hash; +use function is_file; use function min; use function preg_split; use function str_contains; @@ -62,6 +65,8 @@ final class RuleErrorTransformer public function __construct( #[AutowiredParameter(ref: '@currentPhpVersionPhpParser')] private Parser $parser, + #[AutowiredParameter(ref: '@defaultAnalysisParser')] + private AnalysisParser $analysisParser, ) { $this->diffOutputBuilder = new UnifiedDiffOutputBuilder('', addLineNumbers: true); @@ -159,13 +164,29 @@ public function transform( } /** + * Without $fileNodes (errors of CollectedDataNode rules and errors transformed inside collectors), + * the file is parsed with the cached analysis parser. The rule has to take the node it fixes + * from the same parser so that ReplacingNodeVisitor finds it by identity. + * * @param Node\Stmt[] $fileNodes * @param callable(Node): Node $newNodeCallable */ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, callable $newNodeCallable): ?FixedErrorDiff { if ($fileNodes === []) { - return null; + if (!is_file($fixingFile)) { + return null; + } + + try { + $fileNodes = $this->analysisParser->parseFile($fixingFile); + } catch (ParserErrorsException) { + return null; + } + + if ($fileNodes === []) { + return null; + } } $parsedFile = $this->getParsedFile($fixingFile); diff --git a/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php b/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php index 7df8c83398d..f04c1ddbcd0 100644 --- a/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php +++ b/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php @@ -15,6 +15,8 @@ use PHPStan\Analyser\ResultCache\ResultCacheValueExtension; use PHPStan\Collectors\CollectedData; use PHPStan\File\FileHelper; +use PHPStan\Fixable\FixCollectedFuncCallRule; +use PHPStan\Fixable\FooFuncCallCollector; use PHPStan\Node\CollectedDataNode; use PHPStan\Rules\DirectRegistry; use PHPStan\Rules\Rule; @@ -277,6 +279,31 @@ public function testRuleRunsAgainWhenWhatAClassDeclaresChanged(): void unlink($file); } + public function testRuleWithFixRunsAgainWhenTheFixedFileChanged(): void + { + $file = sys_get_temp_dir() . '/phpstan-collected-data-reuse-fix-' . uniqid() . '.php'; + file_put_contents($file, "getService('defaultAnalysisParser')); + $collectedData = [ + $file => [FooFuncCallCollector::class => [3]], + ]; + + $result = $this->finalize([$rule], $collectedData, false, []); + $errors = $result->getAnalyserResult()->getUnorderedErrors(); + $this->assertCount(1, $errors); + $this->assertNotNull($errors[0]->getFixedErrorDiff()); + + $result = $this->finalize([$rule], $collectedData, false, $result->getCollectedDataRuleResults()); + $this->assertSame(1, $result->getReusedRulesCount()); + + // the collected data stays the same, but the diff of the fix no longer applies + file_put_contents($file, "finalize([$rule], $collectedData, false, $result->getCollectedDataRuleResults()); + $this->assertSame(0, $result->getReusedRulesCount()); + + unlink($file); + } + public function testEveryRuleRunsWithoutTheFeatureToggle(): void { $rule = new EarlyReturnRule(); diff --git a/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php b/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php new file mode 100644 index 00000000000..44228eb6e69 --- /dev/null +++ b/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php @@ -0,0 +1,62 @@ + + */ +class FixCollectedFuncCallRule implements Rule +{ + + public function __construct(private Parser $parser) + { + } + + public function getNodeType(): string + { + return CollectedDataNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $errors = []; + foreach ($node->get(FooFuncCallCollector::class) as $file => $lines) { + foreach ((new NodeFinder())->findInstanceOf($this->parser->parseFile($file), FuncCall::class) as $call) { + if (!$call->name instanceof Name || $call->name->toLowerString() !== 'foo') { + continue; + } + if (!in_array($call->getStartLine(), $lines, true)) { + continue; + } + + $errors[] = RuleErrorBuilder::message('Renaming foo() to bar().') + ->identifier('tests.renameFoo') + ->file($file) + ->line($call->getStartLine()) + ->fixNode($call, static function (FuncCall $call): FuncCall { + $call->name = new Name('bar'); + + return $call; + }) + ->build(); + } + } + + return $errors; + } + +} diff --git a/tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php b/tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php new file mode 100644 index 00000000000..e81f6fc2803 --- /dev/null +++ b/tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php @@ -0,0 +1,29 @@ + + */ +class FixCollectedFuncCallRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new FixCollectedFuncCallRule(self::getContainer()->getService('defaultAnalysisParser')); + } + + protected function getCollectors(): array + { + return [new FooFuncCallCollector()]; + } + + public function testFix(): void + { + $this->fix(__DIR__ . '/data/collected-func-call.php', __DIR__ . '/data/collected-func-call.php.fixed'); + } + +} diff --git a/tests/PHPStan/Fixable/FooFuncCallCollector.php b/tests/PHPStan/Fixable/FooFuncCallCollector.php new file mode 100644 index 00000000000..0feb5ae0d7f --- /dev/null +++ b/tests/PHPStan/Fixable/FooFuncCallCollector.php @@ -0,0 +1,31 @@ + + */ +class FooFuncCallCollector implements Collector +{ + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope) + { + if (!$node->name instanceof Name || $node->name->toLowerString() !== 'foo') { + return null; + } + + return $node->getStartLine(); + } + +} diff --git a/tests/PHPStan/Fixable/data/collected-func-call.php b/tests/PHPStan/Fixable/data/collected-func-call.php new file mode 100644 index 00000000000..74cfde728bf --- /dev/null +++ b/tests/PHPStan/Fixable/data/collected-func-call.php @@ -0,0 +1,19 @@ + Date: Mon, 2 Nov 2026 03:59:33 +0000 Subject: [PATCH 05/24] Test fixes in traits RuleTestCase::fix() takes the file the fixes are applied to when it is not the analysed file, analyses it as well because traits are analysed only in analysed files, and applies only the diffs of that file. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Testing/RuleTestCase.php | 20 +++++++++++++++++-- tests/PHPStan/Fixable/FixIssetRuleTest.php | 15 ++++++++++++++ .../Fixable/data/trait/FixableTrait.php | 13 ++++++++++++ .../Fixable/data/trait/FixableTrait.php.fixed | 13 ++++++++++++ .../Fixable/data/trait/same-file-trait.php | 20 +++++++++++++++++++ .../data/trait/same-file-trait.php.fixed | 20 +++++++++++++++++++ .../PHPStan/Fixable/data/trait/uses-trait.php | 17 ++++++++++++++++ 7 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 tests/PHPStan/Fixable/data/trait/FixableTrait.php create mode 100644 tests/PHPStan/Fixable/data/trait/FixableTrait.php.fixed create mode 100644 tests/PHPStan/Fixable/data/trait/same-file-trait.php create mode 100644 tests/PHPStan/Fixable/data/trait/same-file-trait.php.fixed create mode 100644 tests/PHPStan/Fixable/data/trait/uses-trait.php diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 5523d0b6b33..1f1ce10365b 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -31,6 +31,8 @@ use PHPStan\ShouldNotHappenException; use function array_map; use function array_merge; +use function array_unique; +use function array_values; use function count; use function implode; use function sprintf; @@ -234,17 +236,31 @@ static function (Error $error) use ($strictlyTypedSprintf): string { public function fix(string $file, string $expectedFile): void { - [$errors] = $this->gatherAnalyserErrorsWithDelayedErrors([$file]); + $this->fixOtherFile($file, $file, $expectedFile); + } + + /** + * Analyses $file and $fixedFile together and asserts the fixes of $fixedFile, + * like a trait file or a file the rule points to with RuleErrorBuilder::file(). + */ + public function fixOtherFile(string $file, string $fixedFile, string $expectedFile): void + { + $fixedFile = $this->getFileHelper()->normalizePath($fixedFile); + // a trait is analysed only when its file is analysed too + [$errors] = $this->gatherAnalyserErrorsWithDelayedErrors(array_values(array_unique([$this->getFileHelper()->normalizePath($file), $fixedFile]))); $diffs = []; foreach ($errors as $error) { if ($error->getFixedErrorDiff() === null) { continue; } + if ($this->getFileHelper()->normalizePath($error->getTraitFilePath() ?? $error->getFilePath()) !== $fixedFile) { + continue; + } $diffs[] = $error->getFixedErrorDiff(); } $patcher = self::getContainer()->getByType(Patcher::class); - $patchResult = $patcher->applyDiffs($file, $diffs); // @phpstan-ignore missingType.checkedException + $patchResult = $patcher->applyDiffs($fixedFile, $diffs); // @phpstan-ignore missingType.checkedException $this->assertSame(0, $patchResult['skippedCount'], 'Some fixes overlap and could not be applied together.'); $fixedFileContents = FileReader::read($expectedFile); diff --git a/tests/PHPStan/Fixable/FixIssetRuleTest.php b/tests/PHPStan/Fixable/FixIssetRuleTest.php index e6c360c35d2..0a5fb402942 100644 --- a/tests/PHPStan/Fixable/FixIssetRuleTest.php +++ b/tests/PHPStan/Fixable/FixIssetRuleTest.php @@ -21,4 +21,19 @@ public function testRule(): void $this->fix(__DIR__ . '/data/isset.php', __DIR__ . '/data/isset.php.fixed'); } + public function testFixInTraitInSameFile(): void + { + $this->fix(__DIR__ . '/data/trait/same-file-trait.php', __DIR__ . '/data/trait/same-file-trait.php.fixed'); + } + + public function testFixInTraitUsedByTwoClasses(): void + { + // each using class reports the error, both diffs make the same change + $this->fixOtherFile( + __DIR__ . '/data/trait/uses-trait.php', + __DIR__ . '/data/trait/FixableTrait.php', + __DIR__ . '/data/trait/FixableTrait.php.fixed', + ); + } + } diff --git a/tests/PHPStan/Fixable/data/trait/FixableTrait.php b/tests/PHPStan/Fixable/data/trait/FixableTrait.php new file mode 100644 index 00000000000..af9ea3479e9 --- /dev/null +++ b/tests/PHPStan/Fixable/data/trait/FixableTrait.php @@ -0,0 +1,13 @@ + Date: Mon, 2 Nov 2026 03:59:33 +0000 Subject: [PATCH 06/24] Fix nodes in the file set with RuleErrorBuilder::file() The fix was computed on the AST of the analysed file, so a node from the file the error points to was never found and the fix was silently dropped. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Analyser/RuleErrorTransformer.php | 12 ++- tests/PHPStan/Fixable/FixOtherFileRule.php | 73 +++++++++++++++++++ .../PHPStan/Fixable/FixOtherFileRuleTest.php | 28 +++++++ tests/PHPStan/Fixable/data/cross-file/a.php | 5 ++ tests/PHPStan/Fixable/data/cross-file/b.php | 13 ++++ .../Fixable/data/cross-file/b.php.fixed | 13 ++++ 6 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 tests/PHPStan/Fixable/FixOtherFileRule.php create mode 100644 tests/PHPStan/Fixable/FixOtherFileRuleTest.php create mode 100644 tests/PHPStan/Fixable/data/cross-file/a.php create mode 100644 tests/PHPStan/Fixable/data/cross-file/b.php create mode 100644 tests/PHPStan/Fixable/data/cross-file/b.php.fixed diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index 26399846209..b422b83b50f 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -102,6 +102,9 @@ public function transform( } } + // the file $fileNodes come from - the error can point to another one with RuleErrorBuilder::file() + $fileNodesFile = $traitFilePath ?? $filePath; + if ( $ruleError instanceof LineRuleError && $ruleError->getLine() !== -1 @@ -139,9 +142,10 @@ public function transform( throw new ShouldNotHappenException('Cannot fix virtual node'); } + $fixingFile = $traitFilePath ?? $filePath; $fixedErrorDiff = $this->fix( - $traitFilePath ?? $filePath, - $fileNodes, + $fixingFile, + $fixingFile === $fileNodesFile ? $fileNodes : [], $ruleError->getOriginalNode(), $ruleError->getNewNodeCallable(), ); @@ -164,8 +168,8 @@ public function transform( } /** - * Without $fileNodes (errors of CollectedDataNode rules and errors transformed inside collectors), - * the file is parsed with the cached analysis parser. The rule has to take the node it fixes + * Without $fileNodes (errors of CollectedDataNode rules, errors transformed inside collectors, + * and errors pointing to another file with RuleErrorBuilder::file()), the file is parsed with the cached analysis parser. The rule has to take the node it fixes * from the same parser so that ReplacingNodeVisitor finds it by identity. * * @param Node\Stmt[] $fileNodes diff --git a/tests/PHPStan/Fixable/FixOtherFileRule.php b/tests/PHPStan/Fixable/FixOtherFileRule.php new file mode 100644 index 00000000000..bb1f201bfd8 --- /dev/null +++ b/tests/PHPStan/Fixable/FixOtherFileRule.php @@ -0,0 +1,73 @@ + + */ +class FixOtherFileRule implements Rule +{ + + public function __construct(private Parser $parser) + { + } + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Name || $node->name->toLowerString() !== 'renamein') { + return []; + } + + $args = $node->getArgs(); + if (!$args[0]->value instanceof String_ || !$args[1]->value instanceof String_ || !$args[2]->value instanceof String_) { + return []; + } + + $file = dirname($scope->getFile()) . '/' . $args[0]->value->value; + $from = $args[1]->value->value; + $to = $args[2]->value->value; + if ($to === '') { + return []; + } + + $errors = []; + foreach ((new NodeFinder())->findInstanceOf($this->parser->parseFile($file), FuncCall::class) as $call) { + if (!$call->name instanceof Name || $call->name->toString() !== $from) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf('Renaming %s() to %s().', $from, $to)) + ->identifier('tests.renameInOtherFile') + ->file($file) + ->line($call->getStartLine()) + ->fixNode($call, static function (FuncCall $call) use ($to): FuncCall { + $call->name = new Name($to); + + return $call; + }) + ->build(); + } + + return $errors; + } + +} diff --git a/tests/PHPStan/Fixable/FixOtherFileRuleTest.php b/tests/PHPStan/Fixable/FixOtherFileRuleTest.php new file mode 100644 index 00000000000..367af144db6 --- /dev/null +++ b/tests/PHPStan/Fixable/FixOtherFileRuleTest.php @@ -0,0 +1,28 @@ + + */ +class FixOtherFileRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new FixOtherFileRule(self::getContainer()->getService('defaultAnalysisParser')); + } + + public function testFixInFileOfError(): void + { + $this->fixOtherFile( + __DIR__ . '/data/cross-file/a.php', + __DIR__ . '/data/cross-file/b.php', + __DIR__ . '/data/cross-file/b.php.fixed', + ); + } + +} diff --git a/tests/PHPStan/Fixable/data/cross-file/a.php b/tests/PHPStan/Fixable/data/cross-file/a.php new file mode 100644 index 00000000000..c5d25a5003c --- /dev/null +++ b/tests/PHPStan/Fixable/data/cross-file/a.php @@ -0,0 +1,5 @@ + Date: Mon, 2 Nov 2026 04:02:47 +0000 Subject: [PATCH 07/24] Add RuleErrorBuilder::removeNode() Fixes an error by removing a node that is in an array, like a statement, a class member, an argument, or an array item. A fixNode() callback can return NodeVisitor::REMOVE_NODE to the same effect. A node that is not in an array cannot be removed and the error is not fixable. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- bin/generate-rule-error-classes.php | 2 +- src/Analyser/RuleErrorTransformer.php | 3 +- src/Fixable/ReplacingNodeVisitor.php | 45 +++++++++++++-- src/Rules/FixableNodeRuleError.php | 3 +- src/Rules/RuleErrorBuilder.php | 22 +++++++- src/Rules/RuleErrors/RuleError129.php | 5 +- src/Rules/RuleErrors/RuleError131.php | 5 +- src/Rules/RuleErrors/RuleError133.php | 5 +- src/Rules/RuleErrors/RuleError135.php | 5 +- src/Rules/RuleErrors/RuleError137.php | 5 +- src/Rules/RuleErrors/RuleError139.php | 5 +- src/Rules/RuleErrors/RuleError141.php | 5 +- src/Rules/RuleErrors/RuleError143.php | 5 +- src/Rules/RuleErrors/RuleError145.php | 5 +- src/Rules/RuleErrors/RuleError147.php | 5 +- src/Rules/RuleErrors/RuleError149.php | 5 +- src/Rules/RuleErrors/RuleError151.php | 5 +- src/Rules/RuleErrors/RuleError153.php | 5 +- src/Rules/RuleErrors/RuleError155.php | 5 +- src/Rules/RuleErrors/RuleError157.php | 5 +- src/Rules/RuleErrors/RuleError159.php | 5 +- src/Rules/RuleErrors/RuleError161.php | 5 +- src/Rules/RuleErrors/RuleError163.php | 5 +- src/Rules/RuleErrors/RuleError165.php | 5 +- src/Rules/RuleErrors/RuleError167.php | 5 +- src/Rules/RuleErrors/RuleError169.php | 5 +- src/Rules/RuleErrors/RuleError171.php | 5 +- src/Rules/RuleErrors/RuleError173.php | 5 +- src/Rules/RuleErrors/RuleError175.php | 5 +- src/Rules/RuleErrors/RuleError177.php | 5 +- src/Rules/RuleErrors/RuleError179.php | 5 +- src/Rules/RuleErrors/RuleError181.php | 5 +- src/Rules/RuleErrors/RuleError183.php | 5 +- src/Rules/RuleErrors/RuleError185.php | 5 +- src/Rules/RuleErrors/RuleError187.php | 5 +- src/Rules/RuleErrors/RuleError189.php | 5 +- src/Rules/RuleErrors/RuleError191.php | 5 +- src/Rules/RuleErrors/RuleError193.php | 5 +- src/Rules/RuleErrors/RuleError195.php | 5 +- src/Rules/RuleErrors/RuleError197.php | 5 +- src/Rules/RuleErrors/RuleError199.php | 5 +- src/Rules/RuleErrors/RuleError201.php | 5 +- src/Rules/RuleErrors/RuleError203.php | 5 +- src/Rules/RuleErrors/RuleError205.php | 5 +- src/Rules/RuleErrors/RuleError207.php | 5 +- src/Rules/RuleErrors/RuleError209.php | 5 +- src/Rules/RuleErrors/RuleError211.php | 5 +- src/Rules/RuleErrors/RuleError213.php | 5 +- src/Rules/RuleErrors/RuleError215.php | 5 +- src/Rules/RuleErrors/RuleError217.php | 5 +- src/Rules/RuleErrors/RuleError219.php | 5 +- src/Rules/RuleErrors/RuleError221.php | 5 +- src/Rules/RuleErrors/RuleError223.php | 5 +- src/Rules/RuleErrors/RuleError225.php | 5 +- src/Rules/RuleErrors/RuleError227.php | 5 +- src/Rules/RuleErrors/RuleError229.php | 5 +- src/Rules/RuleErrors/RuleError231.php | 5 +- src/Rules/RuleErrors/RuleError233.php | 5 +- src/Rules/RuleErrors/RuleError235.php | 5 +- src/Rules/RuleErrors/RuleError237.php | 5 +- src/Rules/RuleErrors/RuleError239.php | 5 +- src/Rules/RuleErrors/RuleError241.php | 5 +- src/Rules/RuleErrors/RuleError243.php | 5 +- src/Rules/RuleErrors/RuleError245.php | 5 +- src/Rules/RuleErrors/RuleError247.php | 5 +- src/Rules/RuleErrors/RuleError249.php | 5 +- src/Rules/RuleErrors/RuleError251.php | 5 +- src/Rules/RuleErrors/RuleError253.php | 5 +- src/Rules/RuleErrors/RuleError255.php | 5 +- src/Rules/RuleErrors/RuleError385.php | 5 +- src/Rules/RuleErrors/RuleError387.php | 5 +- src/Rules/RuleErrors/RuleError389.php | 5 +- src/Rules/RuleErrors/RuleError391.php | 5 +- src/Rules/RuleErrors/RuleError393.php | 5 +- src/Rules/RuleErrors/RuleError395.php | 5 +- src/Rules/RuleErrors/RuleError397.php | 5 +- src/Rules/RuleErrors/RuleError399.php | 5 +- src/Rules/RuleErrors/RuleError401.php | 5 +- src/Rules/RuleErrors/RuleError403.php | 5 +- src/Rules/RuleErrors/RuleError405.php | 5 +- src/Rules/RuleErrors/RuleError407.php | 5 +- src/Rules/RuleErrors/RuleError409.php | 5 +- src/Rules/RuleErrors/RuleError411.php | 5 +- src/Rules/RuleErrors/RuleError413.php | 5 +- src/Rules/RuleErrors/RuleError415.php | 5 +- src/Rules/RuleErrors/RuleError417.php | 5 +- src/Rules/RuleErrors/RuleError419.php | 5 +- src/Rules/RuleErrors/RuleError421.php | 5 +- src/Rules/RuleErrors/RuleError423.php | 5 +- src/Rules/RuleErrors/RuleError425.php | 5 +- src/Rules/RuleErrors/RuleError427.php | 5 +- src/Rules/RuleErrors/RuleError429.php | 5 +- src/Rules/RuleErrors/RuleError431.php | 5 +- src/Rules/RuleErrors/RuleError433.php | 5 +- src/Rules/RuleErrors/RuleError435.php | 5 +- src/Rules/RuleErrors/RuleError437.php | 5 +- src/Rules/RuleErrors/RuleError439.php | 5 +- src/Rules/RuleErrors/RuleError441.php | 5 +- src/Rules/RuleErrors/RuleError443.php | 5 +- src/Rules/RuleErrors/RuleError445.php | 5 +- src/Rules/RuleErrors/RuleError447.php | 5 +- src/Rules/RuleErrors/RuleError449.php | 5 +- src/Rules/RuleErrors/RuleError451.php | 5 +- src/Rules/RuleErrors/RuleError453.php | 5 +- src/Rules/RuleErrors/RuleError455.php | 5 +- src/Rules/RuleErrors/RuleError457.php | 5 +- src/Rules/RuleErrors/RuleError459.php | 5 +- src/Rules/RuleErrors/RuleError461.php | 5 +- src/Rules/RuleErrors/RuleError463.php | 5 +- src/Rules/RuleErrors/RuleError465.php | 5 +- src/Rules/RuleErrors/RuleError467.php | 5 +- src/Rules/RuleErrors/RuleError469.php | 5 +- src/Rules/RuleErrors/RuleError471.php | 5 +- src/Rules/RuleErrors/RuleError473.php | 5 +- src/Rules/RuleErrors/RuleError475.php | 5 +- src/Rules/RuleErrors/RuleError477.php | 5 +- src/Rules/RuleErrors/RuleError479.php | 5 +- src/Rules/RuleErrors/RuleError481.php | 5 +- src/Rules/RuleErrors/RuleError483.php | 5 +- src/Rules/RuleErrors/RuleError485.php | 5 +- src/Rules/RuleErrors/RuleError487.php | 5 +- src/Rules/RuleErrors/RuleError489.php | 5 +- src/Rules/RuleErrors/RuleError491.php | 5 +- src/Rules/RuleErrors/RuleError493.php | 5 +- src/Rules/RuleErrors/RuleError495.php | 5 +- src/Rules/RuleErrors/RuleError497.php | 5 +- src/Rules/RuleErrors/RuleError499.php | 5 +- src/Rules/RuleErrors/RuleError501.php | 5 +- src/Rules/RuleErrors/RuleError503.php | 5 +- src/Rules/RuleErrors/RuleError505.php | 5 +- src/Rules/RuleErrors/RuleError507.php | 5 +- src/Rules/RuleErrors/RuleError509.php | 5 +- src/Rules/RuleErrors/RuleError511.php | 5 +- tests/PHPStan/Fixable/RemoveNodeRule.php | 55 +++++++++++++++++++ tests/PHPStan/Fixable/RemoveNodeRuleTest.php | 49 +++++++++++++++++ tests/PHPStan/Fixable/data/remove-node.php | 30 ++++++++++ .../Fixable/data/remove-node.php.fixed | 22 ++++++++ 137 files changed, 606 insertions(+), 265 deletions(-) create mode 100644 tests/PHPStan/Fixable/RemoveNodeRule.php create mode 100644 tests/PHPStan/Fixable/RemoveNodeRuleTest.php create mode 100644 tests/PHPStan/Fixable/data/remove-node.php create mode 100644 tests/PHPStan/Fixable/data/remove-node.php.fixed diff --git a/bin/generate-rule-error-classes.php b/bin/generate-rule-error-classes.php index 6b8284669e5..ca9cdcbc4c4 100755 --- a/bin/generate-rule-error-classes.php +++ b/bin/generate-rule-error-classes.php @@ -47,7 +47,7 @@ final class RuleError%s implements %s $typeCombination, implode(', ', $interfaces), implode("\n\n\t", array_map(static fn (array $property): string => sprintf('%spublic %s $%s;', $property[2] !== $property[1] ? sprintf("/** @var %s */\n\t", $property[2]) : '', $property[1], $property[0]), $properties)), - implode("\n\n\t", array_map(static fn (array $property): string => sprintf("%spublic function get%s()%s\n\t{\n\t\treturn \$this->%s;\n\t}", $property[2] !== $property[1] ? sprintf("/**\n\t * @return %s\n\t */\n\t", $property[2]) : '', ucfirst($property[0]), $property[1] === null ? '' : sprintf(': %s', $property[1]), $property[0]), $properties)), + implode("\n\n\t", array_map(static fn (array $property): string => sprintf("%spublic function get%s()%s\n\t{\n\t\treturn \$this->%s;\n\t}", $property[2] !== $property[1] ? sprintf("/**\n\t * @return %s\n\t */\n\t", $property[2]) : '', ucfirst($property[0]), $property[1] === null ? (str_starts_with($property[2], 'callable') ? ': callable' : '') : sprintf(': %s', $property[1]), $property[0]), $properties)), ); file_put_contents(__DIR__ . '/../src/Rules/RuleErrors/RuleError' . $typeCombination . '.php', $phpClass); diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index b422b83b50f..a5ec6a1f128 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Stmt; use PhpParser\NodeTraverser; +use PhpParser\NodeVisitor; use PhpParser\NodeVisitor\CloningVisitor; use PhpParser\Parser; use PhpParser\Token; @@ -173,7 +174,7 @@ public function transform( * from the same parser so that ReplacingNodeVisitor finds it by identity. * * @param Node\Stmt[] $fileNodes - * @param callable(Node): Node $newNodeCallable + * @param callable(Node): (Node|NodeVisitor::REMOVE_NODE) $newNodeCallable */ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, callable $newNodeCallable): ?FixedErrorDiff { diff --git a/src/Fixable/ReplacingNodeVisitor.php b/src/Fixable/ReplacingNodeVisitor.php index 1a7cd8ada2d..b322a00823b 100644 --- a/src/Fixable/ReplacingNodeVisitor.php +++ b/src/Fixable/ReplacingNodeVisitor.php @@ -4,29 +4,56 @@ use Override; use PhpParser\Node; +use PhpParser\NodeVisitor; use PhpParser\NodeVisitorAbstract; use PHPStan\Node\VirtualNode; use PHPStan\ShouldNotHappenException; +use function in_array; +use function is_array; final class ReplacingNodeVisitor extends NodeVisitorAbstract { private bool $found = false; + private bool $originalNodeInArray = false; + /** - * @param callable(Node): Node $newNodeCallable + * @param callable(Node): (Node|NodeVisitor::REMOVE_NODE) $newNodeCallable */ public function __construct(private Node $originalNode, private $newNodeCallable) { } + /** + * CloningVisitor has just cloned $node, its subnodes are still the original nodes. + * Only a node in an array can be removed. + */ + #[Override] + public function enterNode(Node $node): ?Node + { + if ($this->found || $this->originalNodeInArray) { + return null; + } + + foreach ($node->getSubNodeNames() as $subNodeName) { + $subNode = $node->$subNodeName; + if (is_array($subNode) && in_array($this->originalNode, $subNode, true)) { + $this->originalNodeInArray = true; + break; + } + } + + return null; + } + /** * The replacement happens in leaveNode() so that the callable receives a node * whose children have already been cloned by CloningVisitor. That makes it * possible to run both visitors in a single traversal. */ #[Override] - public function leaveNode(Node $node): ?Node + public function leaveNode(Node $node): Node|int|null { if ($this->found) { return null; @@ -37,14 +64,24 @@ public function leaveNode(Node $node): ?Node return null; } - $this->found = true; - $callable = $this->newNodeCallable; $newNode = $callable($node); + if ($newNode === NodeVisitor::REMOVE_NODE) { + if (!$this->originalNodeInArray) { + return null; + } + + $this->found = true; + + return NodeVisitor::REMOVE_NODE; + } + if ($newNode instanceof VirtualNode) { throw new ShouldNotHappenException('Cannot print VirtualNode.'); } + $this->found = true; + return $newNode; } diff --git a/src/Rules/FixableNodeRuleError.php b/src/Rules/FixableNodeRuleError.php index bdb5c973f10..c67c7e07d36 100644 --- a/src/Rules/FixableNodeRuleError.php +++ b/src/Rules/FixableNodeRuleError.php @@ -3,13 +3,14 @@ namespace PHPStan\Rules; use PhpParser\Node; +use PhpParser\NodeVisitor; interface FixableNodeRuleError extends RuleError { public function getOriginalNode(): Node; - /** @return callable(Node): Node */ + /** @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable; } diff --git a/src/Rules/RuleErrorBuilder.php b/src/Rules/RuleErrorBuilder.php index 1e60d7129c1..64e7fd139d8 100644 --- a/src/Rules/RuleErrorBuilder.php +++ b/src/Rules/RuleErrorBuilder.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Analyser\Error; use PHPStan\ShouldNotHappenException; use function array_map; @@ -129,7 +130,7 @@ public static function getRuleErrorTypes(): array [ 'newNodeCallable', null, - 'callable(\PhpParser\Node): \PhpParser\Node', + 'callable(\PhpParser\Node): (\PhpParser\Node|\PhpParser\NodeVisitor::REMOVE_NODE)', ], ], ], @@ -322,7 +323,7 @@ public function nonIgnorable(): self * @internal Experimental * @template TNode of Node * @param TNode $node - * @param callable(TNode): Node $cb + * @param callable(TNode): (Node|NodeVisitor::REMOVE_NODE) $cb returning NodeVisitor::REMOVE_NODE works like removeNode() * @phpstan-this-out self * @return self */ @@ -335,6 +336,23 @@ public function fixNode(Node $node, callable $cb): self return $this; } + /** + * Fixes the error by removing the node. Only a node in an array, like a statement, + * an argument, or an array item, can be removed. Otherwise the error is not fixable. + * + * @internal Experimental + * @phpstan-this-out self + * @return self + */ + public function removeNode(Node $node): self + { + $this->properties['originalNode'] = $node; + $this->properties['newNodeCallable'] = static fn (): int => NodeVisitor::REMOVE_NODE; + $this->type |= self::TYPE_FIXABLE_NODE; + + return $this; + } + /** * @return T */ diff --git a/src/Rules/RuleErrors/RuleError129.php b/src/Rules/RuleErrors/RuleError129.php index bd003c4f5a2..65e6e7e707d 100644 --- a/src/Rules/RuleErrors/RuleError129.php +++ b/src/Rules/RuleErrors/RuleError129.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\RuleError; @@ -16,7 +17,7 @@ final class RuleError129 implements RuleError, FixableNodeRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -30,7 +31,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError131.php b/src/Rules/RuleErrors/RuleError131.php index ba607b957e3..9e05ac02e3b 100644 --- a/src/Rules/RuleErrors/RuleError131.php +++ b/src/Rules/RuleErrors/RuleError131.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\RuleError; @@ -19,7 +20,7 @@ final class RuleError131 implements RuleError, LineRuleError, FixableNodeRuleErr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -38,7 +39,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError133.php b/src/Rules/RuleErrors/RuleError133.php index 481c6f0bcf5..f13cddd71aa 100644 --- a/src/Rules/RuleErrors/RuleError133.php +++ b/src/Rules/RuleErrors/RuleError133.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\RuleError; @@ -21,7 +22,7 @@ final class RuleError133 implements RuleError, FileRuleError, FixableNodeRuleErr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -45,7 +46,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError135.php b/src/Rules/RuleErrors/RuleError135.php index 11f52de24ae..faf9f12aaf6 100644 --- a/src/Rules/RuleErrors/RuleError135.php +++ b/src/Rules/RuleErrors/RuleError135.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -24,7 +25,7 @@ final class RuleError135 implements RuleError, LineRuleError, FileRuleError, Fix public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -53,7 +54,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError137.php b/src/Rules/RuleErrors/RuleError137.php index 47925389f35..7febf76e634 100644 --- a/src/Rules/RuleErrors/RuleError137.php +++ b/src/Rules/RuleErrors/RuleError137.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -19,7 +20,7 @@ final class RuleError137 implements RuleError, TipRuleError, FixableNodeRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -38,7 +39,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError139.php b/src/Rules/RuleErrors/RuleError139.php index d40a1721d6f..0546fb6b4ca 100644 --- a/src/Rules/RuleErrors/RuleError139.php +++ b/src/Rules/RuleErrors/RuleError139.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\RuleError; @@ -22,7 +23,7 @@ final class RuleError139 implements RuleError, LineRuleError, TipRuleError, Fixa public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -46,7 +47,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError141.php b/src/Rules/RuleErrors/RuleError141.php index 5713a025ba4..c0cb0c6b63e 100644 --- a/src/Rules/RuleErrors/RuleError141.php +++ b/src/Rules/RuleErrors/RuleError141.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\RuleError; @@ -24,7 +25,7 @@ final class RuleError141 implements RuleError, FileRuleError, TipRuleError, Fixa public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -53,7 +54,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError143.php b/src/Rules/RuleErrors/RuleError143.php index 1a08b2cf53f..77ac55405e8 100644 --- a/src/Rules/RuleErrors/RuleError143.php +++ b/src/Rules/RuleErrors/RuleError143.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -27,7 +28,7 @@ final class RuleError143 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -61,7 +62,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError145.php b/src/Rules/RuleErrors/RuleError145.php index f23ae4b9e7c..87383183aa4 100644 --- a/src/Rules/RuleErrors/RuleError145.php +++ b/src/Rules/RuleErrors/RuleError145.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\RuleError; @@ -19,7 +20,7 @@ final class RuleError145 implements RuleError, IdentifierRuleError, FixableNodeR public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -38,7 +39,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError147.php b/src/Rules/RuleErrors/RuleError147.php index 47a80d87d8d..e756d3f2e12 100644 --- a/src/Rules/RuleErrors/RuleError147.php +++ b/src/Rules/RuleErrors/RuleError147.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -22,7 +23,7 @@ final class RuleError147 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -46,7 +47,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError149.php b/src/Rules/RuleErrors/RuleError149.php index 802779e5600..d5c0042a8a4 100644 --- a/src/Rules/RuleErrors/RuleError149.php +++ b/src/Rules/RuleErrors/RuleError149.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -24,7 +25,7 @@ final class RuleError149 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -53,7 +54,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError151.php b/src/Rules/RuleErrors/RuleError151.php index 284a5700c51..c316f1b243c 100644 --- a/src/Rules/RuleErrors/RuleError151.php +++ b/src/Rules/RuleErrors/RuleError151.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -27,7 +28,7 @@ final class RuleError151 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -61,7 +62,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError153.php b/src/Rules/RuleErrors/RuleError153.php index 24052dc8c9c..d56a553fb21 100644 --- a/src/Rules/RuleErrors/RuleError153.php +++ b/src/Rules/RuleErrors/RuleError153.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\RuleError; @@ -22,7 +23,7 @@ final class RuleError153 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -46,7 +47,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError155.php b/src/Rules/RuleErrors/RuleError155.php index 038f19d0797..abfef5873a1 100644 --- a/src/Rules/RuleErrors/RuleError155.php +++ b/src/Rules/RuleErrors/RuleError155.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -25,7 +26,7 @@ final class RuleError155 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -54,7 +55,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError157.php b/src/Rules/RuleErrors/RuleError157.php index a2a71b9acae..7d64e9a3a0c 100644 --- a/src/Rules/RuleErrors/RuleError157.php +++ b/src/Rules/RuleErrors/RuleError157.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -27,7 +28,7 @@ final class RuleError157 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -61,7 +62,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError159.php b/src/Rules/RuleErrors/RuleError159.php index 638054207c6..069fdae4b6c 100644 --- a/src/Rules/RuleErrors/RuleError159.php +++ b/src/Rules/RuleErrors/RuleError159.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -30,7 +31,7 @@ final class RuleError159 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -69,7 +70,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError161.php b/src/Rules/RuleErrors/RuleError161.php index 008cfef2de8..c2323c85a8c 100644 --- a/src/Rules/RuleErrors/RuleError161.php +++ b/src/Rules/RuleErrors/RuleError161.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; use PHPStan\Rules\RuleError; @@ -20,7 +21,7 @@ final class RuleError161 implements RuleError, MetadataRuleError, FixableNodeRul public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -42,7 +43,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError163.php b/src/Rules/RuleErrors/RuleError163.php index 840450cce04..95700eacfbf 100644 --- a/src/Rules/RuleErrors/RuleError163.php +++ b/src/Rules/RuleErrors/RuleError163.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; @@ -23,7 +24,7 @@ final class RuleError163 implements RuleError, LineRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -50,7 +51,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError165.php b/src/Rules/RuleErrors/RuleError165.php index 79eb32732d1..175bc53ea71 100644 --- a/src/Rules/RuleErrors/RuleError165.php +++ b/src/Rules/RuleErrors/RuleError165.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -25,7 +26,7 @@ final class RuleError165 implements RuleError, FileRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -57,7 +58,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError167.php b/src/Rules/RuleErrors/RuleError167.php index ccc7d2f3e83..5df04c815e7 100644 --- a/src/Rules/RuleErrors/RuleError167.php +++ b/src/Rules/RuleErrors/RuleError167.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -28,7 +29,7 @@ final class RuleError167 implements RuleError, LineRuleError, FileRuleError, Met public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -65,7 +66,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError169.php b/src/Rules/RuleErrors/RuleError169.php index 7f106fec80b..7f1ee411552 100644 --- a/src/Rules/RuleErrors/RuleError169.php +++ b/src/Rules/RuleErrors/RuleError169.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; use PHPStan\Rules\RuleError; @@ -23,7 +24,7 @@ final class RuleError169 implements RuleError, TipRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -50,7 +51,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError171.php b/src/Rules/RuleErrors/RuleError171.php index bd01419ffbb..08c6509b6e1 100644 --- a/src/Rules/RuleErrors/RuleError171.php +++ b/src/Rules/RuleErrors/RuleError171.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; @@ -26,7 +27,7 @@ final class RuleError171 implements RuleError, LineRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError173.php b/src/Rules/RuleErrors/RuleError173.php index 17e1855459f..6b832dd7324 100644 --- a/src/Rules/RuleErrors/RuleError173.php +++ b/src/Rules/RuleErrors/RuleError173.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -28,7 +29,7 @@ final class RuleError173 implements RuleError, FileRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -65,7 +66,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError175.php b/src/Rules/RuleErrors/RuleError175.php index ed0f4965f7b..3c8a0c1f122 100644 --- a/src/Rules/RuleErrors/RuleError175.php +++ b/src/Rules/RuleErrors/RuleError175.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -31,7 +32,7 @@ final class RuleError175 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -73,7 +74,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError177.php b/src/Rules/RuleErrors/RuleError177.php index 2acb39c8657..6d2479bb0a6 100644 --- a/src/Rules/RuleErrors/RuleError177.php +++ b/src/Rules/RuleErrors/RuleError177.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; @@ -23,7 +24,7 @@ final class RuleError177 implements RuleError, IdentifierRuleError, MetadataRule public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -50,7 +51,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError179.php b/src/Rules/RuleErrors/RuleError179.php index 128b9187435..4c55fd3d97b 100644 --- a/src/Rules/RuleErrors/RuleError179.php +++ b/src/Rules/RuleErrors/RuleError179.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -26,7 +27,7 @@ final class RuleError179 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError181.php b/src/Rules/RuleErrors/RuleError181.php index 601aaf38c8e..0aba9d9a174 100644 --- a/src/Rules/RuleErrors/RuleError181.php +++ b/src/Rules/RuleErrors/RuleError181.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -28,7 +29,7 @@ final class RuleError181 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -65,7 +66,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError183.php b/src/Rules/RuleErrors/RuleError183.php index 61f5965218d..436a4fb40c8 100644 --- a/src/Rules/RuleErrors/RuleError183.php +++ b/src/Rules/RuleErrors/RuleError183.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -31,7 +32,7 @@ final class RuleError183 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -73,7 +74,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError185.php b/src/Rules/RuleErrors/RuleError185.php index 14dd4f7a9d0..3871100e7bd 100644 --- a/src/Rules/RuleErrors/RuleError185.php +++ b/src/Rules/RuleErrors/RuleError185.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; @@ -26,7 +27,7 @@ final class RuleError185 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError187.php b/src/Rules/RuleErrors/RuleError187.php index a76455ad719..fa8c1cb282b 100644 --- a/src/Rules/RuleErrors/RuleError187.php +++ b/src/Rules/RuleErrors/RuleError187.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -29,7 +30,7 @@ final class RuleError187 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -66,7 +67,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError189.php b/src/Rules/RuleErrors/RuleError189.php index d6b044c4265..d102c3df536 100644 --- a/src/Rules/RuleErrors/RuleError189.php +++ b/src/Rules/RuleErrors/RuleError189.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -31,7 +32,7 @@ final class RuleError189 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -73,7 +74,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError191.php b/src/Rules/RuleErrors/RuleError191.php index 55b9f266627..4d4f77cfdd2 100644 --- a/src/Rules/RuleErrors/RuleError191.php +++ b/src/Rules/RuleErrors/RuleError191.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -34,7 +35,7 @@ final class RuleError191 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -81,7 +82,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError193.php b/src/Rules/RuleErrors/RuleError193.php index 452a3d7195b..c4405ed8966 100644 --- a/src/Rules/RuleErrors/RuleError193.php +++ b/src/Rules/RuleErrors/RuleError193.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -17,7 +18,7 @@ final class RuleError193 implements RuleError, NonIgnorableRuleError, FixableNod public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -31,7 +32,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError195.php b/src/Rules/RuleErrors/RuleError195.php index 0c662f1da3d..679b6cea533 100644 --- a/src/Rules/RuleErrors/RuleError195.php +++ b/src/Rules/RuleErrors/RuleError195.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -20,7 +21,7 @@ final class RuleError195 implements RuleError, LineRuleError, NonIgnorableRuleEr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -39,7 +40,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError197.php b/src/Rules/RuleErrors/RuleError197.php index e2b5af378ca..0e82d481596 100644 --- a/src/Rules/RuleErrors/RuleError197.php +++ b/src/Rules/RuleErrors/RuleError197.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -22,7 +23,7 @@ final class RuleError197 implements RuleError, FileRuleError, NonIgnorableRuleEr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -46,7 +47,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError199.php b/src/Rules/RuleErrors/RuleError199.php index c9ed6c09016..f052cc48f9e 100644 --- a/src/Rules/RuleErrors/RuleError199.php +++ b/src/Rules/RuleErrors/RuleError199.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -25,7 +26,7 @@ final class RuleError199 implements RuleError, LineRuleError, FileRuleError, Non public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -54,7 +55,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError201.php b/src/Rules/RuleErrors/RuleError201.php index 2ecf6acaadd..d184fd468c4 100644 --- a/src/Rules/RuleErrors/RuleError201.php +++ b/src/Rules/RuleErrors/RuleError201.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -20,7 +21,7 @@ final class RuleError201 implements RuleError, TipRuleError, NonIgnorableRuleErr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -39,7 +40,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError203.php b/src/Rules/RuleErrors/RuleError203.php index a04fc867b2c..ad5c521f8ac 100644 --- a/src/Rules/RuleErrors/RuleError203.php +++ b/src/Rules/RuleErrors/RuleError203.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -23,7 +24,7 @@ final class RuleError203 implements RuleError, LineRuleError, TipRuleError, NonI public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -47,7 +48,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError205.php b/src/Rules/RuleErrors/RuleError205.php index 697c9eb673d..57c7380ec0e 100644 --- a/src/Rules/RuleErrors/RuleError205.php +++ b/src/Rules/RuleErrors/RuleError205.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -25,7 +26,7 @@ final class RuleError205 implements RuleError, FileRuleError, TipRuleError, NonI public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -54,7 +55,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError207.php b/src/Rules/RuleErrors/RuleError207.php index 8ee9144bc41..83b1bb52274 100644 --- a/src/Rules/RuleErrors/RuleError207.php +++ b/src/Rules/RuleErrors/RuleError207.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -28,7 +29,7 @@ final class RuleError207 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -62,7 +63,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError209.php b/src/Rules/RuleErrors/RuleError209.php index e007d8ed6c8..bb04d668cc1 100644 --- a/src/Rules/RuleErrors/RuleError209.php +++ b/src/Rules/RuleErrors/RuleError209.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -20,7 +21,7 @@ final class RuleError209 implements RuleError, IdentifierRuleError, NonIgnorable public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -39,7 +40,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError211.php b/src/Rules/RuleErrors/RuleError211.php index 6e56086b320..3322302f802 100644 --- a/src/Rules/RuleErrors/RuleError211.php +++ b/src/Rules/RuleErrors/RuleError211.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -23,7 +24,7 @@ final class RuleError211 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -47,7 +48,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError213.php b/src/Rules/RuleErrors/RuleError213.php index a9e6203b319..7d34fa66862 100644 --- a/src/Rules/RuleErrors/RuleError213.php +++ b/src/Rules/RuleErrors/RuleError213.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -25,7 +26,7 @@ final class RuleError213 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -54,7 +55,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError215.php b/src/Rules/RuleErrors/RuleError215.php index 01c82029576..cf9dd95da35 100644 --- a/src/Rules/RuleErrors/RuleError215.php +++ b/src/Rules/RuleErrors/RuleError215.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -28,7 +29,7 @@ final class RuleError215 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -62,7 +63,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError217.php b/src/Rules/RuleErrors/RuleError217.php index e78f445f2ba..800301752c7 100644 --- a/src/Rules/RuleErrors/RuleError217.php +++ b/src/Rules/RuleErrors/RuleError217.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -23,7 +24,7 @@ final class RuleError217 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -47,7 +48,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError219.php b/src/Rules/RuleErrors/RuleError219.php index 2bdc632dc07..9a843f5c8b5 100644 --- a/src/Rules/RuleErrors/RuleError219.php +++ b/src/Rules/RuleErrors/RuleError219.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -26,7 +27,7 @@ final class RuleError219 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -55,7 +56,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError221.php b/src/Rules/RuleErrors/RuleError221.php index d43a6004fa6..29cb6ad61d1 100644 --- a/src/Rules/RuleErrors/RuleError221.php +++ b/src/Rules/RuleErrors/RuleError221.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -28,7 +29,7 @@ final class RuleError221 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -62,7 +63,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError223.php b/src/Rules/RuleErrors/RuleError223.php index b3287c9a056..3fd068cdb67 100644 --- a/src/Rules/RuleErrors/RuleError223.php +++ b/src/Rules/RuleErrors/RuleError223.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -31,7 +32,7 @@ final class RuleError223 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -70,7 +71,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError225.php b/src/Rules/RuleErrors/RuleError225.php index 06ef862f283..14cf2f79fc7 100644 --- a/src/Rules/RuleErrors/RuleError225.php +++ b/src/Rules/RuleErrors/RuleError225.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -21,7 +22,7 @@ final class RuleError225 implements RuleError, MetadataRuleError, NonIgnorableRu public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -43,7 +44,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError227.php b/src/Rules/RuleErrors/RuleError227.php index 633cee8a5c4..5036c9b1e08 100644 --- a/src/Rules/RuleErrors/RuleError227.php +++ b/src/Rules/RuleErrors/RuleError227.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; @@ -24,7 +25,7 @@ final class RuleError227 implements RuleError, LineRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -51,7 +52,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError229.php b/src/Rules/RuleErrors/RuleError229.php index 42c17069737..05c124f8a7b 100644 --- a/src/Rules/RuleErrors/RuleError229.php +++ b/src/Rules/RuleErrors/RuleError229.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -26,7 +27,7 @@ final class RuleError229 implements RuleError, FileRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError231.php b/src/Rules/RuleErrors/RuleError231.php index bbbdb5a38f6..97e7e150125 100644 --- a/src/Rules/RuleErrors/RuleError231.php +++ b/src/Rules/RuleErrors/RuleError231.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -29,7 +30,7 @@ final class RuleError231 implements RuleError, LineRuleError, FileRuleError, Met public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -66,7 +67,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError233.php b/src/Rules/RuleErrors/RuleError233.php index b80cc0c36de..e6c167e4fdd 100644 --- a/src/Rules/RuleErrors/RuleError233.php +++ b/src/Rules/RuleErrors/RuleError233.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -24,7 +25,7 @@ final class RuleError233 implements RuleError, TipRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -51,7 +52,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError235.php b/src/Rules/RuleErrors/RuleError235.php index aaf1c80deeb..d048a5c812b 100644 --- a/src/Rules/RuleErrors/RuleError235.php +++ b/src/Rules/RuleErrors/RuleError235.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; @@ -27,7 +28,7 @@ final class RuleError235 implements RuleError, LineRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -59,7 +60,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError237.php b/src/Rules/RuleErrors/RuleError237.php index 1d4abc43324..4a35b871fa9 100644 --- a/src/Rules/RuleErrors/RuleError237.php +++ b/src/Rules/RuleErrors/RuleError237.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -29,7 +30,7 @@ final class RuleError237 implements RuleError, FileRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -66,7 +67,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError239.php b/src/Rules/RuleErrors/RuleError239.php index 5ee0033dc21..a47b331e446 100644 --- a/src/Rules/RuleErrors/RuleError239.php +++ b/src/Rules/RuleErrors/RuleError239.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -32,7 +33,7 @@ final class RuleError239 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -74,7 +75,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError241.php b/src/Rules/RuleErrors/RuleError241.php index 65d853915a1..41f04fcd5db 100644 --- a/src/Rules/RuleErrors/RuleError241.php +++ b/src/Rules/RuleErrors/RuleError241.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; @@ -24,7 +25,7 @@ final class RuleError241 implements RuleError, IdentifierRuleError, MetadataRule public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -51,7 +52,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError243.php b/src/Rules/RuleErrors/RuleError243.php index e5762ee32b3..a807969d748 100644 --- a/src/Rules/RuleErrors/RuleError243.php +++ b/src/Rules/RuleErrors/RuleError243.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -27,7 +28,7 @@ final class RuleError243 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -59,7 +60,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError245.php b/src/Rules/RuleErrors/RuleError245.php index 369e7cbee33..fbdd133d94d 100644 --- a/src/Rules/RuleErrors/RuleError245.php +++ b/src/Rules/RuleErrors/RuleError245.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -29,7 +30,7 @@ final class RuleError245 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -66,7 +67,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError247.php b/src/Rules/RuleErrors/RuleError247.php index 0a482fa833b..3cff5415b6c 100644 --- a/src/Rules/RuleErrors/RuleError247.php +++ b/src/Rules/RuleErrors/RuleError247.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -32,7 +33,7 @@ final class RuleError247 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -74,7 +75,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError249.php b/src/Rules/RuleErrors/RuleError249.php index ed86576c33f..a27187076e5 100644 --- a/src/Rules/RuleErrors/RuleError249.php +++ b/src/Rules/RuleErrors/RuleError249.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; @@ -27,7 +28,7 @@ final class RuleError249 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -59,7 +60,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError251.php b/src/Rules/RuleErrors/RuleError251.php index b77d8060f82..cb503180209 100644 --- a/src/Rules/RuleErrors/RuleError251.php +++ b/src/Rules/RuleErrors/RuleError251.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; @@ -30,7 +31,7 @@ final class RuleError251 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -67,7 +68,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError253.php b/src/Rules/RuleErrors/RuleError253.php index 17fad64bc19..fc09ead52af 100644 --- a/src/Rules/RuleErrors/RuleError253.php +++ b/src/Rules/RuleErrors/RuleError253.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -32,7 +33,7 @@ final class RuleError253 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -74,7 +75,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError255.php b/src/Rules/RuleErrors/RuleError255.php index 61d6fbd5055..d1f577ec92a 100644 --- a/src/Rules/RuleErrors/RuleError255.php +++ b/src/Rules/RuleErrors/RuleError255.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -35,7 +36,7 @@ final class RuleError255 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; public function getMessage(): string @@ -82,7 +83,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError385.php b/src/Rules/RuleErrors/RuleError385.php index 8e5885de9dc..8936e193062 100644 --- a/src/Rules/RuleErrors/RuleError385.php +++ b/src/Rules/RuleErrors/RuleError385.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\RuleError; @@ -17,7 +18,7 @@ final class RuleError385 implements RuleError, FixableNodeRuleError, FileDepende public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -34,7 +35,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError387.php b/src/Rules/RuleErrors/RuleError387.php index f86720e5f7f..7a14109a605 100644 --- a/src/Rules/RuleErrors/RuleError387.php +++ b/src/Rules/RuleErrors/RuleError387.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -20,7 +21,7 @@ final class RuleError387 implements RuleError, LineRuleError, FixableNodeRuleErr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -42,7 +43,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError389.php b/src/Rules/RuleErrors/RuleError389.php index 34208dc7f69..92971406a69 100644 --- a/src/Rules/RuleErrors/RuleError389.php +++ b/src/Rules/RuleErrors/RuleError389.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -22,7 +23,7 @@ final class RuleError389 implements RuleError, FileRuleError, FixableNodeRuleErr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -49,7 +50,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError391.php b/src/Rules/RuleErrors/RuleError391.php index 987c953124b..c365458e8b8 100644 --- a/src/Rules/RuleErrors/RuleError391.php +++ b/src/Rules/RuleErrors/RuleError391.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -25,7 +26,7 @@ final class RuleError391 implements RuleError, LineRuleError, FileRuleError, Fix public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -57,7 +58,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError393.php b/src/Rules/RuleErrors/RuleError393.php index 203005cb45c..ea075351496 100644 --- a/src/Rules/RuleErrors/RuleError393.php +++ b/src/Rules/RuleErrors/RuleError393.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\RuleError; @@ -20,7 +21,7 @@ final class RuleError393 implements RuleError, TipRuleError, FixableNodeRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -42,7 +43,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError395.php b/src/Rules/RuleErrors/RuleError395.php index 08db496f89e..e58aa3a6df6 100644 --- a/src/Rules/RuleErrors/RuleError395.php +++ b/src/Rules/RuleErrors/RuleError395.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -23,7 +24,7 @@ final class RuleError395 implements RuleError, LineRuleError, TipRuleError, Fixa public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -50,7 +51,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError397.php b/src/Rules/RuleErrors/RuleError397.php index 8753b690c93..8e21ad0d090 100644 --- a/src/Rules/RuleErrors/RuleError397.php +++ b/src/Rules/RuleErrors/RuleError397.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -25,7 +26,7 @@ final class RuleError397 implements RuleError, FileRuleError, TipRuleError, Fixa public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -57,7 +58,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError399.php b/src/Rules/RuleErrors/RuleError399.php index 5422e84ee62..9042ba9bc2d 100644 --- a/src/Rules/RuleErrors/RuleError399.php +++ b/src/Rules/RuleErrors/RuleError399.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -28,7 +29,7 @@ final class RuleError399 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -65,7 +66,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError401.php b/src/Rules/RuleErrors/RuleError401.php index 7895154f147..c3c0ac00c70 100644 --- a/src/Rules/RuleErrors/RuleError401.php +++ b/src/Rules/RuleErrors/RuleError401.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -20,7 +21,7 @@ final class RuleError401 implements RuleError, IdentifierRuleError, FixableNodeR public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -42,7 +43,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError403.php b/src/Rules/RuleErrors/RuleError403.php index c5cb7e881fb..6e85c90fa5c 100644 --- a/src/Rules/RuleErrors/RuleError403.php +++ b/src/Rules/RuleErrors/RuleError403.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -23,7 +24,7 @@ final class RuleError403 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -50,7 +51,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError405.php b/src/Rules/RuleErrors/RuleError405.php index 69a3896c029..b870e12b6d6 100644 --- a/src/Rules/RuleErrors/RuleError405.php +++ b/src/Rules/RuleErrors/RuleError405.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -25,7 +26,7 @@ final class RuleError405 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -57,7 +58,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError407.php b/src/Rules/RuleErrors/RuleError407.php index 01fa71e9b80..2c22d1f4e3f 100644 --- a/src/Rules/RuleErrors/RuleError407.php +++ b/src/Rules/RuleErrors/RuleError407.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -28,7 +29,7 @@ final class RuleError407 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -65,7 +66,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError409.php b/src/Rules/RuleErrors/RuleError409.php index 3ca74e13257..23d23fca33c 100644 --- a/src/Rules/RuleErrors/RuleError409.php +++ b/src/Rules/RuleErrors/RuleError409.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -23,7 +24,7 @@ final class RuleError409 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -50,7 +51,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError411.php b/src/Rules/RuleErrors/RuleError411.php index fa4978f580b..297a329a032 100644 --- a/src/Rules/RuleErrors/RuleError411.php +++ b/src/Rules/RuleErrors/RuleError411.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -26,7 +27,7 @@ final class RuleError411 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError413.php b/src/Rules/RuleErrors/RuleError413.php index beb048bdc46..2174f9941e5 100644 --- a/src/Rules/RuleErrors/RuleError413.php +++ b/src/Rules/RuleErrors/RuleError413.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -28,7 +29,7 @@ final class RuleError413 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -65,7 +66,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError415.php b/src/Rules/RuleErrors/RuleError415.php index f40215bb513..06ee7b9d26f 100644 --- a/src/Rules/RuleErrors/RuleError415.php +++ b/src/Rules/RuleErrors/RuleError415.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -31,7 +32,7 @@ final class RuleError415 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -73,7 +74,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError417.php b/src/Rules/RuleErrors/RuleError417.php index e9ddea4f749..8a7960568b8 100644 --- a/src/Rules/RuleErrors/RuleError417.php +++ b/src/Rules/RuleErrors/RuleError417.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -21,7 +22,7 @@ final class RuleError417 implements RuleError, MetadataRuleError, FixableNodeRul public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -46,7 +47,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError419.php b/src/Rules/RuleErrors/RuleError419.php index 398afb991e0..6397e39aced 100644 --- a/src/Rules/RuleErrors/RuleError419.php +++ b/src/Rules/RuleErrors/RuleError419.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -24,7 +25,7 @@ final class RuleError419 implements RuleError, LineRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -54,7 +55,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError421.php b/src/Rules/RuleErrors/RuleError421.php index 8c06e75f948..93902bdd669 100644 --- a/src/Rules/RuleErrors/RuleError421.php +++ b/src/Rules/RuleErrors/RuleError421.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -26,7 +27,7 @@ final class RuleError421 implements RuleError, FileRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -61,7 +62,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError423.php b/src/Rules/RuleErrors/RuleError423.php index 97869af2410..b2fbff75f15 100644 --- a/src/Rules/RuleErrors/RuleError423.php +++ b/src/Rules/RuleErrors/RuleError423.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -29,7 +30,7 @@ final class RuleError423 implements RuleError, LineRuleError, FileRuleError, Met public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -69,7 +70,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError425.php b/src/Rules/RuleErrors/RuleError425.php index 6543bc97e72..1b20b2e0312 100644 --- a/src/Rules/RuleErrors/RuleError425.php +++ b/src/Rules/RuleErrors/RuleError425.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -24,7 +25,7 @@ final class RuleError425 implements RuleError, TipRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -54,7 +55,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError427.php b/src/Rules/RuleErrors/RuleError427.php index 41ba1720843..3fa04538ca5 100644 --- a/src/Rules/RuleErrors/RuleError427.php +++ b/src/Rules/RuleErrors/RuleError427.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -27,7 +28,7 @@ final class RuleError427 implements RuleError, LineRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -62,7 +63,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError429.php b/src/Rules/RuleErrors/RuleError429.php index 4979227ea00..704dcd73175 100644 --- a/src/Rules/RuleErrors/RuleError429.php +++ b/src/Rules/RuleErrors/RuleError429.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -29,7 +30,7 @@ final class RuleError429 implements RuleError, FileRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -69,7 +70,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError431.php b/src/Rules/RuleErrors/RuleError431.php index dbd6a108055..f0893273022 100644 --- a/src/Rules/RuleErrors/RuleError431.php +++ b/src/Rules/RuleErrors/RuleError431.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -32,7 +33,7 @@ final class RuleError431 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -77,7 +78,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError433.php b/src/Rules/RuleErrors/RuleError433.php index da53294f0e3..e7decd0764a 100644 --- a/src/Rules/RuleErrors/RuleError433.php +++ b/src/Rules/RuleErrors/RuleError433.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -24,7 +25,7 @@ final class RuleError433 implements RuleError, IdentifierRuleError, MetadataRule public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -54,7 +55,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError435.php b/src/Rules/RuleErrors/RuleError435.php index 8af4dd90b00..a61631852e4 100644 --- a/src/Rules/RuleErrors/RuleError435.php +++ b/src/Rules/RuleErrors/RuleError435.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -27,7 +28,7 @@ final class RuleError435 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -62,7 +63,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError437.php b/src/Rules/RuleErrors/RuleError437.php index ac904a8f2c5..dfd1e1630ed 100644 --- a/src/Rules/RuleErrors/RuleError437.php +++ b/src/Rules/RuleErrors/RuleError437.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -29,7 +30,7 @@ final class RuleError437 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -69,7 +70,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError439.php b/src/Rules/RuleErrors/RuleError439.php index 3de3e430a95..a2c9da6fa0a 100644 --- a/src/Rules/RuleErrors/RuleError439.php +++ b/src/Rules/RuleErrors/RuleError439.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -32,7 +33,7 @@ final class RuleError439 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -77,7 +78,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError441.php b/src/Rules/RuleErrors/RuleError441.php index 117836e7f1c..b8e59978545 100644 --- a/src/Rules/RuleErrors/RuleError441.php +++ b/src/Rules/RuleErrors/RuleError441.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -27,7 +28,7 @@ final class RuleError441 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -62,7 +63,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError443.php b/src/Rules/RuleErrors/RuleError443.php index 3df637ed000..0176abfa3c7 100644 --- a/src/Rules/RuleErrors/RuleError443.php +++ b/src/Rules/RuleErrors/RuleError443.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -30,7 +31,7 @@ final class RuleError443 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -70,7 +71,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError445.php b/src/Rules/RuleErrors/RuleError445.php index 207824e9cbe..6438d8e6e94 100644 --- a/src/Rules/RuleErrors/RuleError445.php +++ b/src/Rules/RuleErrors/RuleError445.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -32,7 +33,7 @@ final class RuleError445 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -77,7 +78,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError447.php b/src/Rules/RuleErrors/RuleError447.php index e8334196ed4..dc0e7b27dbd 100644 --- a/src/Rules/RuleErrors/RuleError447.php +++ b/src/Rules/RuleErrors/RuleError447.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -35,7 +36,7 @@ final class RuleError447 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -85,7 +86,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError449.php b/src/Rules/RuleErrors/RuleError449.php index 14b459f2cc2..58d04b02a2e 100644 --- a/src/Rules/RuleErrors/RuleError449.php +++ b/src/Rules/RuleErrors/RuleError449.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -18,7 +19,7 @@ final class RuleError449 implements RuleError, NonIgnorableRuleError, FixableNod public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -35,7 +36,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError451.php b/src/Rules/RuleErrors/RuleError451.php index 6ec124edf8e..08852330aa2 100644 --- a/src/Rules/RuleErrors/RuleError451.php +++ b/src/Rules/RuleErrors/RuleError451.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -21,7 +22,7 @@ final class RuleError451 implements RuleError, LineRuleError, NonIgnorableRuleEr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -43,7 +44,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError453.php b/src/Rules/RuleErrors/RuleError453.php index 286a12f67f1..81c146e89ec 100644 --- a/src/Rules/RuleErrors/RuleError453.php +++ b/src/Rules/RuleErrors/RuleError453.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -23,7 +24,7 @@ final class RuleError453 implements RuleError, FileRuleError, NonIgnorableRuleEr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -50,7 +51,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError455.php b/src/Rules/RuleErrors/RuleError455.php index ce1b5300c11..bcdb600f264 100644 --- a/src/Rules/RuleErrors/RuleError455.php +++ b/src/Rules/RuleErrors/RuleError455.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -26,7 +27,7 @@ final class RuleError455 implements RuleError, LineRuleError, FileRuleError, Non public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError457.php b/src/Rules/RuleErrors/RuleError457.php index 12b08b04de3..9ade4d25771 100644 --- a/src/Rules/RuleErrors/RuleError457.php +++ b/src/Rules/RuleErrors/RuleError457.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\NonIgnorableRuleError; @@ -21,7 +22,7 @@ final class RuleError457 implements RuleError, TipRuleError, NonIgnorableRuleErr public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -43,7 +44,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError459.php b/src/Rules/RuleErrors/RuleError459.php index f4d4378b67d..e2089282a0b 100644 --- a/src/Rules/RuleErrors/RuleError459.php +++ b/src/Rules/RuleErrors/RuleError459.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -24,7 +25,7 @@ final class RuleError459 implements RuleError, LineRuleError, TipRuleError, NonI public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -51,7 +52,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError461.php b/src/Rules/RuleErrors/RuleError461.php index 83e2833e84b..4c2abfa2169 100644 --- a/src/Rules/RuleErrors/RuleError461.php +++ b/src/Rules/RuleErrors/RuleError461.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -26,7 +27,7 @@ final class RuleError461 implements RuleError, FileRuleError, TipRuleError, NonI public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError463.php b/src/Rules/RuleErrors/RuleError463.php index c94ed698c44..cfdcecde211 100644 --- a/src/Rules/RuleErrors/RuleError463.php +++ b/src/Rules/RuleErrors/RuleError463.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -29,7 +30,7 @@ final class RuleError463 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -66,7 +67,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError465.php b/src/Rules/RuleErrors/RuleError465.php index aa850ba143a..05774014db1 100644 --- a/src/Rules/RuleErrors/RuleError465.php +++ b/src/Rules/RuleErrors/RuleError465.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -21,7 +22,7 @@ final class RuleError465 implements RuleError, IdentifierRuleError, NonIgnorable public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -43,7 +44,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError467.php b/src/Rules/RuleErrors/RuleError467.php index 239b4bc8961..df3f666bef4 100644 --- a/src/Rules/RuleErrors/RuleError467.php +++ b/src/Rules/RuleErrors/RuleError467.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -24,7 +25,7 @@ final class RuleError467 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -51,7 +52,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError469.php b/src/Rules/RuleErrors/RuleError469.php index 184f6043fdf..a4ddee597b4 100644 --- a/src/Rules/RuleErrors/RuleError469.php +++ b/src/Rules/RuleErrors/RuleError469.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -26,7 +27,7 @@ final class RuleError469 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -58,7 +59,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError471.php b/src/Rules/RuleErrors/RuleError471.php index c483a990cbf..cab383ec9cf 100644 --- a/src/Rules/RuleErrors/RuleError471.php +++ b/src/Rules/RuleErrors/RuleError471.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -29,7 +30,7 @@ final class RuleError471 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -66,7 +67,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError473.php b/src/Rules/RuleErrors/RuleError473.php index 091b08a0fce..70969d1c5a0 100644 --- a/src/Rules/RuleErrors/RuleError473.php +++ b/src/Rules/RuleErrors/RuleError473.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -24,7 +25,7 @@ final class RuleError473 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -51,7 +52,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError475.php b/src/Rules/RuleErrors/RuleError475.php index 7a7965c10e0..95bf8652993 100644 --- a/src/Rules/RuleErrors/RuleError475.php +++ b/src/Rules/RuleErrors/RuleError475.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -27,7 +28,7 @@ final class RuleError475 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -59,7 +60,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError477.php b/src/Rules/RuleErrors/RuleError477.php index 081110f294b..effb79d3ccb 100644 --- a/src/Rules/RuleErrors/RuleError477.php +++ b/src/Rules/RuleErrors/RuleError477.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -29,7 +30,7 @@ final class RuleError477 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -66,7 +67,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError479.php b/src/Rules/RuleErrors/RuleError479.php index 80254bb60b0..e38fe8fffad 100644 --- a/src/Rules/RuleErrors/RuleError479.php +++ b/src/Rules/RuleErrors/RuleError479.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -32,7 +33,7 @@ final class RuleError479 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -74,7 +75,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError481.php b/src/Rules/RuleErrors/RuleError481.php index 7e77c85a231..a11e19b15b9 100644 --- a/src/Rules/RuleErrors/RuleError481.php +++ b/src/Rules/RuleErrors/RuleError481.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -22,7 +23,7 @@ final class RuleError481 implements RuleError, MetadataRuleError, NonIgnorableRu public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -47,7 +48,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError483.php b/src/Rules/RuleErrors/RuleError483.php index 1f8b3eaabf7..ec6b15cca4b 100644 --- a/src/Rules/RuleErrors/RuleError483.php +++ b/src/Rules/RuleErrors/RuleError483.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -25,7 +26,7 @@ final class RuleError483 implements RuleError, LineRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -55,7 +56,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError485.php b/src/Rules/RuleErrors/RuleError485.php index 4b0bf3aca21..413f8eac71c 100644 --- a/src/Rules/RuleErrors/RuleError485.php +++ b/src/Rules/RuleErrors/RuleError485.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -27,7 +28,7 @@ final class RuleError485 implements RuleError, FileRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -62,7 +63,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError487.php b/src/Rules/RuleErrors/RuleError487.php index 69c4b0b6eee..9df34a39bb1 100644 --- a/src/Rules/RuleErrors/RuleError487.php +++ b/src/Rules/RuleErrors/RuleError487.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -30,7 +31,7 @@ final class RuleError487 implements RuleError, LineRuleError, FileRuleError, Met public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -70,7 +71,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError489.php b/src/Rules/RuleErrors/RuleError489.php index f401d9805bf..4400964f9ec 100644 --- a/src/Rules/RuleErrors/RuleError489.php +++ b/src/Rules/RuleErrors/RuleError489.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; @@ -25,7 +26,7 @@ final class RuleError489 implements RuleError, TipRuleError, MetadataRuleError, public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -55,7 +56,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError491.php b/src/Rules/RuleErrors/RuleError491.php index f4f4323efca..7ac1ef90283 100644 --- a/src/Rules/RuleErrors/RuleError491.php +++ b/src/Rules/RuleErrors/RuleError491.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; @@ -28,7 +29,7 @@ final class RuleError491 implements RuleError, LineRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -63,7 +64,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError493.php b/src/Rules/RuleErrors/RuleError493.php index 4773c9255be..84d395bf4df 100644 --- a/src/Rules/RuleErrors/RuleError493.php +++ b/src/Rules/RuleErrors/RuleError493.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -30,7 +31,7 @@ final class RuleError493 implements RuleError, FileRuleError, TipRuleError, Meta public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -70,7 +71,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError495.php b/src/Rules/RuleErrors/RuleError495.php index 6564db8c8a1..3d0ca3d2b3f 100644 --- a/src/Rules/RuleErrors/RuleError495.php +++ b/src/Rules/RuleErrors/RuleError495.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -33,7 +34,7 @@ final class RuleError495 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -78,7 +79,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError497.php b/src/Rules/RuleErrors/RuleError497.php index 1df55ed5009..053746f23f3 100644 --- a/src/Rules/RuleErrors/RuleError497.php +++ b/src/Rules/RuleErrors/RuleError497.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -25,7 +26,7 @@ final class RuleError497 implements RuleError, IdentifierRuleError, MetadataRule public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -55,7 +56,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError499.php b/src/Rules/RuleErrors/RuleError499.php index 7b451cea678..a061cc823be 100644 --- a/src/Rules/RuleErrors/RuleError499.php +++ b/src/Rules/RuleErrors/RuleError499.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -28,7 +29,7 @@ final class RuleError499 implements RuleError, LineRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -63,7 +64,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError501.php b/src/Rules/RuleErrors/RuleError501.php index 6b68f5fc4f2..0231b6b3b0b 100644 --- a/src/Rules/RuleErrors/RuleError501.php +++ b/src/Rules/RuleErrors/RuleError501.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -30,7 +31,7 @@ final class RuleError501 implements RuleError, FileRuleError, IdentifierRuleErro public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -70,7 +71,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError503.php b/src/Rules/RuleErrors/RuleError503.php index e8bfb21a2cf..97857767ec8 100644 --- a/src/Rules/RuleErrors/RuleError503.php +++ b/src/Rules/RuleErrors/RuleError503.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -33,7 +34,7 @@ final class RuleError503 implements RuleError, LineRuleError, FileRuleError, Ide public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -78,7 +79,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError505.php b/src/Rules/RuleErrors/RuleError505.php index 901a70777d2..04150961307 100644 --- a/src/Rules/RuleErrors/RuleError505.php +++ b/src/Rules/RuleErrors/RuleError505.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -28,7 +29,7 @@ final class RuleError505 implements RuleError, TipRuleError, IdentifierRuleError public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -63,7 +64,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError507.php b/src/Rules/RuleErrors/RuleError507.php index c57afd4784a..830597f945f 100644 --- a/src/Rules/RuleErrors/RuleError507.php +++ b/src/Rules/RuleErrors/RuleError507.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -31,7 +32,7 @@ final class RuleError507 implements RuleError, LineRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -71,7 +72,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError509.php b/src/Rules/RuleErrors/RuleError509.php index e396b433b80..680a13d6214 100644 --- a/src/Rules/RuleErrors/RuleError509.php +++ b/src/Rules/RuleErrors/RuleError509.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -33,7 +34,7 @@ final class RuleError509 implements RuleError, FileRuleError, TipRuleError, Iden public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -78,7 +79,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/src/Rules/RuleErrors/RuleError511.php b/src/Rules/RuleErrors/RuleError511.php index 20a4a3164d2..f07b554d81f 100644 --- a/src/Rules/RuleErrors/RuleError511.php +++ b/src/Rules/RuleErrors/RuleError511.php @@ -3,6 +3,7 @@ namespace PHPStan\Rules\RuleErrors; use PhpParser\Node; +use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; @@ -36,7 +37,7 @@ final class RuleError511 implements RuleError, LineRuleError, FileRuleError, Tip public Node $originalNode; - /** @var callable(Node): Node */ + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public $newNodeCallable; /** @var list */ @@ -86,7 +87,7 @@ public function getOriginalNode(): Node } /** - * @return callable(Node): Node + * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ public function getNewNodeCallable(): callable { diff --git a/tests/PHPStan/Fixable/RemoveNodeRule.php b/tests/PHPStan/Fixable/RemoveNodeRule.php new file mode 100644 index 00000000000..6c405e1826d --- /dev/null +++ b/tests/PHPStan/Fixable/RemoveNodeRule.php @@ -0,0 +1,55 @@ + + */ +class RemoveNodeRule implements Rule +{ + + public function getNodeType(): string + { + return Node::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof Stmt\Expression && self::isRemoveMeCall($node->expr)) { + $toRemove = $node; + } elseif ($node instanceof Stmt\ClassMethod && $node->name->toLowerString() === 'removeme') { + $toRemove = $node; + } elseif ($node instanceof Arg && $node->value instanceof ConstFetch && $node->value->name->toString() === 'REMOVE_ARG') { + $toRemove = $node; + } elseif ($node instanceof Stmt\If_ && self::isRemoveMeCall($node->cond)) { + // not in an array, cannot be removed + $toRemove = $node->cond; + } else { + return []; + } + + return [ + RuleErrorBuilder::message('Removing ' . $toRemove->getType() . '.') + ->identifier('tests.removeNode') + ->line($toRemove->getStartLine()) + ->removeNode($toRemove) + ->build(), + ]; + } + + private static function isRemoveMeCall(Node $node): bool + { + return $node instanceof FuncCall && $node->name instanceof Name && $node->name->toLowerString() === 'removeme'; + } + +} diff --git a/tests/PHPStan/Fixable/RemoveNodeRuleTest.php b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php new file mode 100644 index 00000000000..d9c8ae92287 --- /dev/null +++ b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php @@ -0,0 +1,49 @@ + + */ +class RemoveNodeRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new RemoveNodeRule(); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/remove-node.php'], [ + ['Removing Stmt_Expression.', 11], + ['Removing Arg.', 13], + ['Removing Expr_FuncCall.', 14], + ['Removing Stmt_ClassMethod.', 22], + ]); + } + + public function testFix(): void + { + $this->fix(__DIR__ . '/data/remove-node.php', __DIR__ . '/data/remove-node.php.fixed'); + } + + public function testNodeNotInArrayIsNotFixable(): void + { + $fixable = []; + foreach ($this->gatherAnalyserErrors([__DIR__ . '/data/remove-node.php']) as $error) { + $fixable[$error->getMessage()] = $error->getFixedErrorDiff() !== null; + } + + $this->assertSame([ + 'Removing Stmt_Expression.' => true, + 'Removing Arg.' => true, + 'Removing Expr_FuncCall.' => false, + 'Removing Stmt_ClassMethod.' => true, + ], $fixable); + } + +} diff --git a/tests/PHPStan/Fixable/data/remove-node.php b/tests/PHPStan/Fixable/data/remove-node.php new file mode 100644 index 00000000000..a288fb95058 --- /dev/null +++ b/tests/PHPStan/Fixable/data/remove-node.php @@ -0,0 +1,30 @@ + Date: Mon, 2 Nov 2026 04:05:31 +0000 Subject: [PATCH 08/24] Apply fix diffs to file contents instead of a file path The fixer is going to apply diffs to edited contents that are not written to disk yet. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Command/AnalyseCommand.php | 2 +- src/Fixable/Patcher.php | 6 ++---- src/Testing/RuleTestCase.php | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 07fc64e40f5..57fed17acde 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -583,7 +583,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($diffsByFile as $file => $diffs) { $diffsCount = count($diffs); try { - $patchResult = $patcher->applyDiffs($file, $diffs); + $patchResult = $patcher->applyDiffs(FileReader::read($file), $diffs); $skippedCount += $patchResult['skippedCount']; $errorOutput->getStyle()->progressAdvance($diffsCount); } catch (FileChangedException) { diff --git a/src/Fixable/Patcher.php b/src/Fixable/Patcher.php index 54dcaf1e092..29320ed60c1 100644 --- a/src/Fixable/Patcher.php +++ b/src/Fixable/Patcher.php @@ -5,7 +5,6 @@ use Nette\Utils\Strings; use PHPStan\Analyser\FixedErrorDiff; use PHPStan\DependencyInjection\AutowiredService; -use PHPStan\File\FileReader; use function array_splice; use function count; use function hash; @@ -31,11 +30,10 @@ final class Patcher /** * @param FixedErrorDiff[] $diffs * @return array{contents: string, skippedCount: int} - * @throws FileChangedException + * @throws FileChangedException when a diff was computed against different contents */ - public function applyDiffs(string $fileName, array $diffs): array + public function applyDiffs(string $fileContents, array $diffs): array { - $fileContents = FileReader::read($fileName); $fileHash = hash('sha256', $fileContents); foreach ($diffs as $diff) { if ($diff->originalHash !== $fileHash) { diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 1f1ce10365b..3ee67bbdcc6 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -260,7 +260,7 @@ public function fixOtherFile(string $file, string $fixedFile, string $expectedFi } $patcher = self::getContainer()->getByType(Patcher::class); - $patchResult = $patcher->applyDiffs($fixedFile, $diffs); // @phpstan-ignore missingType.checkedException + $patchResult = $patcher->applyDiffs(FileReader::read($fixedFile), $diffs); // @phpstan-ignore missingType.checkedException $this->assertSame(0, $patchResult['skippedCount'], 'Some fixes overlap and could not be applied together.'); $fixedFileContents = FileReader::read($expectedFile); From 6158a504924e3922c178394a9af1b8334b83eb15 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 04:07:55 +0000 Subject: [PATCH 09/24] Add --fix-ignored Errors ignored by ignoreErrors, the baseline, or inline @phpstan-ignore comments can be fixed with --fix-ignored, alone or together with --fix. The table error formatter mentions them in grey, also when the build is green. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- .github/workflows/e2e-tests.yml | 24 ++++++ e2e/fix/.gitignore | 4 + e2e/fix/composer.json | 7 ++ e2e/fix/expected/Foo.php | 9 +++ e2e/fix/expected/Ignored-fix-both.php | 6 ++ e2e/fix/expected/Ignored-fix-ignored.php | 6 ++ e2e/fix/expected/Ignored-fix.php | 6 ++ e2e/fix/original/Foo.php | 9 +++ e2e/fix/original/Ignored.php | 6 ++ e2e/fix/phpstan.neon | 13 ++++ e2e/fix/rules/rules.php | 75 +++++++++++++++++++ src/Command/AnalyseApplication.php | 16 ++++ src/Command/AnalyseCommand.php | 28 +++++-- src/Command/AnalysisResult.php | 13 ++++ .../ErrorFormatter/TableErrorFormatter.php | 17 ++++- .../TableErrorFormatterTest.php | 22 ++++++ 16 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 e2e/fix/.gitignore create mode 100644 e2e/fix/composer.json create mode 100644 e2e/fix/expected/Foo.php create mode 100644 e2e/fix/expected/Ignored-fix-both.php create mode 100644 e2e/fix/expected/Ignored-fix-ignored.php create mode 100644 e2e/fix/expected/Ignored-fix.php create mode 100644 e2e/fix/original/Foo.php create mode 100644 e2e/fix/original/Ignored.php create mode 100644 e2e/fix/phpstan.neon create mode 100644 e2e/fix/rules/rules.php diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 99db5336ea1..8f941ffa00d 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -967,6 +967,30 @@ jobs: OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw") echo "$OUTPUT" ../bashunit assert contains 'FooTrait.php (in context of class ResultCacheE2ETraitAlongsideClass\ClassUsingFooTrait):10:Method ResultCacheE2ETraitAlongsideClass\ClassUsingFooTrait::doFooTrait() should return stdClass but returns Exception. [identifier=return.type]' "$OUTPUT" + - script: | + cd e2e/fix + composer install + rm -rf src tmp && cp -r original src + OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix") + echo "$OUTPUT" + ../bashunit assert contains '[OK] 2 errors fixed' "$OUTPUT" + diff -u expected/Foo.php src/Foo.php + diff -u expected/Ignored-fix.php src/Ignored.php + rm -rf src && cp -r original src + OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix-ignored") + echo "$OUTPUT" + ../bashunit assert contains '[OK] 1 error fixed' "$OUTPUT" + diff -u original/Foo.php src/Foo.php + diff -u expected/Ignored-fix-ignored.php src/Ignored.php + rm -rf src && cp -r original src + OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix --fix-ignored") + echo "$OUTPUT" + ../bashunit assert contains '[OK] 3 errors fixed' "$OUTPUT" + diff -u expected/Foo.php src/Foo.php + diff -u expected/Ignored-fix-both.php src/Ignored.php + OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse --fix-ignored") + echo "$OUTPUT" + ../bashunit assert contains 'No fixable errors found' "$OUTPUT" - script: | cd e2e/editor-mode OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw") diff --git a/e2e/fix/.gitignore b/e2e/fix/.gitignore new file mode 100644 index 00000000000..82cdbfd52b3 --- /dev/null +++ b/e2e/fix/.gitignore @@ -0,0 +1,4 @@ +/src +/tmp +/vendor +/composer.lock diff --git a/e2e/fix/composer.json b/e2e/fix/composer.json new file mode 100644 index 00000000000..12a1404d2e9 --- /dev/null +++ b/e2e/fix/composer.json @@ -0,0 +1,7 @@ +{ + "autoload-dev": { + "classmap": [ + "rules/" + ] + } +} diff --git a/e2e/fix/expected/Foo.php b/e2e/fix/expected/Foo.php new file mode 100644 index 00000000000..f8d37b785e1 --- /dev/null +++ b/e2e/fix/expected/Foo.php @@ -0,0 +1,9 @@ + + */ +final class StepRule implements Rule +{ + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Node\Name || preg_match('~^step([1-3])$~', $node->name->toString(), $matches) !== 1) { + return []; + } + + $next = 'step' . ((int) $matches[1] + 1); + + return [ + RuleErrorBuilder::message(sprintf('Call %s() instead.', $next)) + ->identifier('fixE2E.step') + ->fixNode($node, static function (FuncCall $node) use ($next): FuncCall { + $node->name = new Node\Name($next); + return $node; + }) + ->build(), + ]; + } + +} + +/** + * Removes every argument of noArgs() with its own error. The fixes of one call conflict, so one is applied per round. + * + * @implements Rule + */ +final class NoArgsRule implements Rule +{ + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Node\Name || $node->name->toString() !== 'noArgs') { + return []; + } + + $errors = []; + foreach ($node->getArgs() as $i => $arg) { + $errors[] = RuleErrorBuilder::message(sprintf('Remove argument #%d.', $i + 1)) + ->identifier('fixE2E.noArgs') + ->removeNode($arg) + ->build(); + } + + return $errors; + } + +} diff --git a/src/Command/AnalyseApplication.php b/src/Command/AnalyseApplication.php index 7155cfcaf09..db9f1d6e652 100644 --- a/src/Command/AnalyseApplication.php +++ b/src/Command/AnalyseApplication.php @@ -79,6 +79,7 @@ public function analyse( $ignoredErrorHelperResult = $this->ignoredErrorHelper->initialize(); $fileSpecificErrors = []; + $fixableIgnoredErrors = []; if (count($ignoredErrorHelperResult->getErrors()) > 0) { $notFileSpecificErrors = $ignoredErrorHelperResult->getErrors(); $internalErrors = []; @@ -169,6 +170,20 @@ public function analyse( $ignoredErrorHelperProcessedResult = $ignoredErrorHelperResult->process($errors, $onlyFiles, $files, $hasInternalErrors); $fileSpecificErrors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); $notFileSpecificErrors = $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages(); + foreach ($ignoredErrorHelperProcessedResult->getIgnoredErrors() as [$ignoredError]) { + if ($ignoredError->getFixedErrorDiff() === null) { + continue; + } + + $fixableIgnoredErrors[] = $ignoredError; + } + foreach ($analyserResult->getLocallyIgnoredErrors() as $locallyIgnoredError) { + if ($locallyIgnoredError->getFixedErrorDiff() === null) { + continue; + } + + $fixableIgnoredErrors[] = $locallyIgnoredError; + } $collectedData = $resultCacheResult->getSavedCollectedData() ?? $analyserResult->getLazyCollectedData(); } @@ -186,6 +201,7 @@ public function analyse( $processedFiles, $resultCacheExisted, $workerCount, + $fixableIgnoredErrors, ); } diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 57fed17acde..991c3994b57 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -116,6 +116,7 @@ protected function configure(): void new InputOption('tmp-file', mode: InputOption::VALUE_REQUIRED, description: '(Editor mode) Edited file used in place of --instead-of file'), new InputOption('instead-of', mode: InputOption::VALUE_REQUIRED, description: '(Editor mode) File being replaced by --tmp-file'), new InputOption('fix', mode: InputOption::VALUE_NONE, description: 'Fix auto-fixable errors (experimental)'), + new InputOption('fix-ignored', mode: InputOption::VALUE_NONE, description: 'Fix auto-fixable ignored errors, can be combined with --fix (experimental)'), new InputOption('watch', mode: InputOption::VALUE_NONE, description: 'Launch PHPStan Pro'), new InputOption('pro', mode: InputOption::VALUE_NONE, description: 'Launch PHPStan Pro'), new InputOption('fail-without-result-cache', mode: InputOption::VALUE_NONE, description: 'Return non-zero exit code when result cache is not used'), @@ -155,7 +156,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowXdebug = $input->getOption('xdebug'); $debugEnabled = (bool) $input->getOption('debug'); $pro = (bool) $input->getOption('watch') || (bool) $input->getOption('pro'); - $fix = (bool) $input->getOption('fix'); + $fixReported = (bool) $input->getOption('fix'); + $fixIgnored = (bool) $input->getOption('fix-ignored'); + $fix = $fixReported || $fixIgnored; $failWithoutResultCache = (bool) $input->getOption('fail-without-result-cache'); /** @var string|false|null $generateBaselineFile */ @@ -221,7 +224,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $inceptionResult->handleReturn(1, null, $this->analysisStartTime); } if ($fix) { - $inceptionResult->getStdOutput()->getStyle()->error('Editor mode options --tmp-file and --instead-of cannot be used with --fix.'); + $inceptionResult->getStdOutput()->getStyle()->error('Editor mode options --tmp-file and --instead-of cannot be used with --fix and --fix-ignored.'); return $inceptionResult->handleReturn(1, null, $this->analysisStartTime); } } @@ -232,7 +235,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $inceptionResult->handleReturn(1, null, $this->analysisStartTime); } - $inceptionResult->getErrorOutput()->getStyle()->note('The --fix CLI option no longer launches PHPStan Pro. Use --pro instead if you want to launch PHPStan Pro'); + if ($fixReported) { + $inceptionResult->getErrorOutput()->getStyle()->note('The --fix CLI option no longer launches PHPStan Pro. Use --pro instead if you want to launch PHPStan Pro'); + } } $errorOutput = $inceptionResult->getErrorOutput(); @@ -548,12 +553,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($fix) { $fixableErrors = []; - foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - if ($fileSpecificError->getFixedErrorDiff() === null) { - continue; - } + if ($fixReported) { + foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { + if ($fileSpecificError->getFixedErrorDiff() === null) { + continue; + } - $fixableErrors[] = $fileSpecificError; + $fixableErrors[] = $fileSpecificError; + } + } + if ($fixIgnored) { + foreach ($analysisResult->getFixableIgnoredErrors() as $fixableIgnoredError) { + $fixableErrors[] = $fixableIgnoredError; + } } $fixableErrorsCount = count($fixableErrors); diff --git a/src/Command/AnalysisResult.php b/src/Command/AnalysisResult.php index bbc823d6340..934fcb91b0f 100644 --- a/src/Command/AnalysisResult.php +++ b/src/Command/AnalysisResult.php @@ -25,6 +25,7 @@ final class AnalysisResult * @param list $warnings * @param list|(Closure(): list) $collectedData A closure defers decoding the result cache until asked * @param list $processedFiles + * @param list $fixableIgnoredErrors ignored errors that --fix-ignored can fix */ public function __construct( array $fileSpecificErrors, @@ -40,6 +41,7 @@ public function __construct( private array $processedFiles = [], private bool $resultCacheExisted = true, private int $workerCount = 0, + private array $fixableIgnoredErrors = [], ) { usort( @@ -202,7 +204,18 @@ public function withFileSpecificErrors(array $fileSpecificErrors): self $this->isResultCacheUsed, $this->processedFiles, $this->resultCacheExisted, + $this->workerCount, + $this->fixableIgnoredErrors, ); } + /** + * @api + * @return list + */ + public function getFixableIgnoredErrors(): array + { + return $this->fixableIgnoredErrors; + } + } diff --git a/src/Command/ErrorFormatter/TableErrorFormatter.php b/src/Command/ErrorFormatter/TableErrorFormatter.php index b36fc8a4507..513ba27fc9a 100644 --- a/src/Command/ErrorFormatter/TableErrorFormatter.php +++ b/src/Command/ErrorFormatter/TableErrorFormatter.php @@ -77,6 +77,7 @@ public function formatErrors( if (!$analysisResult->hasErrors() && !$analysisResult->hasWarnings()) { $style->success('No errors'); + $this->printFixableIgnoredErrors($analysisResult, $output); if ($this->showTipsOfTheDay) { if ($analysisResult->isDefaultLevelUsed()) { @@ -223,12 +224,26 @@ public function formatErrors( if ($fixableErrorsCount > 0) { $output->writeLineFormatted(sprintf('🔧 %d %s can be fixed automatically. Run PHPStan again with --fix.', $fixableErrorsCount, $fixableErrorsCount === 1 ? 'error' : 'errors')); - $output->writeLineFormatted(''); + if (count($analysisResult->getFixableIgnoredErrors()) === 0) { + $output->writeLineFormatted(''); + } } + $this->printFixableIgnoredErrors($analysisResult, $output); return $analysisResult->getTotalErrorsCount() > 0 ? 1 : 0; } + private function printFixableIgnoredErrors(AnalysisResult $analysisResult, Output $output): void + { + $count = count($analysisResult->getFixableIgnoredErrors()); + if ($count === 0) { + return; + } + + $output->writeLineFormatted(sprintf('🔧 %d ignored %s can be fixed automatically. Run PHPStan again with --fix-ignored.', $count, $count === 1 ? 'error' : 'errors')); + $output->writeLineFormatted(''); + } + private function formatLineNumber(?int $lineNumber): string { if ($lineNumber === null) { diff --git a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php index bf31b347be7..81859481157 100644 --- a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php @@ -4,6 +4,7 @@ use Override; use PHPStan\Analyser\Error; +use PHPStan\Analyser\FixedErrorDiff; use PHPStan\Command\AnalysisResult; use PHPStan\Command\CommandHelper; use PHPStan\File\FuzzyRelativePathHelper; @@ -487,6 +488,27 @@ public function testErrorLimit( $this->assertStringContainsString($expected, $this->getOutputContent()); } + public function testFixableIgnoredErrors(): void + { + $fixed = new FixedErrorDiff('hash', 'diff'); + $fixable = new Error('Fixable', 'Foo.php', 12, filePath: 'Foo.php', fixedErrorDiff: $fixed); + $ignoredFixable = new Error('Ignored', 'Foo.php', 13, filePath: 'Foo.php', fixedErrorDiff: $fixed); + + // shown with a green build too, the ignored errors are not in the table + $formatter = $this->createErrorFormatter(null); + $formatter->formatErrors(new AnalysisResult([], [], [], [], [], false, null, true, 0, false, fixableIgnoredErrors: [$ignoredFixable, $ignoredFixable]), $this->getOutput(true)); + $output = $this->getOutputContent(true); + $this->assertStringContainsString("\e[90m🔧 2 ignored errors can be fixed automatically. Run PHPStan again with --fix-ignored.\e[39m", $output); + $this->assertStringNotContainsString('Ignored', $output); + + $formatter = $this->createErrorFormatter(null); + $formatter->formatErrors(new AnalysisResult([$fixable], [], [], [], [], false, null, true, 0, false, fixableIgnoredErrors: [$ignoredFixable]), $this->getOutput()); + $this->assertStringContainsString( + "🔧 1 error can be fixed automatically. Run PHPStan again with --fix.\n🔧 1 ignored error can be fixed automatically. Run PHPStan again with --fix-ignored.\n", + $this->getOutputContent(), + ); + } + public function testEditorUrlWithTrait(): void { $formatter = $this->createErrorFormatter('editor://%file%/%line%'); From 50f8efef718e4ff2fd395789c7a1b9373ca6f15d Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 04:29:38 +0000 Subject: [PATCH 10/24] Register every fixNode() and removeNode() call of an error Each call adds a change to the fix of the error instead of replacing the previous one, and can point to another file. The changes of one file are applied in a single traversal, several changes of the same node in the order they were added. An error gets one diff per file, and Patcher applies the diffs of an error together or not at all, also across files. When some change cannot be applied, the error is not fixable. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- bin/generate-rule-error-classes.php | 2 +- build/ignore-gte-php7.4-errors.neon | 2 +- src/Analyser/AnalyserResultFinalizer.php | 12 +- src/Analyser/Error.php | 71 ++++++---- src/Analyser/FixedErrorDiff.php | 6 +- src/Analyser/RuleErrorTransformer.php | 51 ++++--- src/Command/AnalyseApplication.php | 4 +- src/Command/AnalyseCommand.php | 42 +----- .../ErrorFormatter/TableErrorFormatter.php | 4 +- src/Fixable/FileChangedException.php | 10 -- src/Fixable/Patcher.php | 133 ++++++++++++++---- src/Fixable/ReplacingNodeVisitor.php | 90 +++++++----- src/Rules/FixableNodeRuleError.php | 9 +- src/Rules/NodeFix.php | 26 ++++ src/Rules/Playground/PromoteParameterRule.php | 4 +- src/Rules/RuleErrorBuilder.php | 35 +++-- src/Rules/RuleErrors/RuleError129.php | 20 +-- src/Rules/RuleErrors/RuleError131.php | 20 +-- src/Rules/RuleErrors/RuleError133.php | 20 +-- src/Rules/RuleErrors/RuleError135.php | 20 +-- src/Rules/RuleErrors/RuleError137.php | 20 +-- src/Rules/RuleErrors/RuleError139.php | 20 +-- src/Rules/RuleErrors/RuleError141.php | 20 +-- src/Rules/RuleErrors/RuleError143.php | 20 +-- src/Rules/RuleErrors/RuleError145.php | 20 +-- src/Rules/RuleErrors/RuleError147.php | 20 +-- src/Rules/RuleErrors/RuleError149.php | 20 +-- src/Rules/RuleErrors/RuleError151.php | 20 +-- src/Rules/RuleErrors/RuleError153.php | 20 +-- src/Rules/RuleErrors/RuleError155.php | 20 +-- src/Rules/RuleErrors/RuleError157.php | 20 +-- src/Rules/RuleErrors/RuleError159.php | 20 +-- src/Rules/RuleErrors/RuleError161.php | 20 +-- src/Rules/RuleErrors/RuleError163.php | 20 +-- src/Rules/RuleErrors/RuleError165.php | 20 +-- src/Rules/RuleErrors/RuleError167.php | 20 +-- src/Rules/RuleErrors/RuleError169.php | 20 +-- src/Rules/RuleErrors/RuleError171.php | 20 +-- src/Rules/RuleErrors/RuleError173.php | 20 +-- src/Rules/RuleErrors/RuleError175.php | 20 +-- src/Rules/RuleErrors/RuleError177.php | 20 +-- src/Rules/RuleErrors/RuleError179.php | 20 +-- src/Rules/RuleErrors/RuleError181.php | 20 +-- src/Rules/RuleErrors/RuleError183.php | 20 +-- src/Rules/RuleErrors/RuleError185.php | 20 +-- src/Rules/RuleErrors/RuleError187.php | 20 +-- src/Rules/RuleErrors/RuleError189.php | 20 +-- src/Rules/RuleErrors/RuleError191.php | 20 +-- src/Rules/RuleErrors/RuleError193.php | 20 +-- src/Rules/RuleErrors/RuleError195.php | 20 +-- src/Rules/RuleErrors/RuleError197.php | 20 +-- src/Rules/RuleErrors/RuleError199.php | 20 +-- src/Rules/RuleErrors/RuleError201.php | 20 +-- src/Rules/RuleErrors/RuleError203.php | 20 +-- src/Rules/RuleErrors/RuleError205.php | 20 +-- src/Rules/RuleErrors/RuleError207.php | 20 +-- src/Rules/RuleErrors/RuleError209.php | 20 +-- src/Rules/RuleErrors/RuleError211.php | 20 +-- src/Rules/RuleErrors/RuleError213.php | 20 +-- src/Rules/RuleErrors/RuleError215.php | 20 +-- src/Rules/RuleErrors/RuleError217.php | 20 +-- src/Rules/RuleErrors/RuleError219.php | 20 +-- src/Rules/RuleErrors/RuleError221.php | 20 +-- src/Rules/RuleErrors/RuleError223.php | 20 +-- src/Rules/RuleErrors/RuleError225.php | 20 +-- src/Rules/RuleErrors/RuleError227.php | 20 +-- src/Rules/RuleErrors/RuleError229.php | 20 +-- src/Rules/RuleErrors/RuleError231.php | 20 +-- src/Rules/RuleErrors/RuleError233.php | 20 +-- src/Rules/RuleErrors/RuleError235.php | 20 +-- src/Rules/RuleErrors/RuleError237.php | 20 +-- src/Rules/RuleErrors/RuleError239.php | 20 +-- src/Rules/RuleErrors/RuleError241.php | 20 +-- src/Rules/RuleErrors/RuleError243.php | 20 +-- src/Rules/RuleErrors/RuleError245.php | 20 +-- src/Rules/RuleErrors/RuleError247.php | 20 +-- src/Rules/RuleErrors/RuleError249.php | 20 +-- src/Rules/RuleErrors/RuleError251.php | 20 +-- src/Rules/RuleErrors/RuleError253.php | 20 +-- src/Rules/RuleErrors/RuleError255.php | 20 +-- src/Rules/RuleErrors/RuleError385.php | 20 +-- src/Rules/RuleErrors/RuleError387.php | 20 +-- src/Rules/RuleErrors/RuleError389.php | 20 +-- src/Rules/RuleErrors/RuleError391.php | 20 +-- src/Rules/RuleErrors/RuleError393.php | 20 +-- src/Rules/RuleErrors/RuleError395.php | 20 +-- src/Rules/RuleErrors/RuleError397.php | 20 +-- src/Rules/RuleErrors/RuleError399.php | 20 +-- src/Rules/RuleErrors/RuleError401.php | 20 +-- src/Rules/RuleErrors/RuleError403.php | 20 +-- src/Rules/RuleErrors/RuleError405.php | 20 +-- src/Rules/RuleErrors/RuleError407.php | 20 +-- src/Rules/RuleErrors/RuleError409.php | 20 +-- src/Rules/RuleErrors/RuleError411.php | 20 +-- src/Rules/RuleErrors/RuleError413.php | 20 +-- src/Rules/RuleErrors/RuleError415.php | 20 +-- src/Rules/RuleErrors/RuleError417.php | 20 +-- src/Rules/RuleErrors/RuleError419.php | 20 +-- src/Rules/RuleErrors/RuleError421.php | 20 +-- src/Rules/RuleErrors/RuleError423.php | 20 +-- src/Rules/RuleErrors/RuleError425.php | 20 +-- src/Rules/RuleErrors/RuleError427.php | 20 +-- src/Rules/RuleErrors/RuleError429.php | 20 +-- src/Rules/RuleErrors/RuleError431.php | 20 +-- src/Rules/RuleErrors/RuleError433.php | 20 +-- src/Rules/RuleErrors/RuleError435.php | 20 +-- src/Rules/RuleErrors/RuleError437.php | 20 +-- src/Rules/RuleErrors/RuleError439.php | 20 +-- src/Rules/RuleErrors/RuleError441.php | 20 +-- src/Rules/RuleErrors/RuleError443.php | 20 +-- src/Rules/RuleErrors/RuleError445.php | 20 +-- src/Rules/RuleErrors/RuleError447.php | 20 +-- src/Rules/RuleErrors/RuleError449.php | 20 +-- src/Rules/RuleErrors/RuleError451.php | 20 +-- src/Rules/RuleErrors/RuleError453.php | 20 +-- src/Rules/RuleErrors/RuleError455.php | 20 +-- src/Rules/RuleErrors/RuleError457.php | 20 +-- src/Rules/RuleErrors/RuleError459.php | 20 +-- src/Rules/RuleErrors/RuleError461.php | 20 +-- src/Rules/RuleErrors/RuleError463.php | 20 +-- src/Rules/RuleErrors/RuleError465.php | 20 +-- src/Rules/RuleErrors/RuleError467.php | 20 +-- src/Rules/RuleErrors/RuleError469.php | 20 +-- src/Rules/RuleErrors/RuleError471.php | 20 +-- src/Rules/RuleErrors/RuleError473.php | 20 +-- src/Rules/RuleErrors/RuleError475.php | 20 +-- src/Rules/RuleErrors/RuleError477.php | 20 +-- src/Rules/RuleErrors/RuleError479.php | 20 +-- src/Rules/RuleErrors/RuleError481.php | 20 +-- src/Rules/RuleErrors/RuleError483.php | 20 +-- src/Rules/RuleErrors/RuleError485.php | 20 +-- src/Rules/RuleErrors/RuleError487.php | 20 +-- src/Rules/RuleErrors/RuleError489.php | 20 +-- src/Rules/RuleErrors/RuleError491.php | 20 +-- src/Rules/RuleErrors/RuleError493.php | 20 +-- src/Rules/RuleErrors/RuleError495.php | 20 +-- src/Rules/RuleErrors/RuleError497.php | 20 +-- src/Rules/RuleErrors/RuleError499.php | 20 +-- src/Rules/RuleErrors/RuleError501.php | 20 +-- src/Rules/RuleErrors/RuleError503.php | 20 +-- src/Rules/RuleErrors/RuleError505.php | 20 +-- src/Rules/RuleErrors/RuleError507.php | 20 +-- src/Rules/RuleErrors/RuleError509.php | 20 +-- src/Rules/RuleErrors/RuleError511.php | 20 +-- src/Testing/RuleTestCase.php | 21 ++- .../Analyser/CollectedDataRuleReuseTest.php | 2 +- .../TableErrorFormatterTest.php | 6 +- tests/PHPStan/Fixable/MultiFixRule.php | 98 +++++++++++++ tests/PHPStan/Fixable/MultiFixRuleTest.php | 36 +++++ tests/PHPStan/Fixable/PatcherTest.php | 39 +++++ tests/PHPStan/Fixable/RemoveNodeRuleTest.php | 2 +- tests/PHPStan/Fixable/data/multi-fix/a.php | 6 + .../Fixable/data/multi-fix/a.php.fixed | 6 + .../Fixable/data/multi-fix/all-or-nothing.php | 8 ++ .../PHPStan/Fixable/data/multi-fix/other.php | 8 ++ .../Fixable/data/multi-fix/other.php.fixed | 8 ++ 156 files changed, 1299 insertions(+), 2002 deletions(-) delete mode 100644 src/Fixable/FileChangedException.php create mode 100644 src/Rules/NodeFix.php create mode 100644 tests/PHPStan/Fixable/MultiFixRule.php create mode 100644 tests/PHPStan/Fixable/MultiFixRuleTest.php create mode 100644 tests/PHPStan/Fixable/PatcherTest.php create mode 100644 tests/PHPStan/Fixable/data/multi-fix/a.php create mode 100644 tests/PHPStan/Fixable/data/multi-fix/a.php.fixed create mode 100644 tests/PHPStan/Fixable/data/multi-fix/all-or-nothing.php create mode 100644 tests/PHPStan/Fixable/data/multi-fix/other.php create mode 100644 tests/PHPStan/Fixable/data/multi-fix/other.php.fixed diff --git a/bin/generate-rule-error-classes.php b/bin/generate-rule-error-classes.php index ca9cdcbc4c4..6b8284669e5 100755 --- a/bin/generate-rule-error-classes.php +++ b/bin/generate-rule-error-classes.php @@ -47,7 +47,7 @@ final class RuleError%s implements %s $typeCombination, implode(', ', $interfaces), implode("\n\n\t", array_map(static fn (array $property): string => sprintf('%spublic %s $%s;', $property[2] !== $property[1] ? sprintf("/** @var %s */\n\t", $property[2]) : '', $property[1], $property[0]), $properties)), - implode("\n\n\t", array_map(static fn (array $property): string => sprintf("%spublic function get%s()%s\n\t{\n\t\treturn \$this->%s;\n\t}", $property[2] !== $property[1] ? sprintf("/**\n\t * @return %s\n\t */\n\t", $property[2]) : '', ucfirst($property[0]), $property[1] === null ? (str_starts_with($property[2], 'callable') ? ': callable' : '') : sprintf(': %s', $property[1]), $property[0]), $properties)), + implode("\n\n\t", array_map(static fn (array $property): string => sprintf("%spublic function get%s()%s\n\t{\n\t\treturn \$this->%s;\n\t}", $property[2] !== $property[1] ? sprintf("/**\n\t * @return %s\n\t */\n\t", $property[2]) : '', ucfirst($property[0]), $property[1] === null ? '' : sprintf(': %s', $property[1]), $property[0]), $properties)), ); file_put_contents(__DIR__ . '/../src/Rules/RuleErrors/RuleError' . $typeCombination . '.php', $phpClass); diff --git a/build/ignore-gte-php7.4-errors.neon b/build/ignore-gte-php7.4-errors.neon index 112fb17e4cd..4cd10ed69e5 100644 --- a/build/ignore-gte-php7.4-errors.neon +++ b/build/ignore-gte-php7.4-errors.neon @@ -3,7 +3,7 @@ includes: parameters: ignoreErrors: - - '#^Class PHPStan\\Rules\\RuleErrors\\RuleError(?:\d+) has an uninitialized property (?:\$message|\$line|\$identifier|\$tip|\$file|\$metadata|\$originalNode)#' + - '#^Class PHPStan\\Rules\\RuleErrors\\RuleError(?:\d+) has an uninitialized property (?:\$message|\$line|\$identifier|\$tip|\$file|\$metadata|\$nodeFixes)#' - '#Extension has an uninitialized property (?:\$typeSpecifier|\$broker)#' - message: '#has an uninitialized property#' diff --git a/src/Analyser/AnalyserResultFinalizer.php b/src/Analyser/AnalyserResultFinalizer.php index d905d7d584f..ffe1cf8e238 100644 --- a/src/Analyser/AnalyserResultFinalizer.php +++ b/src/Analyser/AnalyserResultFinalizer.php @@ -311,14 +311,10 @@ private function canReuse(CollectedDataRuleResult $previousResult, bool $onlyFil // a fix is a diff against the file contents, which can change without changing the collected data foreach ($previousResult->getErrors() as $error) { - $fixedErrorDiff = $error->getFixedErrorDiff(); - if ($fixedErrorDiff === null) { - continue; - } - - $fixedFile = $error->getTraitFilePath() ?? $error->getFilePath(); - if (!is_file($fixedFile) || hash_file('sha256', $fixedFile) !== $fixedErrorDiff->originalHash) { - return false; + foreach ($error->getFixedErrorDiffs() as $fixedErrorDiff) { + if (!is_file($fixedErrorDiff->file) || hash_file('sha256', $fixedErrorDiff->file) !== $fixedErrorDiff->originalHash) { + return false; + } } } diff --git a/src/Analyser/Error.php b/src/Analyser/Error.php index 9d116266e4f..04c11790513 100644 --- a/src/Analyser/Error.php +++ b/src/Analyser/Error.php @@ -11,6 +11,8 @@ use ReturnTypeWillChange; use Throwable; use function array_key_exists; +use function array_map; +use function count; use function is_bool; use function sprintf; @@ -27,6 +29,7 @@ final class Error implements JsonSerializable * * @param class-string|null $nodeType * @param mixed[] $metadata + * @param list $fixedErrorDiffs one diff per fixed file * @param array $traitContexts */ public function __construct( @@ -41,7 +44,7 @@ public function __construct( private ?string $nodeType = null, private ?string $identifier = null, private array $metadata = [], - private ?FixedErrorDiff $fixedErrorDiff = null, + private array $fixedErrorDiffs = [], private array $traitContexts = [], ) { @@ -87,7 +90,7 @@ public function changeFilePath(string $newFilePath): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + $this->renameFixedFile($this->getFilePath(), $newFilePath), ); } @@ -105,7 +108,7 @@ public function changeTraitFilePath(string $newFilePath): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + $this->traitFilePath === null ? $this->fixedErrorDiffs : $this->renameFixedFile($this->traitFilePath, $newFilePath), $this->traitContexts, ); } @@ -128,7 +131,7 @@ public function removeTraitContext(): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + $this->fixedErrorDiffs, $this->traitContexts, ); } @@ -169,7 +172,7 @@ public function withTraitContexts(array $traitContexts): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + $this->fixedErrorDiffs, $traitContexts, ); } @@ -196,7 +199,7 @@ public function asReportedInTraitContext(string $contextFilePath): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + $this->fixedErrorDiffs, ); } @@ -222,7 +225,7 @@ public function transformPaths(callable $transformPath): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + array_map(static fn (FixedErrorDiff $diff): FixedErrorDiff => new FixedErrorDiff($transformPath($diff->file), $diff->originalHash, $diff->diff), $this->fixedErrorDiffs), $this->transformTraitContexts($transformPath), ); } @@ -265,7 +268,7 @@ public function withoutTip(): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + $this->fixedErrorDiffs, $this->traitContexts, ); } @@ -288,7 +291,7 @@ public function doNotIgnore(): self $this->nodeType, $this->identifier, $this->metadata, - $this->fixedErrorDiff, + $this->fixedErrorDiffs, $this->traitContexts, ); } @@ -311,7 +314,7 @@ public function withIdentifier(string $identifier): self $this->nodeType, $identifier, $this->metadata, - $this->fixedErrorDiff, + $this->fixedErrorDiffs, $this->traitContexts, ); } @@ -337,7 +340,7 @@ public function withMetadata(array $metadata): self $this->nodeType, $this->identifier, $metadata, - $this->fixedErrorDiff, + $this->fixedErrorDiffs, $this->traitContexts, ); } @@ -375,10 +378,34 @@ public function getMetadata(): array /** * @internal Experimental + * @deprecated Use getFixedErrorDiffs(), a fix can change several files. */ public function getFixedErrorDiff(): ?FixedErrorDiff { - return $this->fixedErrorDiff; + // one diff of a fix of several files would apply only a part of the fix + return count($this->fixedErrorDiffs) === 1 ? $this->fixedErrorDiffs[0] : null; + } + + /** + * The diffs are applied together or not at all. + * + * @internal Experimental + * @return list + */ + public function getFixedErrorDiffs(): array + { + return $this->fixedErrorDiffs; + } + + /** + * @return list + */ + private function renameFixedFile(string $oldFile, string $newFile): array + { + return array_map( + static fn (FixedErrorDiff $diff): FixedErrorDiff => $diff->file === $oldFile ? new FixedErrorDiff($newFile, $diff->originalHash, $diff->diff) : $diff, + $this->fixedErrorDiffs, + ); } /** @@ -388,13 +415,6 @@ public function getFixedErrorDiff(): ?FixedErrorDiff #[Override] public function jsonSerialize() { - $fixedErrorDiffHash = null; - $fixedErrorDiffDiff = null; - if ($this->fixedErrorDiff !== null) { - $fixedErrorDiffHash = $this->fixedErrorDiff->originalHash; - $fixedErrorDiffDiff = $this->fixedErrorDiff->diff; - } - return [ 'message' => $this->message, 'file' => $this->file, @@ -407,8 +427,7 @@ public function jsonSerialize() 'nodeType' => $this->nodeType, 'identifier' => $this->identifier, 'metadata' => $this->metadata, - 'fixedErrorDiffHash' => $fixedErrorDiffHash, - 'fixedErrorDiffDiff' => $fixedErrorDiffDiff, + 'fixedErrorDiffs' => array_map(static fn (FixedErrorDiff $diff): array => [$diff->file, $diff->originalHash, $diff->diff], $this->fixedErrorDiffs), 'traitContexts' => $this->traitContexts, ]; } @@ -418,9 +437,9 @@ public function jsonSerialize() */ public static function decode(array $json): self { - $fixedErrorDiff = null; - if ($json['fixedErrorDiffHash'] !== null && $json['fixedErrorDiffDiff'] !== null) { - $fixedErrorDiff = new FixedErrorDiff($json['fixedErrorDiffHash'], $json['fixedErrorDiffDiff']); + $fixedErrorDiffs = []; + foreach ($json['fixedErrorDiffs'] ?? [] as [$file, $hash, $diff]) { + $fixedErrorDiffs[] = new FixedErrorDiff($file, $hash, $diff); } return new self( @@ -435,7 +454,7 @@ public static function decode(array $json): self $json['nodeType'] ?? null, $json['identifier'] ?? null, $json['metadata'] ?? [], - $fixedErrorDiff, + $fixedErrorDiffs, $json['traitContexts'] ?? [], ); } @@ -457,7 +476,7 @@ public static function __set_state(array $properties): self $properties['nodeType'] ?? null, $properties['identifier'] ?? null, $properties['metadata'] ?? [], - $properties['fixedErrorDiff'] ?? null, + $properties['fixedErrorDiffs'] ?? [], $properties['traitContexts'] ?? [], ); } diff --git a/src/Analyser/FixedErrorDiff.php b/src/Analyser/FixedErrorDiff.php index af8755b2f88..d67fee2cafe 100644 --- a/src/Analyser/FixedErrorDiff.php +++ b/src/Analyser/FixedErrorDiff.php @@ -2,10 +2,14 @@ namespace PHPStan\Analyser; +/** + * A unified diff of one file that fixes an error, computed against the contents with $originalHash. + */ final class FixedErrorDiff { public function __construct( + public readonly string $file, public readonly string $originalHash, public readonly string $diff, ) @@ -17,7 +21,7 @@ public function __construct( */ public static function __set_state(array $properties): self { - return new self($properties['originalHash'], $properties['diff']); + return new self($properties['file'], $properties['originalHash'], $properties['diff']); } } diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index a5ec6a1f128..c93268df9ea 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -6,7 +6,6 @@ use PhpParser\Node; use PhpParser\Node\Stmt; use PhpParser\NodeTraverser; -use PhpParser\NodeVisitor; use PhpParser\NodeVisitor\CloningVisitor; use PhpParser\Parser; use PhpParser\Token; @@ -24,6 +23,7 @@ use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrors\TransformedRuleError; @@ -137,19 +137,31 @@ public function transform( $canBeIgnored = false; } - $fixedErrorDiff = null; + $fixedErrorDiffs = []; if ($ruleError instanceof FixableNodeRuleError) { - if ($ruleError->getOriginalNode() instanceof VirtualNode) { - throw new ShouldNotHappenException('Cannot fix virtual node'); + $fixesByFile = []; + foreach ($ruleError->getNodeFixes() as $nodeFix) { + if ($nodeFix->node instanceof VirtualNode) { + throw new ShouldNotHappenException('Cannot fix virtual node'); + } + + $fixesByFile[$nodeFix->file ?? $traitFilePath ?? $filePath][] = $nodeFix; } - $fixingFile = $traitFilePath ?? $filePath; - $fixedErrorDiff = $this->fix( - $fixingFile, - $fixingFile === $fileNodesFile ? $fileNodes : [], - $ruleError->getOriginalNode(), - $ruleError->getNewNodeCallable(), - ); + foreach ($fixesByFile as $fixingFile => $fixes) { + $fixedErrorDiff = $this->fix( + $fixingFile, + $fixingFile === $fileNodesFile ? $fileNodes : [], + $fixes, + ); + if ($fixedErrorDiff === null) { + // the changes are applied together or not at all + $fixedErrorDiffs = []; + break; + } + + $fixedErrorDiffs[] = $fixedErrorDiff; + } } return new Error( @@ -164,19 +176,20 @@ public function transform( get_class($node), $identifier, $metadata, - $fixedErrorDiff, + $fixedErrorDiffs, ); } /** * Without $fileNodes (errors of CollectedDataNode rules, errors transformed inside collectors, - * and errors pointing to another file with RuleErrorBuilder::file()), the file is parsed with the cached analysis parser. The rule has to take the node it fixes - * from the same parser so that ReplacingNodeVisitor finds it by identity. + * and fixes in another file), the file is parsed with the cached analysis parser. The rule has to take + * the nodes it fixes from the same parser so that ReplacingNodeVisitor finds them by identity. + * Returns null when some of the nodes cannot be fixed. * * @param Node\Stmt[] $fileNodes - * @param callable(Node): (Node|NodeVisitor::REMOVE_NODE) $newNodeCallable + * @param non-empty-list $fixes */ - private function fix(string $fixingFile, array $fileNodes, Node $originalNode, callable $newNodeCallable): ?FixedErrorDiff + private function fix(string $fixingFile, array $fileNodes, array $fixes): ?FixedErrorDiff { if ($fileNodes === []) { if (!is_file($fixingFile)) { @@ -203,7 +216,7 @@ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, c $visitors[] = $indentDetector; } $visitors[] = new CloningVisitor(); - $replacingVisitor = new ReplacingNodeVisitor($originalNode, $newNodeCallable); + $replacingVisitor = new ReplacingNodeVisitor($fixes); $visitors[] = $replacingVisitor; /** @var Stmt[] $newStmts */ @@ -222,7 +235,7 @@ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, c } } - if (!$replacingVisitor->isFound()) { + if (!$replacingVisitor->isComplete()) { return null; } @@ -231,7 +244,7 @@ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, c return null; } - return new FixedErrorDiff($parsedFile['hash'], $this->diff($parsedFile['code'], $newCode)); + return new FixedErrorDiff($fixingFile, $parsedFile['hash'], $this->diff($parsedFile['code'], $newCode)); } /** diff --git a/src/Command/AnalyseApplication.php b/src/Command/AnalyseApplication.php index db9f1d6e652..d9c223b153d 100644 --- a/src/Command/AnalyseApplication.php +++ b/src/Command/AnalyseApplication.php @@ -171,14 +171,14 @@ public function analyse( $fileSpecificErrors = $ignoredErrorHelperProcessedResult->getNotIgnoredErrors(); $notFileSpecificErrors = $ignoredErrorHelperProcessedResult->getOtherIgnoreMessages(); foreach ($ignoredErrorHelperProcessedResult->getIgnoredErrors() as [$ignoredError]) { - if ($ignoredError->getFixedErrorDiff() === null) { + if ($ignoredError->getFixedErrorDiffs() === []) { continue; } $fixableIgnoredErrors[] = $ignoredError; } foreach ($analyserResult->getLocallyIgnoredErrors() as $locallyIgnoredError) { - if ($locallyIgnoredError->getFixedErrorDiff() === null) { + if ($locallyIgnoredError->getFixedErrorDiffs() === []) { continue; } diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 991c3994b57..d1c9d4271c1 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -4,6 +4,7 @@ use OndraM\CiDetector\CiDetector; use Override; +use PHPStan\Analyser\Error; use PHPStan\Analyser\InternalError; use PHPStan\Command\ErrorFormatter\BaselineNeonErrorFormatter; use PHPStan\Command\ErrorFormatter\BaselinePhpErrorFormatter; @@ -20,7 +21,6 @@ use PHPStan\File\ParentDirectoryRelativePathHelper; use PHPStan\File\PathNotFoundException; use PHPStan\File\RelativePathHelper; -use PHPStan\Fixable\FileChangedException; use PHPStan\Fixable\Patcher; use PHPStan\Internal\AgentDetector; use PHPStan\Internal\BytesHelper; @@ -555,7 +555,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $fixableErrors = []; if ($fixReported) { foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - if ($fileSpecificError->getFixedErrorDiff() === null) { + if ($fileSpecificError->getFixedErrorDiffs() === []) { continue; } @@ -573,41 +573,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $inceptionResult->getStdOutput()->getStyle()->error('No fixable errors found'); $exitCode = 1; } else { - $skippedCount = 0; - $diffsByFile = []; - foreach ($fixableErrors as $fixableError) { - $fixFile = $fixableError->getFilePath(); - if ($fixableError->getTraitFilePath() !== null) { - $fixFile = $fixableError->getTraitFilePath(); - } - - if ($fixableError->getFixedErrorDiff() === null) { - throw new ShouldNotHappenException(); - } - - $diffsByFile[$fixFile][] = $fixableError->getFixedErrorDiff(); - } - $inceptionResult->getErrorOutput()->writeLineFormatted('Fixing errors...'); - $errorOutput->getStyle()->progressStart($fixableErrorsCount); - - $patcher = $container->getByType(Patcher::class); - foreach ($diffsByFile as $file => $diffs) { - $diffsCount = count($diffs); - try { - $patchResult = $patcher->applyDiffs(FileReader::read($file), $diffs); - $skippedCount += $patchResult['skippedCount']; - $errorOutput->getStyle()->progressAdvance($diffsCount); - } catch (FileChangedException) { - $skippedCount += $diffsCount; - $errorOutput->getStyle()->progressAdvance($diffsCount); - continue; - } - FileWriter::write($file, $patchResult['contents']); - } - - $errorOutput->getStyle()->progressFinish(); + $patchResult = $container->getByType(Patcher::class)->applyToFiles(array_map( + static fn (Error $error): array => $error->getFixedErrorDiffs(), + $fixableErrors, + )); + $skippedCount = $patchResult['skippedCount']; if ($skippedCount > 0) { $fixedCount = $fixableErrorsCount - $skippedCount; diff --git a/src/Command/ErrorFormatter/TableErrorFormatter.php b/src/Command/ErrorFormatter/TableErrorFormatter.php index 513ba27fc9a..508555837e0 100644 --- a/src/Command/ErrorFormatter/TableErrorFormatter.php +++ b/src/Command/ErrorFormatter/TableErrorFormatter.php @@ -98,7 +98,7 @@ public function formatErrors( $fileErrors = []; $fixableErrorsCount = 0; foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - if ($fileSpecificError->getFixedErrorDiff() !== null) { + if ($fileSpecificError->getFixedErrorDiffs() !== []) { $fixableErrorsCount++; } if (!isset($fileErrors[$fileSpecificError->getFile()])) { @@ -121,7 +121,7 @@ public function formatErrors( ) { $message = '' . OutputFormatter::escape($message) . ''; } - if ($error->getFixedErrorDiff() !== null) { + if ($error->getFixedErrorDiffs() !== []) { $message .= ' 🔧'; } if ($error->getIdentifier() !== null) { diff --git a/src/Fixable/FileChangedException.php b/src/Fixable/FileChangedException.php deleted file mode 100644 index 89eaf7ac6f0..00000000000 --- a/src/Fixable/FileChangedException.php +++ /dev/null @@ -1,10 +0,0 @@ - $contentsByFile current contents of the files the diffs change + * @param list> $diffGroups diffs of each error + * @return array{contents: array, appliedCount: int, skippedCount: int} contents of the files in $contentsByFile */ - public function applyDiffs(string $fileContents, array $diffs): array + public function apply(array $contentsByFile, array $diffGroups): array { - $fileHash = hash('sha256', $fileContents); - foreach ($diffs as $diff) { - if ($diff->originalHash !== $fileHash) { - throw new FileChangedException(); - } + $hashes = []; + foreach ($contentsByFile as $file => $contents) { + $hashes[$file] = hash('sha256', $contents); } - /** @var list}> $acceptedRuns sorted by start, non-overlapping */ + /** @var array}>> $acceptedRuns per file sorted by start, non-overlapping */ $acceptedRuns = []; + $appliedCount = 0; $skippedCount = 0; - foreach ($diffs as $diff) { - $insertions = []; - foreach (self::parseChangeRuns($diff->diff) as $run) { - $index = self::findInsertionIndex($acceptedRuns, $run); - if ($index === null) { + foreach ($diffGroups as $diffs) { + $insertionsByFile = []; + foreach ($diffs as $diff) { + if (!isset($hashes[$diff->file]) || $hashes[$diff->file] !== $diff->originalHash) { $skippedCount++; continue 2; } - if (isset($acceptedRuns[$index]) && $acceptedRuns[$index] === $run) { - // another diff makes the exact same change + + $fileRuns = $acceptedRuns[$diff->file] ?? []; + $insertions = []; + foreach (self::parseChangeRuns($diff->diff) as $run) { + $index = self::findInsertionIndex($fileRuns, $run); + if ($index === null) { + $skippedCount++; + continue 3; + } + if (isset($fileRuns[$index]) && $fileRuns[$index] === $run) { + // another error makes the exact same change + continue; + } + $insertions[] = [$index, $run]; + } + + $insertionsByFile[$diff->file] = $insertions; + } + + foreach ($insertionsByFile as $file => $insertions) { + $acceptedRuns[$file] ??= []; + + // runs of a single diff are ordered and non-overlapping, + // inserting from the last one keeps the earlier indexes valid + for ($i = count($insertions) - 1; $i >= 0; $i--) { + array_splice($acceptedRuns[$file], $insertions[$i][0], 0, [$insertions[$i][1]]); + } + } + $appliedCount++; + } + + $result = $contentsByFile; + foreach ($acceptedRuns as $file => $runs) { + $result[$file] = self::splice($contentsByFile[$file], $runs); + } + + return [ + 'contents' => $result, + 'appliedCount' => $appliedCount, + 'skippedCount' => $skippedCount, + ]; + } + + /** + * Applies the diffs to the files on disk and writes the changed files. + * + * @param list> $diffGroups diffs of each error + * @return array{changedFiles: list, appliedCount: int, skippedCount: int} + */ + public function applyToFiles(array $diffGroups): array + { + $contentsByFile = []; + foreach ($diffGroups as $diffs) { + foreach ($diffs as $diff) { + if (array_key_exists($diff->file, $contentsByFile) || !is_file($diff->file)) { continue; } - $insertions[] = [$index, $run]; + + $contentsByFile[$diff->file] = FileReader::read($diff->file); } + } - // runs of a single diff are ordered and non-overlapping, - // inserting from the last one keeps the earlier indexes valid - for ($i = count($insertions) - 1; $i >= 0; $i--) { - array_splice($acceptedRuns, $insertions[$i][0], 0, [$insertions[$i][1]]); + $result = $this->apply($contentsByFile, $diffGroups); + $changedFiles = []; + foreach ($result['contents'] as $file => $contents) { + if ($contents === $contentsByFile[$file]) { + continue; } + + FileWriter::write($file, $contents); + $changedFiles[] = $file; } + return [ + 'changedFiles' => $changedFiles, + 'appliedCount' => $result['appliedCount'], + 'skippedCount' => $result['skippedCount'], + ]; + } + + /** + * @param list}> $runs + */ + private static function splice(string $fileContents, array $runs): string + { $baseLines = self::splitStringByLines($fileContents); $result = []; $position = 0; - foreach ($acceptedRuns as [$start, $removedCount, $addedLines]) { + foreach ($runs as [$start, $removedCount, $addedLines]) { for (; $position < $start; $position++) { $result[] = $baseLines[$position]; } @@ -82,10 +158,7 @@ public function applyDiffs(string $fileContents, array $diffs): array $result[] = $baseLines[$position]; } - return [ - 'contents' => implode('', $result), - 'skippedCount' => $skippedCount, - ]; + return implode('', $result); } /** diff --git a/src/Fixable/ReplacingNodeVisitor.php b/src/Fixable/ReplacingNodeVisitor.php index b322a00823b..c9a33edd76f 100644 --- a/src/Fixable/ReplacingNodeVisitor.php +++ b/src/Fixable/ReplacingNodeVisitor.php @@ -7,40 +7,60 @@ use PhpParser\NodeVisitor; use PhpParser\NodeVisitorAbstract; use PHPStan\Node\VirtualNode; +use PHPStan\Rules\NodeFix; use PHPStan\ShouldNotHappenException; -use function in_array; +use SplObjectStorage; +use function count; use function is_array; +/** + * Applies the NodeFixes of one error to the nodes of one file. Runs after CloningVisitor in the same traversal. + */ final class ReplacingNodeVisitor extends NodeVisitorAbstract { - private bool $found = false; + /** @var SplObjectStorage> */ + private SplObjectStorage $callbacks; - private bool $originalNodeInArray = false; + /** @var SplObjectStorage original nodes in an array, those can be removed */ + private SplObjectStorage $removable; + + private int $appliedCount = 0; + + private bool $failed = false; /** - * @param callable(Node): (Node|NodeVisitor::REMOVE_NODE) $newNodeCallable + * @param non-empty-list $fixes */ - public function __construct(private Node $originalNode, private $newNodeCallable) + public function __construct(array $fixes) { + $this->callbacks = new SplObjectStorage(); + $this->removable = new SplObjectStorage(); + foreach ($fixes as $fix) { + $callbacks = $this->callbacks->contains($fix->node) ? $this->callbacks[$fix->node] : []; + $callbacks[] = $fix->callback; + $this->callbacks[$fix->node] = $callbacks; + } } /** * CloningVisitor has just cloned $node, its subnodes are still the original nodes. - * Only a node in an array can be removed. */ #[Override] public function enterNode(Node $node): ?Node { - if ($this->found || $this->originalNodeInArray) { - return null; - } - foreach ($node->getSubNodeNames() as $subNodeName) { $subNode = $node->$subNodeName; - if (is_array($subNode) && in_array($this->originalNode, $subNode, true)) { - $this->originalNodeInArray = true; - break; + if (!is_array($subNode)) { + continue; + } + + foreach ($subNode as $item) { + if (!$item instanceof Node || !$this->callbacks->contains($item)) { + continue; + } + + $this->removable[$item] = true; } } @@ -49,45 +69,43 @@ public function enterNode(Node $node): ?Node /** * The replacement happens in leaveNode() so that the callable receives a node - * whose children have already been cloned by CloningVisitor. That makes it - * possible to run both visitors in a single traversal. + * whose children have already been cloned and fixed. */ #[Override] public function leaveNode(Node $node): Node|int|null { - if ($this->found) { - return null; - } - $origNode = $node->getAttribute('origNode'); - if ($origNode !== $this->originalNode) { + if (!$origNode instanceof Node || !$this->callbacks->contains($origNode)) { return null; } - $callable = $this->newNodeCallable; - $newNode = $callable($node); - if ($newNode === NodeVisitor::REMOVE_NODE) { - if (!$this->originalNodeInArray) { - return null; + $this->appliedCount++; + $newNode = $node; + foreach ($this->callbacks[$origNode] as $callback) { + $newNode = $callback($newNode); + if ($newNode === NodeVisitor::REMOVE_NODE) { + if (!$this->removable->contains($origNode)) { + $this->failed = true; + return null; + } + + return NodeVisitor::REMOVE_NODE; } - $this->found = true; - - return NodeVisitor::REMOVE_NODE; - } - - if ($newNode instanceof VirtualNode) { - throw new ShouldNotHappenException('Cannot print VirtualNode.'); + if ($newNode instanceof VirtualNode) { + throw new ShouldNotHappenException('Cannot print VirtualNode.'); + } } - $this->found = true; - return $newNode; } - public function isFound(): bool + /** + * Whether every node was found and fixed. + */ + public function isComplete(): bool { - return $this->found; + return !$this->failed && $this->appliedCount === count($this->callbacks); } } diff --git a/src/Rules/FixableNodeRuleError.php b/src/Rules/FixableNodeRuleError.php index c67c7e07d36..4244f86a44a 100644 --- a/src/Rules/FixableNodeRuleError.php +++ b/src/Rules/FixableNodeRuleError.php @@ -2,15 +2,10 @@ namespace PHPStan\Rules; -use PhpParser\Node; -use PhpParser\NodeVisitor; - interface FixableNodeRuleError extends RuleError { - public function getOriginalNode(): Node; - - /** @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public function getNewNodeCallable(): callable; + /** @return non-empty-list */ + public function getNodeFixes(): array; } diff --git a/src/Rules/NodeFix.php b/src/Rules/NodeFix.php new file mode 100644 index 00000000000..dc8d273a54c --- /dev/null +++ b/src/Rules/NodeFix.php @@ -0,0 +1,26 @@ +line($error->getLine()); } if ($error instanceof FixableNodeRuleError) { - $builder->fixNode($error->getOriginalNode(), $error->getNewNodeCallable()); + foreach ($error->getNodeFixes() as $nodeFix) { + $builder->fixNode($nodeFix->node, $nodeFix->callback, $nodeFix->file); + } } $errors[] = $builder->build(); } diff --git a/src/Rules/RuleErrorBuilder.php b/src/Rules/RuleErrorBuilder.php index 64e7fd139d8..5f159e91437 100644 --- a/src/Rules/RuleErrorBuilder.php +++ b/src/Rules/RuleErrorBuilder.php @@ -123,14 +123,9 @@ public static function getRuleErrorTypes(): array FixableNodeRuleError::class, [ [ - 'originalNode', - '\PhpParser\Node', - '\PhpParser\Node', - ], - [ - 'newNodeCallable', - null, - 'callable(\PhpParser\Node): (\PhpParser\Node|\PhpParser\NodeVisitor::REMOVE_NODE)', + 'nodeFixes', + 'array', + 'non-empty-list<\PHPStan\Rules\NodeFix>', ], ], ], @@ -320,37 +315,39 @@ public function nonIgnorable(): self } /** + * Every call adds a change to the fix of the error. The changes are applied together or not at all. + * Several changes of the same node are applied in the order they were added. + * * @internal Experimental * @template TNode of Node * @param TNode $node * @param callable(TNode): (Node|NodeVisitor::REMOVE_NODE) $cb returning NodeVisitor::REMOVE_NODE works like removeNode() + * @param string|null $file the file of the node when it is not the file of the error * @phpstan-this-out self * @return self */ - public function fixNode(Node $node, callable $cb): self + public function fixNode(Node $node, callable $cb, ?string $file = null): self { - $this->properties['originalNode'] = $node; - $this->properties['newNodeCallable'] = $cb; + // ReplacingNodeVisitor passes the callback only a clone of $node + /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) $cb */ + $this->properties['nodeFixes'][] = new NodeFix($node, $cb, $file); $this->type |= self::TYPE_FIXABLE_NODE; return $this; } /** - * Fixes the error by removing the node. Only a node in an array, like a statement, - * an argument, or an array item, can be removed. Otherwise the error is not fixable. + * Adds removing the node to the fix of the error, see fixNode(). Only a node in an array, + * like a statement, an argument, or an array item, can be removed. Otherwise the error is not fixable. * * @internal Experimental + * @param string|null $file the file of the node when it is not the file of the error * @phpstan-this-out self * @return self */ - public function removeNode(Node $node): self + public function removeNode(Node $node, ?string $file = null): self { - $this->properties['originalNode'] = $node; - $this->properties['newNodeCallable'] = static fn (): int => NodeVisitor::REMOVE_NODE; - $this->type |= self::TYPE_FIXABLE_NODE; - - return $this; + return $this->fixNode($node, static fn (): int => NodeVisitor::REMOVE_NODE, $file); } /** diff --git a/src/Rules/RuleErrors/RuleError129.php b/src/Rules/RuleErrors/RuleError129.php index 65e6e7e707d..046e9dbd1a7 100644 --- a/src/Rules/RuleErrors/RuleError129.php +++ b/src/Rules/RuleErrors/RuleError129.php @@ -2,9 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -15,27 +14,20 @@ final class RuleError129 implements RuleError, FixableNodeRuleError public string $message; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { return $this->message; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError131.php b/src/Rules/RuleErrors/RuleError131.php index 9e05ac02e3b..a5a5b44897c 100644 --- a/src/Rules/RuleErrors/RuleError131.php +++ b/src/Rules/RuleErrors/RuleError131.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -18,10 +17,8 @@ final class RuleError131 implements RuleError, LineRuleError, FixableNodeRuleErr public int $line; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -33,17 +30,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError133.php b/src/Rules/RuleErrors/RuleError133.php index f13cddd71aa..f13e6157a6c 100644 --- a/src/Rules/RuleErrors/RuleError133.php +++ b/src/Rules/RuleErrors/RuleError133.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -20,10 +19,8 @@ final class RuleError133 implements RuleError, FileRuleError, FixableNodeRuleErr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -40,17 +37,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError135.php b/src/Rules/RuleErrors/RuleError135.php index faf9f12aaf6..6bf76168a6e 100644 --- a/src/Rules/RuleErrors/RuleError135.php +++ b/src/Rules/RuleErrors/RuleError135.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -23,10 +22,8 @@ final class RuleError135 implements RuleError, LineRuleError, FileRuleError, Fix public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -48,17 +45,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError137.php b/src/Rules/RuleErrors/RuleError137.php index 7febf76e634..7e6fd73d2d5 100644 --- a/src/Rules/RuleErrors/RuleError137.php +++ b/src/Rules/RuleErrors/RuleError137.php @@ -2,9 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -18,10 +17,8 @@ final class RuleError137 implements RuleError, TipRuleError, FixableNodeRuleErro public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -33,17 +30,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError139.php b/src/Rules/RuleErrors/RuleError139.php index 0546fb6b4ca..fc85c3859f6 100644 --- a/src/Rules/RuleErrors/RuleError139.php +++ b/src/Rules/RuleErrors/RuleError139.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -21,10 +20,8 @@ final class RuleError139 implements RuleError, LineRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -41,17 +38,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError141.php b/src/Rules/RuleErrors/RuleError141.php index c0cb0c6b63e..42c3151c243 100644 --- a/src/Rules/RuleErrors/RuleError141.php +++ b/src/Rules/RuleErrors/RuleError141.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +22,8 @@ final class RuleError141 implements RuleError, FileRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -48,17 +45,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError143.php b/src/Rules/RuleErrors/RuleError143.php index 77ac55405e8..6b5b5442ba1 100644 --- a/src/Rules/RuleErrors/RuleError143.php +++ b/src/Rules/RuleErrors/RuleError143.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +25,8 @@ final class RuleError143 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -56,17 +53,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError145.php b/src/Rules/RuleErrors/RuleError145.php index 87383183aa4..6c87a27fcea 100644 --- a/src/Rules/RuleErrors/RuleError145.php +++ b/src/Rules/RuleErrors/RuleError145.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -18,10 +17,8 @@ final class RuleError145 implements RuleError, IdentifierRuleError, FixableNodeR public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -33,17 +30,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError147.php b/src/Rules/RuleErrors/RuleError147.php index e756d3f2e12..a578aeaa99b 100644 --- a/src/Rules/RuleErrors/RuleError147.php +++ b/src/Rules/RuleErrors/RuleError147.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -21,10 +20,8 @@ final class RuleError147 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -41,17 +38,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError149.php b/src/Rules/RuleErrors/RuleError149.php index d5c0042a8a4..14a39aeff80 100644 --- a/src/Rules/RuleErrors/RuleError149.php +++ b/src/Rules/RuleErrors/RuleError149.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -23,10 +22,8 @@ final class RuleError149 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -48,17 +45,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError151.php b/src/Rules/RuleErrors/RuleError151.php index c316f1b243c..2a719c715f8 100644 --- a/src/Rules/RuleErrors/RuleError151.php +++ b/src/Rules/RuleErrors/RuleError151.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -26,10 +25,8 @@ final class RuleError151 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -56,17 +53,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError153.php b/src/Rules/RuleErrors/RuleError153.php index d56a553fb21..e34eeab3d94 100644 --- a/src/Rules/RuleErrors/RuleError153.php +++ b/src/Rules/RuleErrors/RuleError153.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -21,10 +20,8 @@ final class RuleError153 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -41,17 +38,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError155.php b/src/Rules/RuleErrors/RuleError155.php index abfef5873a1..f75dca0a9d6 100644 --- a/src/Rules/RuleErrors/RuleError155.php +++ b/src/Rules/RuleErrors/RuleError155.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -24,10 +23,8 @@ final class RuleError155 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -49,17 +46,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError157.php b/src/Rules/RuleErrors/RuleError157.php index 7d64e9a3a0c..7356ab049c6 100644 --- a/src/Rules/RuleErrors/RuleError157.php +++ b/src/Rules/RuleErrors/RuleError157.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +25,8 @@ final class RuleError157 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -56,17 +53,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError159.php b/src/Rules/RuleErrors/RuleError159.php index 069fdae4b6c..3db8d021fdd 100644 --- a/src/Rules/RuleErrors/RuleError159.php +++ b/src/Rules/RuleErrors/RuleError159.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -29,10 +28,8 @@ final class RuleError159 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -64,17 +61,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError161.php b/src/Rules/RuleErrors/RuleError161.php index c2323c85a8c..1d47ef9e1be 100644 --- a/src/Rules/RuleErrors/RuleError161.php +++ b/src/Rules/RuleErrors/RuleError161.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -19,10 +18,8 @@ final class RuleError161 implements RuleError, MetadataRuleError, FixableNodeRul /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -37,17 +34,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError163.php b/src/Rules/RuleErrors/RuleError163.php index 95700eacfbf..7d88b27a85d 100644 --- a/src/Rules/RuleErrors/RuleError163.php +++ b/src/Rules/RuleErrors/RuleError163.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -22,10 +21,8 @@ final class RuleError163 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -45,17 +42,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError165.php b/src/Rules/RuleErrors/RuleError165.php index 175bc53ea71..e62ecb64977 100644 --- a/src/Rules/RuleErrors/RuleError165.php +++ b/src/Rules/RuleErrors/RuleError165.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -24,10 +23,8 @@ final class RuleError165 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -52,17 +49,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError167.php b/src/Rules/RuleErrors/RuleError167.php index 5df04c815e7..11fce81716d 100644 --- a/src/Rules/RuleErrors/RuleError167.php +++ b/src/Rules/RuleErrors/RuleError167.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -27,10 +26,8 @@ final class RuleError167 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -60,17 +57,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError169.php b/src/Rules/RuleErrors/RuleError169.php index 7f1ee411552..87da8b7579f 100644 --- a/src/Rules/RuleErrors/RuleError169.php +++ b/src/Rules/RuleErrors/RuleError169.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +21,8 @@ final class RuleError169 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -45,17 +42,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError171.php b/src/Rules/RuleErrors/RuleError171.php index 08c6509b6e1..6782baf324c 100644 --- a/src/Rules/RuleErrors/RuleError171.php +++ b/src/Rules/RuleErrors/RuleError171.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -25,10 +24,8 @@ final class RuleError171 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -53,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError173.php b/src/Rules/RuleErrors/RuleError173.php index 6b832dd7324..f24b785db97 100644 --- a/src/Rules/RuleErrors/RuleError173.php +++ b/src/Rules/RuleErrors/RuleError173.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -27,10 +26,8 @@ final class RuleError173 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -60,17 +57,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError175.php b/src/Rules/RuleErrors/RuleError175.php index 3c8a0c1f122..6c36d9f2e72 100644 --- a/src/Rules/RuleErrors/RuleError175.php +++ b/src/Rules/RuleErrors/RuleError175.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -30,10 +29,8 @@ final class RuleError175 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -68,17 +65,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError177.php b/src/Rules/RuleErrors/RuleError177.php index 6d2479bb0a6..4b533d9704d 100644 --- a/src/Rules/RuleErrors/RuleError177.php +++ b/src/Rules/RuleErrors/RuleError177.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -22,10 +21,8 @@ final class RuleError177 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -45,17 +42,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError179.php b/src/Rules/RuleErrors/RuleError179.php index 4c55fd3d97b..bb155fc9f8a 100644 --- a/src/Rules/RuleErrors/RuleError179.php +++ b/src/Rules/RuleErrors/RuleError179.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -25,10 +24,8 @@ final class RuleError179 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -53,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError181.php b/src/Rules/RuleErrors/RuleError181.php index 0aba9d9a174..93863a58fd7 100644 --- a/src/Rules/RuleErrors/RuleError181.php +++ b/src/Rules/RuleErrors/RuleError181.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -27,10 +26,8 @@ final class RuleError181 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -60,17 +57,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError183.php b/src/Rules/RuleErrors/RuleError183.php index 436a4fb40c8..0cee596d2ed 100644 --- a/src/Rules/RuleErrors/RuleError183.php +++ b/src/Rules/RuleErrors/RuleError183.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -30,10 +29,8 @@ final class RuleError183 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -68,17 +65,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError185.php b/src/Rules/RuleErrors/RuleError185.php index 3871100e7bd..7a9fefbb890 100644 --- a/src/Rules/RuleErrors/RuleError185.php +++ b/src/Rules/RuleErrors/RuleError185.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -25,10 +24,8 @@ final class RuleError185 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -53,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError187.php b/src/Rules/RuleErrors/RuleError187.php index fa8c1cb282b..d2f0b1fb2fb 100644 --- a/src/Rules/RuleErrors/RuleError187.php +++ b/src/Rules/RuleErrors/RuleError187.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -28,10 +27,8 @@ final class RuleError187 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -61,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError189.php b/src/Rules/RuleErrors/RuleError189.php index d102c3df536..0469c572a27 100644 --- a/src/Rules/RuleErrors/RuleError189.php +++ b/src/Rules/RuleErrors/RuleError189.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -30,10 +29,8 @@ final class RuleError189 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -68,17 +65,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError191.php b/src/Rules/RuleErrors/RuleError191.php index 4d4f77cfdd2..bbc51f0df35 100644 --- a/src/Rules/RuleErrors/RuleError191.php +++ b/src/Rules/RuleErrors/RuleError191.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -33,10 +32,8 @@ final class RuleError191 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -76,17 +73,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError193.php b/src/Rules/RuleErrors/RuleError193.php index c4405ed8966..61ead7b5bfc 100644 --- a/src/Rules/RuleErrors/RuleError193.php +++ b/src/Rules/RuleErrors/RuleError193.php @@ -2,9 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -16,27 +15,20 @@ final class RuleError193 implements RuleError, NonIgnorableRuleError, FixableNod public string $message; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { return $this->message; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError195.php b/src/Rules/RuleErrors/RuleError195.php index 679b6cea533..10ea9632f40 100644 --- a/src/Rules/RuleErrors/RuleError195.php +++ b/src/Rules/RuleErrors/RuleError195.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -19,10 +18,8 @@ final class RuleError195 implements RuleError, LineRuleError, NonIgnorableRuleEr public int $line; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -34,17 +31,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError197.php b/src/Rules/RuleErrors/RuleError197.php index 0e82d481596..084a5f3e3e2 100644 --- a/src/Rules/RuleErrors/RuleError197.php +++ b/src/Rules/RuleErrors/RuleError197.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -21,10 +20,8 @@ final class RuleError197 implements RuleError, FileRuleError, NonIgnorableRuleEr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -41,17 +38,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError199.php b/src/Rules/RuleErrors/RuleError199.php index f052cc48f9e..7bc6d8791df 100644 --- a/src/Rules/RuleErrors/RuleError199.php +++ b/src/Rules/RuleErrors/RuleError199.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -24,10 +23,8 @@ final class RuleError199 implements RuleError, LineRuleError, FileRuleError, Non public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -49,17 +46,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError201.php b/src/Rules/RuleErrors/RuleError201.php index d184fd468c4..97dd1f05b5f 100644 --- a/src/Rules/RuleErrors/RuleError201.php +++ b/src/Rules/RuleErrors/RuleError201.php @@ -2,9 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -19,10 +18,8 @@ final class RuleError201 implements RuleError, TipRuleError, NonIgnorableRuleErr public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -34,17 +31,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError203.php b/src/Rules/RuleErrors/RuleError203.php index ad5c521f8ac..3aa56ecce08 100644 --- a/src/Rules/RuleErrors/RuleError203.php +++ b/src/Rules/RuleErrors/RuleError203.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +21,8 @@ final class RuleError203 implements RuleError, LineRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -42,17 +39,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError205.php b/src/Rules/RuleErrors/RuleError205.php index 57c7380ec0e..6c8c91dd0fc 100644 --- a/src/Rules/RuleErrors/RuleError205.php +++ b/src/Rules/RuleErrors/RuleError205.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -24,10 +23,8 @@ final class RuleError205 implements RuleError, FileRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -49,17 +46,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError207.php b/src/Rules/RuleErrors/RuleError207.php index 83b1bb52274..7430c5826e1 100644 --- a/src/Rules/RuleErrors/RuleError207.php +++ b/src/Rules/RuleErrors/RuleError207.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -27,10 +26,8 @@ final class RuleError207 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -57,17 +54,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError209.php b/src/Rules/RuleErrors/RuleError209.php index bb04d668cc1..31b7bce3367 100644 --- a/src/Rules/RuleErrors/RuleError209.php +++ b/src/Rules/RuleErrors/RuleError209.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -19,10 +18,8 @@ final class RuleError209 implements RuleError, IdentifierRuleError, NonIgnorable public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -34,17 +31,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError211.php b/src/Rules/RuleErrors/RuleError211.php index 3322302f802..fe5ae8c0d59 100644 --- a/src/Rules/RuleErrors/RuleError211.php +++ b/src/Rules/RuleErrors/RuleError211.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -22,10 +21,8 @@ final class RuleError211 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -42,17 +39,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError213.php b/src/Rules/RuleErrors/RuleError213.php index 7d34fa66862..de954e9ef18 100644 --- a/src/Rules/RuleErrors/RuleError213.php +++ b/src/Rules/RuleErrors/RuleError213.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -24,10 +23,8 @@ final class RuleError213 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -49,17 +46,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError215.php b/src/Rules/RuleErrors/RuleError215.php index cf9dd95da35..51be06114e1 100644 --- a/src/Rules/RuleErrors/RuleError215.php +++ b/src/Rules/RuleErrors/RuleError215.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -27,10 +26,8 @@ final class RuleError215 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -57,17 +54,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError217.php b/src/Rules/RuleErrors/RuleError217.php index 800301752c7..896cac199d4 100644 --- a/src/Rules/RuleErrors/RuleError217.php +++ b/src/Rules/RuleErrors/RuleError217.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +21,8 @@ final class RuleError217 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -42,17 +39,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError219.php b/src/Rules/RuleErrors/RuleError219.php index 9a843f5c8b5..fbd9f427308 100644 --- a/src/Rules/RuleErrors/RuleError219.php +++ b/src/Rules/RuleErrors/RuleError219.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -25,10 +24,8 @@ final class RuleError219 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -50,17 +47,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError221.php b/src/Rules/RuleErrors/RuleError221.php index 29cb6ad61d1..29ca8a4000e 100644 --- a/src/Rules/RuleErrors/RuleError221.php +++ b/src/Rules/RuleErrors/RuleError221.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -27,10 +26,8 @@ final class RuleError221 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -57,17 +54,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError223.php b/src/Rules/RuleErrors/RuleError223.php index 3fd068cdb67..5fbaca86e56 100644 --- a/src/Rules/RuleErrors/RuleError223.php +++ b/src/Rules/RuleErrors/RuleError223.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -30,10 +29,8 @@ final class RuleError223 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -65,17 +62,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError225.php b/src/Rules/RuleErrors/RuleError225.php index 14cf2f79fc7..8ae53206b26 100644 --- a/src/Rules/RuleErrors/RuleError225.php +++ b/src/Rules/RuleErrors/RuleError225.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -20,10 +19,8 @@ final class RuleError225 implements RuleError, MetadataRuleError, NonIgnorableRu /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -38,17 +35,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError227.php b/src/Rules/RuleErrors/RuleError227.php index 5036c9b1e08..83bc7c1e5aa 100644 --- a/src/Rules/RuleErrors/RuleError227.php +++ b/src/Rules/RuleErrors/RuleError227.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -23,10 +22,8 @@ final class RuleError227 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -46,17 +43,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError229.php b/src/Rules/RuleErrors/RuleError229.php index 05c124f8a7b..c168e20470e 100644 --- a/src/Rules/RuleErrors/RuleError229.php +++ b/src/Rules/RuleErrors/RuleError229.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -25,10 +24,8 @@ final class RuleError229 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -53,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError231.php b/src/Rules/RuleErrors/RuleError231.php index 97e7e150125..9277017490c 100644 --- a/src/Rules/RuleErrors/RuleError231.php +++ b/src/Rules/RuleErrors/RuleError231.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -28,10 +27,8 @@ final class RuleError231 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -61,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError233.php b/src/Rules/RuleErrors/RuleError233.php index e6c167e4fdd..c3d3be1d9c4 100644 --- a/src/Rules/RuleErrors/RuleError233.php +++ b/src/Rules/RuleErrors/RuleError233.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +22,8 @@ final class RuleError233 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -46,17 +43,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError235.php b/src/Rules/RuleErrors/RuleError235.php index d048a5c812b..d50acf5ccb5 100644 --- a/src/Rules/RuleErrors/RuleError235.php +++ b/src/Rules/RuleErrors/RuleError235.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +25,8 @@ final class RuleError235 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -54,17 +51,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError237.php b/src/Rules/RuleErrors/RuleError237.php index 4a35b871fa9..8a638eda137 100644 --- a/src/Rules/RuleErrors/RuleError237.php +++ b/src/Rules/RuleErrors/RuleError237.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -28,10 +27,8 @@ final class RuleError237 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -61,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError239.php b/src/Rules/RuleErrors/RuleError239.php index a47b331e446..f56a1a38804 100644 --- a/src/Rules/RuleErrors/RuleError239.php +++ b/src/Rules/RuleErrors/RuleError239.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -31,10 +30,8 @@ final class RuleError239 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -69,17 +66,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError241.php b/src/Rules/RuleErrors/RuleError241.php index 41f04fcd5db..029871acba0 100644 --- a/src/Rules/RuleErrors/RuleError241.php +++ b/src/Rules/RuleErrors/RuleError241.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -23,10 +22,8 @@ final class RuleError241 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -46,17 +43,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError243.php b/src/Rules/RuleErrors/RuleError243.php index a807969d748..2d8a7946c89 100644 --- a/src/Rules/RuleErrors/RuleError243.php +++ b/src/Rules/RuleErrors/RuleError243.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -26,10 +25,8 @@ final class RuleError243 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -54,17 +51,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError245.php b/src/Rules/RuleErrors/RuleError245.php index fbdd133d94d..24fac503e76 100644 --- a/src/Rules/RuleErrors/RuleError245.php +++ b/src/Rules/RuleErrors/RuleError245.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -28,10 +27,8 @@ final class RuleError245 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -61,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError247.php b/src/Rules/RuleErrors/RuleError247.php index 3cff5415b6c..f030c5dfa9d 100644 --- a/src/Rules/RuleErrors/RuleError247.php +++ b/src/Rules/RuleErrors/RuleError247.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -31,10 +30,8 @@ final class RuleError247 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -69,17 +66,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError249.php b/src/Rules/RuleErrors/RuleError249.php index a27187076e5..93fc5e3cdd6 100644 --- a/src/Rules/RuleErrors/RuleError249.php +++ b/src/Rules/RuleErrors/RuleError249.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +25,8 @@ final class RuleError249 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -54,17 +51,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError251.php b/src/Rules/RuleErrors/RuleError251.php index cb503180209..660013fec41 100644 --- a/src/Rules/RuleErrors/RuleError251.php +++ b/src/Rules/RuleErrors/RuleError251.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -29,10 +28,8 @@ final class RuleError251 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -62,17 +59,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError253.php b/src/Rules/RuleErrors/RuleError253.php index fc09ead52af..51cc012e2ab 100644 --- a/src/Rules/RuleErrors/RuleError253.php +++ b/src/Rules/RuleErrors/RuleError253.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -31,10 +30,8 @@ final class RuleError253 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -69,17 +66,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError255.php b/src/Rules/RuleErrors/RuleError255.php index d1f577ec92a..b8bf2c5bbc6 100644 --- a/src/Rules/RuleErrors/RuleError255.php +++ b/src/Rules/RuleErrors/RuleError255.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -34,10 +33,8 @@ final class RuleError255 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -77,17 +74,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } } diff --git a/src/Rules/RuleErrors/RuleError385.php b/src/Rules/RuleErrors/RuleError385.php index 8936e193062..ce50b42aa32 100644 --- a/src/Rules/RuleErrors/RuleError385.php +++ b/src/Rules/RuleErrors/RuleError385.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -16,10 +15,8 @@ final class RuleError385 implements RuleError, FixableNodeRuleError, FileDepende public string $message; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -29,17 +26,12 @@ public function getMessage(): string return $this->message; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError387.php b/src/Rules/RuleErrors/RuleError387.php index 7a14109a605..e56c2a7cedc 100644 --- a/src/Rules/RuleErrors/RuleError387.php +++ b/src/Rules/RuleErrors/RuleError387.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -19,10 +18,8 @@ final class RuleError387 implements RuleError, LineRuleError, FixableNodeRuleErr public int $line; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -37,17 +34,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError389.php b/src/Rules/RuleErrors/RuleError389.php index 92971406a69..f48e60781af 100644 --- a/src/Rules/RuleErrors/RuleError389.php +++ b/src/Rules/RuleErrors/RuleError389.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -21,10 +20,8 @@ final class RuleError389 implements RuleError, FileRuleError, FixableNodeRuleErr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -44,17 +41,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError391.php b/src/Rules/RuleErrors/RuleError391.php index c365458e8b8..286726ae123 100644 --- a/src/Rules/RuleErrors/RuleError391.php +++ b/src/Rules/RuleErrors/RuleError391.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -24,10 +23,8 @@ final class RuleError391 implements RuleError, LineRuleError, FileRuleError, Fix public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -52,17 +49,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError393.php b/src/Rules/RuleErrors/RuleError393.php index ea075351496..750c7486fb9 100644 --- a/src/Rules/RuleErrors/RuleError393.php +++ b/src/Rules/RuleErrors/RuleError393.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -19,10 +18,8 @@ final class RuleError393 implements RuleError, TipRuleError, FixableNodeRuleErro public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -37,17 +34,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError395.php b/src/Rules/RuleErrors/RuleError395.php index e58aa3a6df6..1c5097476bc 100644 --- a/src/Rules/RuleErrors/RuleError395.php +++ b/src/Rules/RuleErrors/RuleError395.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +21,8 @@ final class RuleError395 implements RuleError, LineRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -45,17 +42,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError397.php b/src/Rules/RuleErrors/RuleError397.php index 8e21ad0d090..c52d5986aed 100644 --- a/src/Rules/RuleErrors/RuleError397.php +++ b/src/Rules/RuleErrors/RuleError397.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -24,10 +23,8 @@ final class RuleError397 implements RuleError, FileRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -52,17 +49,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError399.php b/src/Rules/RuleErrors/RuleError399.php index 9042ba9bc2d..4be9084f0bc 100644 --- a/src/Rules/RuleErrors/RuleError399.php +++ b/src/Rules/RuleErrors/RuleError399.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -27,10 +26,8 @@ final class RuleError399 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -60,17 +57,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError401.php b/src/Rules/RuleErrors/RuleError401.php index c3c0ac00c70..b6d681fb363 100644 --- a/src/Rules/RuleErrors/RuleError401.php +++ b/src/Rules/RuleErrors/RuleError401.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -19,10 +18,8 @@ final class RuleError401 implements RuleError, IdentifierRuleError, FixableNodeR public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -37,17 +34,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError403.php b/src/Rules/RuleErrors/RuleError403.php index 6e85c90fa5c..062658d2392 100644 --- a/src/Rules/RuleErrors/RuleError403.php +++ b/src/Rules/RuleErrors/RuleError403.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -22,10 +21,8 @@ final class RuleError403 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -45,17 +42,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError405.php b/src/Rules/RuleErrors/RuleError405.php index b870e12b6d6..fbd2379add8 100644 --- a/src/Rules/RuleErrors/RuleError405.php +++ b/src/Rules/RuleErrors/RuleError405.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -24,10 +23,8 @@ final class RuleError405 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -52,17 +49,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError407.php b/src/Rules/RuleErrors/RuleError407.php index 2c22d1f4e3f..97b05d1386f 100644 --- a/src/Rules/RuleErrors/RuleError407.php +++ b/src/Rules/RuleErrors/RuleError407.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -27,10 +26,8 @@ final class RuleError407 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -60,17 +57,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError409.php b/src/Rules/RuleErrors/RuleError409.php index 23d23fca33c..c00c00d6c9e 100644 --- a/src/Rules/RuleErrors/RuleError409.php +++ b/src/Rules/RuleErrors/RuleError409.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +21,8 @@ final class RuleError409 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -45,17 +42,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError411.php b/src/Rules/RuleErrors/RuleError411.php index 297a329a032..e81f89b0934 100644 --- a/src/Rules/RuleErrors/RuleError411.php +++ b/src/Rules/RuleErrors/RuleError411.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -25,10 +24,8 @@ final class RuleError411 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -53,17 +50,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError413.php b/src/Rules/RuleErrors/RuleError413.php index 2174f9941e5..2dc52407995 100644 --- a/src/Rules/RuleErrors/RuleError413.php +++ b/src/Rules/RuleErrors/RuleError413.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -27,10 +26,8 @@ final class RuleError413 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -60,17 +57,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError415.php b/src/Rules/RuleErrors/RuleError415.php index 06ee7b9d26f..a34fa3b5b0f 100644 --- a/src/Rules/RuleErrors/RuleError415.php +++ b/src/Rules/RuleErrors/RuleError415.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -30,10 +29,8 @@ final class RuleError415 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -68,17 +65,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError417.php b/src/Rules/RuleErrors/RuleError417.php index 8a7960568b8..90b68b0fdd8 100644 --- a/src/Rules/RuleErrors/RuleError417.php +++ b/src/Rules/RuleErrors/RuleError417.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -20,10 +19,8 @@ final class RuleError417 implements RuleError, MetadataRuleError, FixableNodeRul /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -41,17 +38,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError419.php b/src/Rules/RuleErrors/RuleError419.php index 6397e39aced..0ecfe959443 100644 --- a/src/Rules/RuleErrors/RuleError419.php +++ b/src/Rules/RuleErrors/RuleError419.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -23,10 +22,8 @@ final class RuleError419 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -49,17 +46,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError421.php b/src/Rules/RuleErrors/RuleError421.php index 93902bdd669..d3b28b75fb4 100644 --- a/src/Rules/RuleErrors/RuleError421.php +++ b/src/Rules/RuleErrors/RuleError421.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -25,10 +24,8 @@ final class RuleError421 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -56,17 +53,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError423.php b/src/Rules/RuleErrors/RuleError423.php index b2fbff75f15..176523a3dde 100644 --- a/src/Rules/RuleErrors/RuleError423.php +++ b/src/Rules/RuleErrors/RuleError423.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -28,10 +27,8 @@ final class RuleError423 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -64,17 +61,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError425.php b/src/Rules/RuleErrors/RuleError425.php index 1b20b2e0312..24cabb6a190 100644 --- a/src/Rules/RuleErrors/RuleError425.php +++ b/src/Rules/RuleErrors/RuleError425.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +22,8 @@ final class RuleError425 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -49,17 +46,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError427.php b/src/Rules/RuleErrors/RuleError427.php index 3fa04538ca5..41d442e175c 100644 --- a/src/Rules/RuleErrors/RuleError427.php +++ b/src/Rules/RuleErrors/RuleError427.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +25,8 @@ final class RuleError427 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -57,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError429.php b/src/Rules/RuleErrors/RuleError429.php index 704dcd73175..b9c0cfde238 100644 --- a/src/Rules/RuleErrors/RuleError429.php +++ b/src/Rules/RuleErrors/RuleError429.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -28,10 +27,8 @@ final class RuleError429 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -64,17 +61,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError431.php b/src/Rules/RuleErrors/RuleError431.php index f0893273022..e087e558321 100644 --- a/src/Rules/RuleErrors/RuleError431.php +++ b/src/Rules/RuleErrors/RuleError431.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -31,10 +30,8 @@ final class RuleError431 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -72,17 +69,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError433.php b/src/Rules/RuleErrors/RuleError433.php index e7decd0764a..6b20bd67392 100644 --- a/src/Rules/RuleErrors/RuleError433.php +++ b/src/Rules/RuleErrors/RuleError433.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -23,10 +22,8 @@ final class RuleError433 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -49,17 +46,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError435.php b/src/Rules/RuleErrors/RuleError435.php index a61631852e4..043626532e5 100644 --- a/src/Rules/RuleErrors/RuleError435.php +++ b/src/Rules/RuleErrors/RuleError435.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -26,10 +25,8 @@ final class RuleError435 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -57,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError437.php b/src/Rules/RuleErrors/RuleError437.php index dfd1e1630ed..1f899bc07d4 100644 --- a/src/Rules/RuleErrors/RuleError437.php +++ b/src/Rules/RuleErrors/RuleError437.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -28,10 +27,8 @@ final class RuleError437 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -64,17 +61,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError439.php b/src/Rules/RuleErrors/RuleError439.php index a2c9da6fa0a..8a3beef3da4 100644 --- a/src/Rules/RuleErrors/RuleError439.php +++ b/src/Rules/RuleErrors/RuleError439.php @@ -2,14 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -31,10 +30,8 @@ final class RuleError439 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -72,17 +69,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError441.php b/src/Rules/RuleErrors/RuleError441.php index b8e59978545..7abb7b7baee 100644 --- a/src/Rules/RuleErrors/RuleError441.php +++ b/src/Rules/RuleErrors/RuleError441.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +25,8 @@ final class RuleError441 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -57,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError443.php b/src/Rules/RuleErrors/RuleError443.php index 0176abfa3c7..3d241d34a0f 100644 --- a/src/Rules/RuleErrors/RuleError443.php +++ b/src/Rules/RuleErrors/RuleError443.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -29,10 +28,8 @@ final class RuleError443 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -65,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError445.php b/src/Rules/RuleErrors/RuleError445.php index 6438d8e6e94..5606b774f32 100644 --- a/src/Rules/RuleErrors/RuleError445.php +++ b/src/Rules/RuleErrors/RuleError445.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -31,10 +30,8 @@ final class RuleError445 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -72,17 +69,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError447.php b/src/Rules/RuleErrors/RuleError447.php index dc0e7b27dbd..5100c91f309 100644 --- a/src/Rules/RuleErrors/RuleError447.php +++ b/src/Rules/RuleErrors/RuleError447.php @@ -2,14 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -34,10 +33,8 @@ final class RuleError447 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -80,17 +77,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError449.php b/src/Rules/RuleErrors/RuleError449.php index 58d04b02a2e..bf1b0e8965e 100644 --- a/src/Rules/RuleErrors/RuleError449.php +++ b/src/Rules/RuleErrors/RuleError449.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -17,10 +16,8 @@ final class RuleError449 implements RuleError, NonIgnorableRuleError, FixableNod public string $message; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -30,17 +27,12 @@ public function getMessage(): string return $this->message; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError451.php b/src/Rules/RuleErrors/RuleError451.php index 08852330aa2..8479ccd0c79 100644 --- a/src/Rules/RuleErrors/RuleError451.php +++ b/src/Rules/RuleErrors/RuleError451.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -20,10 +19,8 @@ final class RuleError451 implements RuleError, LineRuleError, NonIgnorableRuleEr public int $line; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -38,17 +35,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError453.php b/src/Rules/RuleErrors/RuleError453.php index 81c146e89ec..3db549031dd 100644 --- a/src/Rules/RuleErrors/RuleError453.php +++ b/src/Rules/RuleErrors/RuleError453.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -22,10 +21,8 @@ final class RuleError453 implements RuleError, FileRuleError, NonIgnorableRuleEr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -45,17 +42,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError455.php b/src/Rules/RuleErrors/RuleError455.php index bcdb600f264..880c74ceb8a 100644 --- a/src/Rules/RuleErrors/RuleError455.php +++ b/src/Rules/RuleErrors/RuleError455.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -25,10 +24,8 @@ final class RuleError455 implements RuleError, LineRuleError, FileRuleError, Non public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -53,17 +50,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError457.php b/src/Rules/RuleErrors/RuleError457.php index 9ade4d25771..1fb0f9604a6 100644 --- a/src/Rules/RuleErrors/RuleError457.php +++ b/src/Rules/RuleErrors/RuleError457.php @@ -2,10 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -20,10 +19,8 @@ final class RuleError457 implements RuleError, TipRuleError, NonIgnorableRuleErr public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -38,17 +35,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError459.php b/src/Rules/RuleErrors/RuleError459.php index e2089282a0b..f11e22ba81d 100644 --- a/src/Rules/RuleErrors/RuleError459.php +++ b/src/Rules/RuleErrors/RuleError459.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +22,8 @@ final class RuleError459 implements RuleError, LineRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -46,17 +43,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError461.php b/src/Rules/RuleErrors/RuleError461.php index 4c2abfa2169..67cceada863 100644 --- a/src/Rules/RuleErrors/RuleError461.php +++ b/src/Rules/RuleErrors/RuleError461.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -25,10 +24,8 @@ final class RuleError461 implements RuleError, FileRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -53,17 +50,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError463.php b/src/Rules/RuleErrors/RuleError463.php index cfdcecde211..d1fb6cdb033 100644 --- a/src/Rules/RuleErrors/RuleError463.php +++ b/src/Rules/RuleErrors/RuleError463.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -28,10 +27,8 @@ final class RuleError463 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -61,17 +58,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError465.php b/src/Rules/RuleErrors/RuleError465.php index 05774014db1..939f1972245 100644 --- a/src/Rules/RuleErrors/RuleError465.php +++ b/src/Rules/RuleErrors/RuleError465.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -20,10 +19,8 @@ final class RuleError465 implements RuleError, IdentifierRuleError, NonIgnorable public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -38,17 +35,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError467.php b/src/Rules/RuleErrors/RuleError467.php index df3f666bef4..fed6fcd0dcc 100644 --- a/src/Rules/RuleErrors/RuleError467.php +++ b/src/Rules/RuleErrors/RuleError467.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -23,10 +22,8 @@ final class RuleError467 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -46,17 +43,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError469.php b/src/Rules/RuleErrors/RuleError469.php index a4ddee597b4..cca3dcfa5aa 100644 --- a/src/Rules/RuleErrors/RuleError469.php +++ b/src/Rules/RuleErrors/RuleError469.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -25,10 +24,8 @@ final class RuleError469 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -53,17 +50,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError471.php b/src/Rules/RuleErrors/RuleError471.php index cab383ec9cf..64fdec44050 100644 --- a/src/Rules/RuleErrors/RuleError471.php +++ b/src/Rules/RuleErrors/RuleError471.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -28,10 +27,8 @@ final class RuleError471 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -61,17 +58,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError473.php b/src/Rules/RuleErrors/RuleError473.php index 70969d1c5a0..901fdc0c2bc 100644 --- a/src/Rules/RuleErrors/RuleError473.php +++ b/src/Rules/RuleErrors/RuleError473.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +22,8 @@ final class RuleError473 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -46,17 +43,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError475.php b/src/Rules/RuleErrors/RuleError475.php index 95bf8652993..f976f782927 100644 --- a/src/Rules/RuleErrors/RuleError475.php +++ b/src/Rules/RuleErrors/RuleError475.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +25,8 @@ final class RuleError475 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -54,17 +51,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError477.php b/src/Rules/RuleErrors/RuleError477.php index effb79d3ccb..eff6088e3bf 100644 --- a/src/Rules/RuleErrors/RuleError477.php +++ b/src/Rules/RuleErrors/RuleError477.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -28,10 +27,8 @@ final class RuleError477 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -61,17 +58,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError479.php b/src/Rules/RuleErrors/RuleError479.php index e38fe8fffad..bbd59dd4691 100644 --- a/src/Rules/RuleErrors/RuleError479.php +++ b/src/Rules/RuleErrors/RuleError479.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -31,10 +30,8 @@ final class RuleError479 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -69,17 +66,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError481.php b/src/Rules/RuleErrors/RuleError481.php index a11e19b15b9..179cdb6987e 100644 --- a/src/Rules/RuleErrors/RuleError481.php +++ b/src/Rules/RuleErrors/RuleError481.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -21,10 +20,8 @@ final class RuleError481 implements RuleError, MetadataRuleError, NonIgnorableRu /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -42,17 +39,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError483.php b/src/Rules/RuleErrors/RuleError483.php index ec6b15cca4b..ad42d4d805d 100644 --- a/src/Rules/RuleErrors/RuleError483.php +++ b/src/Rules/RuleErrors/RuleError483.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -24,10 +23,8 @@ final class RuleError483 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -50,17 +47,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError485.php b/src/Rules/RuleErrors/RuleError485.php index 413f8eac71c..3586f66eb51 100644 --- a/src/Rules/RuleErrors/RuleError485.php +++ b/src/Rules/RuleErrors/RuleError485.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -26,10 +25,8 @@ final class RuleError485 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -57,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError487.php b/src/Rules/RuleErrors/RuleError487.php index 9df34a39bb1..2ad5c0198d2 100644 --- a/src/Rules/RuleErrors/RuleError487.php +++ b/src/Rules/RuleErrors/RuleError487.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -29,10 +28,8 @@ final class RuleError487 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -65,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError489.php b/src/Rules/RuleErrors/RuleError489.php index 4400964f9ec..b22072f4537 100644 --- a/src/Rules/RuleErrors/RuleError489.php +++ b/src/Rules/RuleErrors/RuleError489.php @@ -2,11 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -24,10 +23,8 @@ final class RuleError489 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -50,17 +47,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError491.php b/src/Rules/RuleErrors/RuleError491.php index 7ac1ef90283..216cb8b8fe0 100644 --- a/src/Rules/RuleErrors/RuleError491.php +++ b/src/Rules/RuleErrors/RuleError491.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -27,10 +26,8 @@ final class RuleError491 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -58,17 +55,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError493.php b/src/Rules/RuleErrors/RuleError493.php index 84d395bf4df..18318b6c962 100644 --- a/src/Rules/RuleErrors/RuleError493.php +++ b/src/Rules/RuleErrors/RuleError493.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -29,10 +28,8 @@ final class RuleError493 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -65,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError495.php b/src/Rules/RuleErrors/RuleError495.php index 3d0ca3d2b3f..05d106c0c3f 100644 --- a/src/Rules/RuleErrors/RuleError495.php +++ b/src/Rules/RuleErrors/RuleError495.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -32,10 +31,8 @@ final class RuleError495 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -73,17 +70,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError497.php b/src/Rules/RuleErrors/RuleError497.php index 053746f23f3..8dc28faec52 100644 --- a/src/Rules/RuleErrors/RuleError497.php +++ b/src/Rules/RuleErrors/RuleError497.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -24,10 +23,8 @@ final class RuleError497 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -50,17 +47,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError499.php b/src/Rules/RuleErrors/RuleError499.php index a061cc823be..d3c897b4b65 100644 --- a/src/Rules/RuleErrors/RuleError499.php +++ b/src/Rules/RuleErrors/RuleError499.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -27,10 +26,8 @@ final class RuleError499 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -58,17 +55,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError501.php b/src/Rules/RuleErrors/RuleError501.php index 0231b6b3b0b..23f471ee959 100644 --- a/src/Rules/RuleErrors/RuleError501.php +++ b/src/Rules/RuleErrors/RuleError501.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -29,10 +28,8 @@ final class RuleError501 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -65,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError503.php b/src/Rules/RuleErrors/RuleError503.php index 97857767ec8..b232978cb2a 100644 --- a/src/Rules/RuleErrors/RuleError503.php +++ b/src/Rules/RuleErrors/RuleError503.php @@ -2,14 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -32,10 +31,8 @@ final class RuleError503 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -73,17 +70,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError505.php b/src/Rules/RuleErrors/RuleError505.php index 04150961307..4ecd31c1a3a 100644 --- a/src/Rules/RuleErrors/RuleError505.php +++ b/src/Rules/RuleErrors/RuleError505.php @@ -2,12 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -27,10 +26,8 @@ final class RuleError505 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -58,17 +55,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError507.php b/src/Rules/RuleErrors/RuleError507.php index 830597f945f..05adef43413 100644 --- a/src/Rules/RuleErrors/RuleError507.php +++ b/src/Rules/RuleErrors/RuleError507.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -30,10 +29,8 @@ final class RuleError507 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -66,17 +63,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError509.php b/src/Rules/RuleErrors/RuleError509.php index 680a13d6214..c77523f8cd9 100644 --- a/src/Rules/RuleErrors/RuleError509.php +++ b/src/Rules/RuleErrors/RuleError509.php @@ -2,13 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -32,10 +31,8 @@ final class RuleError509 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -73,17 +70,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Rules/RuleErrors/RuleError511.php b/src/Rules/RuleErrors/RuleError511.php index f07b554d81f..14bd0fc5286 100644 --- a/src/Rules/RuleErrors/RuleError511.php +++ b/src/Rules/RuleErrors/RuleError511.php @@ -2,14 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; -use PhpParser\NodeVisitor; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -35,10 +34,8 @@ final class RuleError511 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): (Node|NodeVisitor::REMOVE_NODE) */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -81,17 +78,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): (Node|NodeVisitor::REMOVE_NODE) + * @return non-empty-list */ - public function getNewNodeCallable(): callable + public function getNodeFixes(): array { - return $this->newNodeCallable; + return $this->nodeFixes; } /** diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 3ee67bbdcc6..45aabff128a 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -8,6 +8,7 @@ use PHPStan\Analyser\Error; use PHPStan\Analyser\ExpressionResultFactory; use PHPStan\Analyser\FileAnalyser; +use PHPStan\Analyser\FixedErrorDiff; use PHPStan\Analyser\Generics\TemplateArgumentObserver; use PHPStan\Analyser\IgnoreErrorExtension; use PHPStan\Analyser\InternalError; @@ -248,24 +249,30 @@ public function fixOtherFile(string $file, string $fixedFile, string $expectedFi $fixedFile = $this->getFileHelper()->normalizePath($fixedFile); // a trait is analysed only when its file is analysed too [$errors] = $this->gatherAnalyserErrorsWithDelayedErrors(array_values(array_unique([$this->getFileHelper()->normalizePath($file), $fixedFile]))); - $diffs = []; + $diffGroups = []; + $contentsByFile = [$fixedFile => FileReader::read($fixedFile)]; foreach ($errors as $error) { - if ($error->getFixedErrorDiff() === null) { + if ($error->getFixedErrorDiffs() === []) { continue; } - if ($this->getFileHelper()->normalizePath($error->getTraitFilePath() ?? $error->getFilePath()) !== $fixedFile) { - continue; + + $diffs = []; + foreach ($error->getFixedErrorDiffs() as $diff) { + // the fix of an error applies to all its files or none, all of them take part + $diffFile = $this->getFileHelper()->normalizePath($diff->file); + $contentsByFile[$diffFile] ??= FileReader::read($diffFile); + $diffs[] = new FixedErrorDiff($diffFile, $diff->originalHash, $diff->diff); } - $diffs[] = $error->getFixedErrorDiff(); + $diffGroups[] = $diffs; } $patcher = self::getContainer()->getByType(Patcher::class); - $patchResult = $patcher->applyDiffs(FileReader::read($fixedFile), $diffs); // @phpstan-ignore missingType.checkedException + $patchResult = $patcher->apply($contentsByFile, $diffGroups); $this->assertSame(0, $patchResult['skippedCount'], 'Some fixes overlap and could not be applied together.'); $fixedFileContents = FileReader::read($expectedFile); - $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($patchResult['contents'])); + $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($patchResult['contents'][$fixedFile])); } private function normalizeLineEndings(string $string): string diff --git a/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php b/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php index f04c1ddbcd0..b514e5bdd88 100644 --- a/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php +++ b/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php @@ -291,7 +291,7 @@ public function testRuleWithFixRunsAgainWhenTheFixedFileChanged(): void $result = $this->finalize([$rule], $collectedData, false, []); $errors = $result->getAnalyserResult()->getUnorderedErrors(); $this->assertCount(1, $errors); - $this->assertNotNull($errors[0]->getFixedErrorDiff()); + $this->assertNotSame([], $errors[0]->getFixedErrorDiffs()); $result = $this->finalize([$rule], $collectedData, false, $result->getCollectedDataRuleResults()); $this->assertSame(1, $result->getReusedRulesCount()); diff --git a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php index 81859481157..06ddbba2981 100644 --- a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php @@ -490,9 +490,9 @@ public function testErrorLimit( public function testFixableIgnoredErrors(): void { - $fixed = new FixedErrorDiff('hash', 'diff'); - $fixable = new Error('Fixable', 'Foo.php', 12, filePath: 'Foo.php', fixedErrorDiff: $fixed); - $ignoredFixable = new Error('Ignored', 'Foo.php', 13, filePath: 'Foo.php', fixedErrorDiff: $fixed); + $fixed = [new FixedErrorDiff('Foo.php', 'hash', 'diff')]; + $fixable = new Error('Fixable', 'Foo.php', 12, filePath: 'Foo.php', fixedErrorDiffs: $fixed); + $ignoredFixable = new Error('Ignored', 'Foo.php', 13, filePath: 'Foo.php', fixedErrorDiffs: $fixed); // shown with a green build too, the ignored errors are not in the table $formatter = $this->createErrorFormatter(null); diff --git a/tests/PHPStan/Fixable/MultiFixRule.php b/tests/PHPStan/Fixable/MultiFixRule.php new file mode 100644 index 00000000000..65bff404add --- /dev/null +++ b/tests/PHPStan/Fixable/MultiFixRule.php @@ -0,0 +1,98 @@ + + */ +class MultiFixRule implements Rule +{ + + public function __construct(private Parser $parser) + { + } + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Name || !$node->getArgs()[0]->value instanceof String_) { + return []; + } + + $name = $node->name->toLowerString(); + if ($name !== 'renameall' && $name !== 'renameallornothing') { + return []; + } + + $otherFile = dirname($scope->getFile()) . '/' . $node->getArgs()[0]->value->value; + $builder = RuleErrorBuilder::message('Renaming foo() to bar().')->identifier('tests.multiFix'); + foreach ($this->findFooCalls($scope->getFile()) as $call) { + $builder->fixNode($call, static function (FuncCall $call): FuncCall { + $call->name = new Name('bar'); + + return $call; + }); + } + foreach ($this->findFooCalls($otherFile) as $call) { + $builder->fixNode($call, static function (FuncCall $call): FuncCall { + $call->name = new Name('bar'); + + return $call; + }, $otherFile); + // applied after the rename, to the renamed call + $builder->fixNode($call, static function (FuncCall $call): FuncCall { + $call->args[] = new Arg(new Int_(1)); + + return $call; + }, $otherFile); + } + + if ($name === 'renameallornothing') { + foreach ((new NodeFinder())->findInstanceOf($this->parser->parseFile($scope->getFile()), If_::class) as $if) { + $builder->removeNode($if->cond); + } + } + + return [$builder->build()]; + } + + /** + * @return list + */ + private function findFooCalls(string $file): array + { + $calls = []; + foreach ((new NodeFinder())->findInstanceOf($this->parser->parseFile($file), FuncCall::class) as $call) { + if (!$call->name instanceof Name || $call->name->toLowerString() !== 'foo') { + continue; + } + + $calls[] = $call; + } + + return $calls; + } + +} diff --git a/tests/PHPStan/Fixable/MultiFixRuleTest.php b/tests/PHPStan/Fixable/MultiFixRuleTest.php new file mode 100644 index 00000000000..c60701bb4aa --- /dev/null +++ b/tests/PHPStan/Fixable/MultiFixRuleTest.php @@ -0,0 +1,36 @@ + + */ +class MultiFixRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new MultiFixRule(self::getContainer()->getService('defaultAnalysisParser')); + } + + public function testFixInFileOfError(): void + { + $this->fix(__DIR__ . '/data/multi-fix/a.php', __DIR__ . '/data/multi-fix/a.php.fixed'); + } + + public function testFixInOtherFile(): void + { + $this->fixOtherFile(__DIR__ . '/data/multi-fix/a.php', __DIR__ . '/data/multi-fix/other.php', __DIR__ . '/data/multi-fix/other.php.fixed'); + } + + public function testAllOrNothing(): void + { + $errors = $this->gatherAnalyserErrors([__DIR__ . '/data/multi-fix/all-or-nothing.php']); + $this->assertCount(1, $errors); + $this->assertSame([], $errors[0]->getFixedErrorDiffs()); + } + +} diff --git a/tests/PHPStan/Fixable/PatcherTest.php b/tests/PHPStan/Fixable/PatcherTest.php new file mode 100644 index 00000000000..cbaea268856 --- /dev/null +++ b/tests/PHPStan/Fixable/PatcherTest.php @@ -0,0 +1,39 @@ + new FixedErrorDiff($file, hash('sha256', $contents), $diff); + + $result = (new Patcher())->apply(['x.php' => $x, 'y.php' => $y], [ + [ + $diff('x.php', $x, "@@ -2,1 +2,1 @@\n-x2\n+A\n"), + $diff('y.php', $y, "@@ -1,1 +1,1 @@\n-y1\n+A\n"), + ], + [ + // conflicts with the first group in x.php, so its change of y.php is not applied either + $diff('x.php', $x, "@@ -2,1 +2,1 @@\n-x2\n+B\n"), + $diff('y.php', $y, "@@ -3,1 +3,1 @@\n-y3\n+B\n"), + ], + [ + // computed against different contents + $diff('y.php', "changed\n", "@@ -2,1 +2,1 @@\n-y2\n+C\n"), + ], + ]); + + $this->assertSame(['x.php' => "x1\nA\nx3\n", 'y.php' => "A\ny2\ny3\n"], $result['contents']); + $this->assertSame(1, $result['appliedCount']); + $this->assertSame(2, $result['skippedCount']); + } + +} diff --git a/tests/PHPStan/Fixable/RemoveNodeRuleTest.php b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php index d9c8ae92287..b2db7470003 100644 --- a/tests/PHPStan/Fixable/RemoveNodeRuleTest.php +++ b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php @@ -35,7 +35,7 @@ public function testNodeNotInArrayIsNotFixable(): void { $fixable = []; foreach ($this->gatherAnalyserErrors([__DIR__ . '/data/remove-node.php']) as $error) { - $fixable[$error->getMessage()] = $error->getFixedErrorDiff() !== null; + $fixable[$error->getMessage()] = $error->getFixedErrorDiffs() !== []; } $this->assertSame([ diff --git a/tests/PHPStan/Fixable/data/multi-fix/a.php b/tests/PHPStan/Fixable/data/multi-fix/a.php new file mode 100644 index 00000000000..68371008ae2 --- /dev/null +++ b/tests/PHPStan/Fixable/data/multi-fix/a.php @@ -0,0 +1,6 @@ + Date: Mon, 2 Nov 2026 04:31:57 +0000 Subject: [PATCH 11/24] Remove statements left without items by a fix When fixes remove every constant of a const group, every property of a property group, every use of a use statement etc., the remaining statement is invalid PHP, so ReplacingNodeVisitor removes it too. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Fixable/ReplacingNodeVisitor.php | 35 ++++++++++++++++++- tests/PHPStan/Fixable/RemoveNodeRule.php | 16 +++++++++ tests/PHPStan/Fixable/RemoveNodeRuleTest.php | 13 ++++--- tests/PHPStan/Fixable/data/remove-node.php | 8 +++++ .../Fixable/data/remove-node.php.fixed | 4 +++ 5 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/Fixable/ReplacingNodeVisitor.php b/src/Fixable/ReplacingNodeVisitor.php index c9a33edd76f..05e76ba66e9 100644 --- a/src/Fixable/ReplacingNodeVisitor.php +++ b/src/Fixable/ReplacingNodeVisitor.php @@ -75,7 +75,16 @@ public function enterNode(Node $node): ?Node public function leaveNode(Node $node): Node|int|null { $origNode = $node->getAttribute('origNode'); - if (!$origNode instanceof Node || !$this->callbacks->contains($origNode)) { + if (!$origNode instanceof Node) { + return null; + } + + if (!$this->callbacks->contains($origNode)) { + // a statement is invalid without items, remove it when a fix removed all of them + if (self::getItems($node) === [] && self::getItems($origNode) !== []) { + return NodeVisitor::REMOVE_NODE; + } + return null; } @@ -108,4 +117,28 @@ public function isComplete(): bool return !$this->failed && $this->appliedCount === count($this->callbacks); } + /** + * @return array|null + */ + private static function getItems(Node $node): ?array + { + if ($node instanceof Node\Stmt\ClassConst || $node instanceof Node\Stmt\Const_) { + return $node->consts; + } + if ($node instanceof Node\Stmt\Property) { + return $node->props; + } + if ($node instanceof Node\Stmt\Use_ || $node instanceof Node\Stmt\GroupUse) { + return $node->uses; + } + if ($node instanceof Node\Stmt\Global_ || $node instanceof Node\Stmt\Static_ || $node instanceof Node\Stmt\Unset_) { + return $node->vars; + } + if ($node instanceof Node\Stmt\Echo_) { + return $node->exprs; + } + + return null; + } + } diff --git a/tests/PHPStan/Fixable/RemoveNodeRule.php b/tests/PHPStan/Fixable/RemoveNodeRule.php index 6c405e1826d..faf46907325 100644 --- a/tests/PHPStan/Fixable/RemoveNodeRule.php +++ b/tests/PHPStan/Fixable/RemoveNodeRule.php @@ -11,6 +11,8 @@ use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; +use function str_starts_with; +use function strtolower; /** * @implements Rule @@ -31,6 +33,20 @@ public function processNode(Node $node, Scope $scope): array $toRemove = $node; } elseif ($node instanceof Arg && $node->value instanceof ConstFetch && $node->value->name->toString() === 'REMOVE_ARG') { $toRemove = $node; + } elseif ($node instanceof Stmt\ClassConst || $node instanceof Stmt\Property) { + // one error removes all REMOVE* constants or remove* properties of the statement + $builder = RuleErrorBuilder::message('Removing items.')->identifier('tests.removeNode'); + $found = false; + foreach ($node instanceof Stmt\ClassConst ? $node->consts : $node->props as $item) { + if (!str_starts_with(strtolower($item->name->toString()), 'remove')) { + continue; + } + + $builder->removeNode($item); + $found = true; + } + + return $found ? [$builder->build()] : []; } elseif ($node instanceof Stmt\If_ && self::isRemoveMeCall($node->cond)) { // not in an array, cannot be removed $toRemove = $node->cond; diff --git a/tests/PHPStan/Fixable/RemoveNodeRuleTest.php b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php index b2db7470003..fd58d01724c 100644 --- a/tests/PHPStan/Fixable/RemoveNodeRuleTest.php +++ b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php @@ -19,10 +19,14 @@ protected function getRule(): Rule public function testRule(): void { $this->analyse([__DIR__ . '/data/remove-node.php'], [ - ['Removing Stmt_Expression.', 11], - ['Removing Arg.', 13], - ['Removing Expr_FuncCall.', 14], - ['Removing Stmt_ClassMethod.', 22], + ['Removing items.', 8], + ['Removing items.', 10], + ['Removing items.', 12], + ['Removing items.', 14], + ['Removing Stmt_Expression.', 19], + ['Removing Arg.', 21], + ['Removing Expr_FuncCall.', 22], + ['Removing Stmt_ClassMethod.', 30], ]); } @@ -39,6 +43,7 @@ public function testNodeNotInArrayIsNotFixable(): void } $this->assertSame([ + 'Removing items.' => true, 'Removing Stmt_Expression.' => true, 'Removing Arg.' => true, 'Removing Expr_FuncCall.' => false, diff --git a/tests/PHPStan/Fixable/data/remove-node.php b/tests/PHPStan/Fixable/data/remove-node.php index a288fb95058..393180657c6 100644 --- a/tests/PHPStan/Fixable/data/remove-node.php +++ b/tests/PHPStan/Fixable/data/remove-node.php @@ -5,6 +5,14 @@ class Foo { + const REMOVE_A = 1, REMOVE_B = 2; + + const KEEP = 1, REMOVE_C = 2; + + public $removeA, $removeB; + + public $keep, $removeC; + public function doFoo(): void { echo 1; diff --git a/tests/PHPStan/Fixable/data/remove-node.php.fixed b/tests/PHPStan/Fixable/data/remove-node.php.fixed index 47e1e97451e..a34d7060ad5 100644 --- a/tests/PHPStan/Fixable/data/remove-node.php.fixed +++ b/tests/PHPStan/Fixable/data/remove-node.php.fixed @@ -5,6 +5,10 @@ namespace RemoveNode; class Foo { + const KEEP = 1; + + public $keep; + public function doFoo(): void { echo 1; From 374c814bf22e94a2d9e8a2cc2b2f9f3c4bd32faf Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 04:32:11 +0000 Subject: [PATCH 12/24] Make RuleErrorBuilder::fixNode() and removeNode() public API Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Rules/RuleErrorBuilder.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Rules/RuleErrorBuilder.php b/src/Rules/RuleErrorBuilder.php index 5f159e91437..c583bbbb796 100644 --- a/src/Rules/RuleErrorBuilder.php +++ b/src/Rules/RuleErrorBuilder.php @@ -318,7 +318,6 @@ public function nonIgnorable(): self * Every call adds a change to the fix of the error. The changes are applied together or not at all. * Several changes of the same node are applied in the order they were added. * - * @internal Experimental * @template TNode of Node * @param TNode $node * @param callable(TNode): (Node|NodeVisitor::REMOVE_NODE) $cb returning NodeVisitor::REMOVE_NODE works like removeNode() @@ -340,7 +339,6 @@ public function fixNode(Node $node, callable $cb, ?string $file = null): self * Adds removing the node to the fix of the error, see fixNode(). Only a node in an array, * like a statement, an argument, or an array item, can be removed. Otherwise the error is not fixable. * - * @internal Experimental * @param string|null $file the file of the node when it is not the file of the error * @phpstan-this-out self * @return self From 23e6a7cd9b5394aa6761a3b207612e9eb6096030 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 04:37:28 +0000 Subject: [PATCH 13/24] Fix errors in rounds until nothing fixable is left After the first round of fixes is written, --fix analyses the changed code again in a new process, which also saves the result cache, and fixes what is still fixable: fixes skipped because they conflicted with another fix, and errors that the previous fixes caused. It stops when nothing is applied or after FIX_ROUNDS_LIMIT rounds. The reported count is the number of fixes applied in all rounds, and errors that are still fixable at the end are reported as not fixed. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- .github/workflows/e2e-tests.yml | 22 ++-- build/composer-dependency-analyser.php | 1 - e2e/fix/.gitignore | 1 + e2e/fix/cycle-original/Foo.php | 8 ++ e2e/fix/cycle.neon | 8 ++ e2e/fix/expected/Foo.php | 6 + e2e/fix/expected/Ignored-fix-both.php | 6 - e2e/fix/expected/Ignored-fix-ignored.php | 2 +- e2e/fix/expected/Ignored-fix.php | 2 +- e2e/fix/original/Foo.php | 6 + e2e/fix/original/Ignored.php | 2 +- e2e/fix/rules/rules.php | 34 ++++++ src/Command/AnalyseCommand.php | 144 +++++++++++++++++++---- 13 files changed, 194 insertions(+), 48 deletions(-) create mode 100644 e2e/fix/cycle-original/Foo.php create mode 100644 e2e/fix/cycle.neon delete mode 100644 e2e/fix/expected/Ignored-fix-both.php diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 8f941ffa00d..1d77dc0d6f4 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -970,27 +970,25 @@ jobs: - script: | cd e2e/fix composer install - rm -rf src tmp && cp -r original src + rm -rf src cycle tmp && cp -r original src && cp -r cycle-original cycle OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix") echo "$OUTPUT" - ../bashunit assert contains '[OK] 2 errors fixed' "$OUTPUT" + ../bashunit assert contains 'Analysing fixed code (round 4)...' "$OUTPUT" + ../bashunit assert not_contains 'round 5' "$OUTPUT" + ../bashunit assert contains '[OK] 10 errors fixed' "$OUTPUT" diff -u expected/Foo.php src/Foo.php diff -u expected/Ignored-fix.php src/Ignored.php - rm -rf src && cp -r original src OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix-ignored") echo "$OUTPUT" - ../bashunit assert contains '[OK] 1 error fixed' "$OUTPUT" - diff -u original/Foo.php src/Foo.php - diff -u expected/Ignored-fix-ignored.php src/Ignored.php - rm -rf src && cp -r original src - OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix --fix-ignored") - echo "$OUTPUT" - ../bashunit assert contains '[OK] 3 errors fixed' "$OUTPUT" + ../bashunit assert contains '[OK] 2 errors fixed' "$OUTPUT" diff -u expected/Foo.php src/Foo.php - diff -u expected/Ignored-fix-both.php src/Ignored.php - OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse --fix-ignored") + diff -u expected/Ignored-fix-ignored.php src/Ignored.php + OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse --fix --fix-ignored") echo "$OUTPUT" ../bashunit assert contains 'No fixable errors found' "$OUTPUT" + OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -c cycle.neon --fix") + echo "$OUTPUT" + ../bashunit assert contains 'Fixing stopped after 10 rounds' "$OUTPUT" - script: | cd e2e/editor-mode OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw") diff --git a/build/composer-dependency-analyser.php b/build/composer-dependency-analyser.php index e46cf402576..6d9e722e6e4 100644 --- a/build/composer-dependency-analyser.php +++ b/build/composer-dependency-analyser.php @@ -17,7 +17,6 @@ ]; $pinnedToSupportPhp72 = [ - 'symfony/process', 'symfony/service-contracts', 'symfony/string', ]; diff --git a/e2e/fix/.gitignore b/e2e/fix/.gitignore index 82cdbfd52b3..67962ade64f 100644 --- a/e2e/fix/.gitignore +++ b/e2e/fix/.gitignore @@ -1,4 +1,5 @@ /src +/cycle /tmp /vendor /composer.lock diff --git a/e2e/fix/cycle-original/Foo.php b/e2e/fix/cycle-original/Foo.php new file mode 100644 index 00000000000..efbacbd8937 --- /dev/null +++ b/e2e/fix/cycle-original/Foo.php @@ -0,0 +1,8 @@ + + */ +final class PingPongRule implements Rule +{ + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Node\Name || !in_array($node->name->toString(), ['ping', 'pong'], true)) { + return []; + } + + $other = $node->name->toString() === 'ping' ? 'pong' : 'ping'; + + return [ + RuleErrorBuilder::message(sprintf('Call %s() instead.', $other)) + ->identifier('fixE2E.pingPong') + ->fixNode($node, static function (FuncCall $node) use ($other): FuncCall { + $node->name = new Node\Name($other); + return $node; + }) + ->build(), + ]; + } + +} diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index d1c9d4271c1..7bacc79f38f 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -2,6 +2,8 @@ namespace PHPStan\Command; +use Nette\Utils\Json; +use Nette\Utils\JsonException; use OndraM\CiDetector\CiDetector; use Override; use PHPStan\Analyser\Error; @@ -27,6 +29,7 @@ use PHPStan\Internal\ComposerHelper; use PHPStan\Internal\DirectoryCreator; use PHPStan\Internal\DirectoryCreatorException; +use PHPStan\Process\ProcessHelper; use PHPStan\ShouldNotHappenException; use PHPStan\Turbo\TurboExtensionEnabler; use PHPStan\Turbo\TurboExtensionSelector; @@ -37,10 +40,12 @@ use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\StreamOutput; +use Symfony\Component\Process\Process; use Throwable; use function array_intersect; use function array_key_exists; use function array_map; +use function array_merge; use function array_reverse; use function array_values; use function count; @@ -63,6 +68,7 @@ use function stream_get_contents; use function strlen; use function substr; +use function trim; use const PATHINFO_BASENAME; use const PATHINFO_EXTENSION; @@ -85,6 +91,11 @@ final class AnalyseCommand extends Command */ private const RESULT_CACHE_CI_NOTIFICATION_ELAPSED_LIMIT = 60.0; + /** Fixes can lead to new fixable errors, or to new fixes forever. */ + private const FIX_ROUNDS_LIMIT = 10; + + private const OPTION_FIX_ROUND = 'fix-round'; + /** * @param string[] $composerAutoloaderProjectPaths */ @@ -117,6 +128,7 @@ protected function configure(): void new InputOption('instead-of', mode: InputOption::VALUE_REQUIRED, description: '(Editor mode) File being replaced by --tmp-file'), new InputOption('fix', mode: InputOption::VALUE_NONE, description: 'Fix auto-fixable errors (experimental)'), new InputOption('fix-ignored', mode: InputOption::VALUE_NONE, description: 'Fix auto-fixable ignored errors, can be combined with --fix (experimental)'), + new InputOption(self::OPTION_FIX_ROUND, mode: InputOption::VALUE_NONE, description: '(Internal) Run one round of --fix and print its counts as JSON'), new InputOption('watch', mode: InputOption::VALUE_NONE, description: 'Launch PHPStan Pro'), new InputOption('pro', mode: InputOption::VALUE_NONE, description: 'Launch PHPStan Pro'), new InputOption('fail-without-result-cache', mode: InputOption::VALUE_NONE, description: 'Return non-zero exit code when result cache is not used'), @@ -159,6 +171,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $fixReported = (bool) $input->getOption('fix'); $fixIgnored = (bool) $input->getOption('fix-ignored'); $fix = $fixReported || $fixIgnored; + $fixRound = (bool) $input->getOption(self::OPTION_FIX_ROUND); $failWithoutResultCache = (bool) $input->getOption('fail-without-result-cache'); /** @var string|false|null $generateBaselineFile */ @@ -235,7 +248,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $inceptionResult->handleReturn(1, null, $this->analysisStartTime); } - if ($fixReported) { + if ($fixReported && !$fixRound) { $inceptionResult->getErrorOutput()->getStyle()->note('The --fix CLI option no longer launches PHPStan Pro. Use --pro instead if you want to launch PHPStan Pro'); } } @@ -374,7 +387,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int throw new ShouldNotHappenException(); } - if ($fix) { + if ($fix && !$fixRound) { $inceptionResult->getErrorOutput()->writeLineFormatted('Analysing files...'); } @@ -568,36 +581,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } + $patcher = $container->getByType(Patcher::class); $fixableErrorsCount = count($fixableErrors); + if ($fixRound) { + $patchResult = $patcher->applyToFiles(array_map( + static fn (Error $error): array => $error->getFixedErrorDiffs(), + $fixableErrors, + )); + $inceptionResult->getStdOutput()->writeRaw(Json::encode([ + 'fixable' => $fixableErrorsCount, + 'applied' => $patchResult['appliedCount'], + ])); + + return $inceptionResult->handleReturn(0, $analysisResult->getPeakMemoryUsageBytes(), $this->analysisStartTime, $analysisResult->getWorkerCount()); + } + if ($fixableErrorsCount === 0) { $inceptionResult->getStdOutput()->getStyle()->error('No fixable errors found'); $exitCode = 1; } else { $inceptionResult->getErrorOutput()->writeLineFormatted('Fixing errors...'); - - $patchResult = $container->getByType(Patcher::class)->applyToFiles(array_map( - static fn (Error $error): array => $error->getFixedErrorDiffs(), - $fixableErrors, - )); - $skippedCount = $patchResult['skippedCount']; - - if ($skippedCount > 0) { - $fixedCount = $fixableErrorsCount - $skippedCount; - $inceptionResult->getStdOutput()->getStyle()->warning(sprintf( - '%d %s fixed, %d %s skipped', - $fixedCount, - $fixedCount === 1 ? 'error' : 'errors', - $skippedCount, - $skippedCount === 1 ? 'error' : 'errors', - )); - } else { - $inceptionResult->getStdOutput()->getStyle()->success(sprintf( - '%d %s fixed', - $fixableErrorsCount, - $fixableErrorsCount === 1 ? 'error' : 'errors', - )); - } - $exitCode = 0; + $exitCode = $this->fixInRounds( + $inceptionResult, + $input, + $fixableErrorsCount, + $patcher->applyToFiles(array_map( + static fn (Error $error): array => $error->getFixedErrorDiffs(), + $fixableErrors, + ))['appliedCount'], + ); } } else { if (AgentDetector::isRunningInAgent() && count($analysisResult->getFileSpecificErrors()) > 0) { @@ -637,6 +649,86 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); } + /** + * After the fixes of the first round are written, every next round analyses the changed code + * in a new process, which also saves the result cache, and fixes what is still fixable. + * This applies fixes skipped because of a conflict and fixes of errors the previous round caused. + */ + private function fixInRounds(InceptionResult $inceptionResult, InputInterface $input, int $fixableCount, int $appliedCount): int + { + $errorOutput = $inceptionResult->getErrorOutput(); + $style = $inceptionResult->getStdOutput()->getStyle(); + $fixedCount = $appliedCount; + $round = 1; + while ($appliedCount > 0) { + if ($round === self::FIX_ROUNDS_LIMIT) { + $style->warning(sprintf( + '%d %s fixed. Fixing stopped after %d rounds, run PHPStan again to see what is left.', + $fixedCount, + $fixedCount === 1 ? 'error' : 'errors', + $round, + )); + + return 0; + } + + $round++; + $errorOutput->writeLineFormatted(sprintf('Analysing fixed code (round %d)...', $round)); + $command = ProcessHelper::getWorkerCommand( + $_SERVER['argv'][0], + self::NAME, + $inceptionResult->getProjectConfigFile(), + array_merge( + ['--' . self::OPTION_FIX_ROUND, '--' . ErrorsConsoleStyle::OPTION_NO_PROGRESS], + (bool) $input->getOption('fix') ? ['--fix'] : [], + (bool) $input->getOption('fix-ignored') ? ['--fix-ignored'] : [], + ), + $input, + ); + $process = Process::fromShellCommandline($command, timeout: null); + $process->run(); + try { + /** @var array{fixable: int, applied: int} $roundResult */ + $roundResult = Json::decode($process->getOutput(), Json::FORCE_ARRAY); + } catch (JsonException) { + $style->error(sprintf( + "%d %s fixed, but analysing the fixed code failed:\n%s", + $fixedCount, + $fixedCount === 1 ? 'error' : 'errors', + trim($process->getOutput() . "\n" . $process->getErrorOutput()), + )); + + return 1; + } + + $fixableCount = $roundResult['fixable']; + $appliedCount = $roundResult['applied']; + $fixedCount += $appliedCount; + } + + $leftCount = $fixableCount; + if ($leftCount > 0) { + $style->warning(sprintf( + '%d %s fixed, %d %s could not be fixed because of conflicting fixes', + $fixedCount, + $fixedCount === 1 ? 'error' : 'errors', + $leftCount, + $leftCount === 1 ? 'error' : 'errors', + )); + } else { + $style->success(sprintf( + '%d %s fixed', + $fixedCount, + $fixedCount === 1 ? 'error' : 'errors', + )); + + return 0; + } + + // some fixable errors are left, like errors left after the analysis + return 1; + } + private function reportMissingResultCacheInCi(Output $errorOutput, AnalysisResult $analysisResult, bool $onlyFiles): void { if ( From bb98ac2e612dee26030234225c70e7d9d0395dbe Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 04:51:59 +0000 Subject: [PATCH 14/24] Find fixed nodes by position instead of identity A CollectedDataNode rule parses the files it fixes itself. The parser cache keeps the nodes of at most 256 files, so in a big project the file was parsed again before the fix was made and none of the nodes were found. Matching the nodes by class and position in the file works with any parse of the same file contents. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Analyser/RuleErrorTransformer.php | 4 +- src/Fixable/ReplacingNodeVisitor.php | 49 +++++++++++++------ .../Fixable/FixCollectedFuncCallRule.php | 2 +- .../Fixable/FixCollectedFuncCallRuleTest.php | 2 +- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index c93268df9ea..756c2dd46cf 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -182,8 +182,8 @@ public function transform( /** * Without $fileNodes (errors of CollectedDataNode rules, errors transformed inside collectors, - * and fixes in another file), the file is parsed with the cached analysis parser. The rule has to take - * the nodes it fixes from the same parser so that ReplacingNodeVisitor finds them by identity. + * and fixes in another file), the file is parsed with the cached analysis parser. ReplacingNodeVisitor + * finds the fixed nodes by their position, so the rule has to take them from a parse of the same file contents. * Returns null when some of the nodes cannot be fixed. * * @param Node\Stmt[] $fileNodes diff --git a/src/Fixable/ReplacingNodeVisitor.php b/src/Fixable/ReplacingNodeVisitor.php index 05e76ba66e9..99081afc3b2 100644 --- a/src/Fixable/ReplacingNodeVisitor.php +++ b/src/Fixable/ReplacingNodeVisitor.php @@ -9,21 +9,27 @@ use PHPStan\Node\VirtualNode; use PHPStan\Rules\NodeFix; use PHPStan\ShouldNotHappenException; -use SplObjectStorage; +use function array_key_exists; use function count; +use function get_class; use function is_array; +use function spl_object_id; /** * Applies the NodeFixes of one error to the nodes of one file. Runs after CloningVisitor in the same traversal. + * + * Nodes are matched by their class and position in the file, not by identity, so a rule can take them + * from any parse of the same file contents. A CollectedDataNode rule parses files itself, + * and the parser cache does not keep the parsed nodes of every file until the fixes are made. */ final class ReplacingNodeVisitor extends NodeVisitorAbstract { - /** @var SplObjectStorage> */ - private SplObjectStorage $callbacks; + /** @var array> */ + private array $callbacks = []; - /** @var SplObjectStorage original nodes in an array, those can be removed */ - private SplObjectStorage $removable; + /** @var array nodes in an array, those can be removed */ + private array $removable = []; private int $appliedCount = 0; @@ -34,12 +40,9 @@ final class ReplacingNodeVisitor extends NodeVisitorAbstract */ public function __construct(array $fixes) { - $this->callbacks = new SplObjectStorage(); - $this->removable = new SplObjectStorage(); foreach ($fixes as $fix) { - $callbacks = $this->callbacks->contains($fix->node) ? $this->callbacks[$fix->node] : []; - $callbacks[] = $fix->callback; - $this->callbacks[$fix->node] = $callbacks; + // a node without a position cannot be found, it stays in $callbacks so that the fix is not complete + $this->callbacks[self::getKey($fix->node) ?? '#' . spl_object_id($fix->node)][] = $fix->callback; } } @@ -56,11 +59,16 @@ public function enterNode(Node $node): ?Node } foreach ($subNode as $item) { - if (!$item instanceof Node || !$this->callbacks->contains($item)) { + if (!$item instanceof Node) { continue; } - $this->removable[$item] = true; + $key = self::getKey($item); + if ($key === null || !array_key_exists($key, $this->callbacks)) { + continue; + } + + $this->removable[$key] = true; } } @@ -79,7 +87,8 @@ public function leaveNode(Node $node): Node|int|null return null; } - if (!$this->callbacks->contains($origNode)) { + $key = self::getKey($origNode); + if ($key === null || !array_key_exists($key, $this->callbacks)) { // a statement is invalid without items, remove it when a fix removed all of them if (self::getItems($node) === [] && self::getItems($origNode) !== []) { return NodeVisitor::REMOVE_NODE; @@ -90,10 +99,10 @@ public function leaveNode(Node $node): Node|int|null $this->appliedCount++; $newNode = $node; - foreach ($this->callbacks[$origNode] as $callback) { + foreach ($this->callbacks[$key] as $callback) { $newNode = $callback($newNode); if ($newNode === NodeVisitor::REMOVE_NODE) { - if (!$this->removable->contains($origNode)) { + if (!array_key_exists($key, $this->removable)) { $this->failed = true; return null; } @@ -117,6 +126,16 @@ public function isComplete(): bool return !$this->failed && $this->appliedCount === count($this->callbacks); } + private static function getKey(Node $node): ?string + { + $start = $node->getStartFilePos(); + if ($start < 0) { + return null; + } + + return get_class($node) . ':' . $start . ':' . $node->getEndFilePos(); + } + /** * @return array|null */ diff --git a/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php b/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php index 44228eb6e69..dafbbf7db2d 100644 --- a/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php +++ b/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php @@ -15,7 +15,7 @@ /** * Renames foo() calls to bar(). The calls are collected per file and fixed in a CollectedDataNode rule, - * which takes the nodes from the same parser the analysis uses. + * which parses the files itself, without the parser cache of the analysis. * * @implements Rule */ diff --git a/tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php b/tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php index e81f6fc2803..d6aa4784a50 100644 --- a/tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php +++ b/tests/PHPStan/Fixable/FixCollectedFuncCallRuleTest.php @@ -13,7 +13,7 @@ class FixCollectedFuncCallRuleTest extends RuleTestCase protected function getRule(): Rule { - return new FixCollectedFuncCallRule(self::getContainer()->getService('defaultAnalysisParser')); + return new FixCollectedFuncCallRule(self::getContainer()->getService('currentPhpVersionRichParser')); } protected function getCollectors(): array From ba0c59f47114dcd00507f6366cf8207ab242c717 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 04:59:35 +0000 Subject: [PATCH 15/24] Show the progress and the result of every fix round Rounds after the first one showed no progress bar, so a long analysis of the fixed code looked stuck. The new process now streams its progress bar, every round reports how many errors it fixed in how many files, and the changed files are listed at the end. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- .github/workflows/e2e-tests.yml | 3 +- src/Command/AnalyseCommand.php | 94 ++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 32 deletions(-) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 1d77dc0d6f4..65ed8386f90 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -975,7 +975,8 @@ jobs: echo "$OUTPUT" ../bashunit assert contains 'Analysing fixed code (round 4)...' "$OUTPUT" ../bashunit assert not_contains 'round 5' "$OUTPUT" - ../bashunit assert contains '[OK] 10 errors fixed' "$OUTPUT" + ../bashunit assert contains 'Round 2: fixed 3 errors in 1 file' "$OUTPUT" + ../bashunit assert contains '[OK] 10 errors fixed in 2 files' "$OUTPUT" diff -u expected/Foo.php src/Foo.php diff -u expected/Ignored-fix.php src/Ignored.php OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix-ignored") diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 7bacc79f38f..41502084ae4 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -251,6 +251,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($fixReported && !$fixRound) { $inceptionResult->getErrorOutput()->getStyle()->note('The --fix CLI option no longer launches PHPStan Pro. Use --pro instead if you want to launch PHPStan Pro'); } + } $errorOutput = $inceptionResult->getErrorOutput(); @@ -591,6 +592,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $inceptionResult->getStdOutput()->writeRaw(Json::encode([ 'fixable' => $fixableErrorsCount, 'applied' => $patchResult['appliedCount'], + 'changedFiles' => $patchResult['changedFiles'], ])); return $inceptionResult->handleReturn(0, $analysisResult->getPeakMemoryUsageBytes(), $this->analysisStartTime, $analysisResult->getWorkerCount()); @@ -600,7 +602,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $inceptionResult->getStdOutput()->getStyle()->error('No fixable errors found'); $exitCode = 1; } else { - $inceptionResult->getErrorOutput()->writeLineFormatted('Fixing errors...'); $exitCode = $this->fixInRounds( $inceptionResult, $input, @@ -608,7 +609,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $patcher->applyToFiles(array_map( static fn (Error $error): array => $error->getFixedErrorDiffs(), $fixableErrors, - ))['appliedCount'], + )), ); } } else { @@ -654,48 +655,76 @@ protected function execute(InputInterface $input, OutputInterface $output): int * in a new process, which also saves the result cache, and fixes what is still fixable. * This applies fixes skipped because of a conflict and fixes of errors the previous round caused. */ - private function fixInRounds(InceptionResult $inceptionResult, InputInterface $input, int $fixableCount, int $appliedCount): int + /** + * @param array{changedFiles: list, appliedCount: int, skippedCount: int} $patchResult the first round + */ + private function fixInRounds( + InceptionResult $inceptionResult, + InputInterface $input, + int $fixableCount, + array $patchResult, + ): int { $errorOutput = $inceptionResult->getErrorOutput(); - $style = $inceptionResult->getStdOutput()->getStyle(); - $fixedCount = $appliedCount; + $stdOutput = $inceptionResult->getStdOutput(); + $appliedCount = $patchResult['appliedCount']; + $roundChangedFiles = $patchResult['changedFiles']; + $fixedCount = 0; + $changedFiles = []; $round = 1; - while ($appliedCount > 0) { - if ($round === self::FIX_ROUNDS_LIMIT) { - $style->warning(sprintf( - '%d %s fixed. Fixing stopped after %d rounds, run PHPStan again to see what is left.', - $fixedCount, - $fixedCount === 1 ? 'error' : 'errors', + while (true) { + $fixedCount += $appliedCount; + foreach ($roundChangedFiles as $changedFile) { + $changedFiles[$changedFile] = true; + } + if ($appliedCount > 0) { + $errorOutput->writeLineFormatted(sprintf( + '🔧 Round %d: fixed %d %s in %d %s', $round, + $appliedCount, + $appliedCount === 1 ? 'error' : 'errors', + count($roundChangedFiles), + count($roundChangedFiles) === 1 ? 'file' : 'files', )); + } - return 0; + if ($appliedCount === 0 || $round === self::FIX_ROUNDS_LIMIT) { + break; } $round++; + $errorOutput->writeLineFormatted(''); $errorOutput->writeLineFormatted(sprintf('Analysing fixed code (round %d)...', $round)); $command = ProcessHelper::getWorkerCommand( $_SERVER['argv'][0], self::NAME, $inceptionResult->getProjectConfigFile(), array_merge( - ['--' . self::OPTION_FIX_ROUND, '--' . ErrorsConsoleStyle::OPTION_NO_PROGRESS], + ['--' . self::OPTION_FIX_ROUND, $errorOutput->isDecorated() ? '--ansi' : '--no-ansi'], + (bool) $input->getOption(ErrorsConsoleStyle::OPTION_NO_PROGRESS) ? ['--' . ErrorsConsoleStyle::OPTION_NO_PROGRESS] : [], (bool) $input->getOption('fix') ? ['--fix'] : [], (bool) $input->getOption('fix-ignored') ? ['--fix-ignored'] : [], ), $input, ); $process = Process::fromShellCommandline($command, timeout: null); - $process->run(); + // the progress bar of the analysis is on stderr, the result of the round on stdout + $process->run(static function (string $type, string $buffer) use ($errorOutput): void { + if ($type !== Process::ERR) { + return; + } + + $errorOutput->writeRaw($buffer); + }); try { - /** @var array{fixable: int, applied: int} $roundResult */ + /** @var array{fixable: int, applied: int, changedFiles: list} $roundResult */ $roundResult = Json::decode($process->getOutput(), Json::FORCE_ARRAY); } catch (JsonException) { - $style->error(sprintf( + $stdOutput->getStyle()->error(sprintf( "%d %s fixed, but analysing the fixed code failed:\n%s", $fixedCount, $fixedCount === 1 ? 'error' : 'errors', - trim($process->getOutput() . "\n" . $process->getErrorOutput()), + trim($process->getOutput()), )); return 1; @@ -703,24 +732,27 @@ private function fixInRounds(InceptionResult $inceptionResult, InputInterface $i $fixableCount = $roundResult['fixable']; $appliedCount = $roundResult['applied']; - $fixedCount += $appliedCount; + $roundChangedFiles = $roundResult['changedFiles']; } - $leftCount = $fixableCount; - if ($leftCount > 0) { - $style->warning(sprintf( - '%d %s fixed, %d %s could not be fixed because of conflicting fixes', - $fixedCount, - $fixedCount === 1 ? 'error' : 'errors', - $leftCount, - $leftCount === 1 ? 'error' : 'errors', + $summary = sprintf( + '%d %s fixed in %d %s', + $fixedCount, + $fixedCount === 1 ? 'error' : 'errors', + count($changedFiles), + count($changedFiles) === 1 ? 'file' : 'files', + ); + if ($appliedCount > 0) { + $stdOutput->getStyle()->warning(sprintf('%s. Fixing stopped after %d rounds, run PHPStan again to see what is left.', $summary, $round)); + } elseif ($fixableCount > 0) { + $stdOutput->getStyle()->warning(sprintf( + '%s, %d %s could not be fixed because of conflicting fixes', + $summary, + $fixableCount, + $fixableCount === 1 ? 'error' : 'errors', )); } else { - $style->success(sprintf( - '%d %s fixed', - $fixedCount, - $fixedCount === 1 ? 'error' : 'errors', - )); + $stdOutput->getStyle()->success($summary); return 0; } From 1751524132c8f538804329f592cf7da1c3e5e358 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 04:59:35 +0000 Subject: [PATCH 16/24] Do not print the PHPStan Pro note on --fix --fix fixes errors itself since a long time, the note only adds noise to every run. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Command/AnalyseCommand.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 41502084ae4..7e59516b034 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -248,10 +248,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $inceptionResult->handleReturn(1, null, $this->analysisStartTime); } - if ($fixReported && !$fixRound) { - $inceptionResult->getErrorOutput()->getStyle()->note('The --fix CLI option no longer launches PHPStan Pro. Use --pro instead if you want to launch PHPStan Pro'); - } - } $errorOutput = $inceptionResult->getErrorOutput(); From 28a57052246efaab365becca9c757ddc94c074a4 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 05:08:58 +0000 Subject: [PATCH 17/24] Compute fix diffs against the current contents of a file The contents of a file were cached by its path for the whole process. When the file changed between analyses in one process, like in PHPStan Pro or in tests, the diffs were computed against the old contents and were never applied. --- src/Analyser/RuleErrorTransformer.php | 6 ++++-- tests/PHPStan/Fixable/FixIssetRuleTest.php | 25 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index 756c2dd46cf..325cc0b8871 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -312,11 +312,13 @@ private static function splitStringByLines(string $input): array */ private function getParsedFile(string $file): array { - if (array_key_exists($file, $this->parsedFiles)) { + // the file can change between analyses in one process, like PHPStan Pro or tests + $code = FileReader::read($file); + if (array_key_exists($file, $this->parsedFiles) && $this->parsedFiles[$file]['code'] === $code) { return $this->parsedFiles[$file]; } - $code = FileReader::read($file); + unset($this->parsedFiles[$file]); $this->parser->parse($code); if (count($this->parsedFiles) >= self::PARSED_FILES_LIMIT) { diff --git a/tests/PHPStan/Fixable/FixIssetRuleTest.php b/tests/PHPStan/Fixable/FixIssetRuleTest.php index 0a5fb402942..46b5dd53234 100644 --- a/tests/PHPStan/Fixable/FixIssetRuleTest.php +++ b/tests/PHPStan/Fixable/FixIssetRuleTest.php @@ -2,8 +2,14 @@ namespace PHPStan\Fixable; +use PHPStan\File\FileReader; +use PHPStan\File\FileWriter; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use function str_replace; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; /** * @extends RuleTestCase @@ -21,6 +27,25 @@ public function testRule(): void $this->fix(__DIR__ . '/data/isset.php', __DIR__ . '/data/isset.php.fixed'); } + public function testFixFileChangedSinceLastFix(): void + { + $file = tempnam(sys_get_temp_dir(), 'phpstan-fix'); + $expectedFile = tempnam(sys_get_temp_dir(), 'phpstan-fix'); + try { + FileWriter::write($file, FileReader::read(__DIR__ . '/data/isset.php')); + $this->fix($file, __DIR__ . '/data/isset.php.fixed'); + + // the diff has to be computed against the new contents, not the ones fixed before + $addComment = static fn (string $code): string => str_replace('namespace FixIsset;', "namespace FixIsset;\n\n// changed", $code); + FileWriter::write($file, $addComment(FileReader::read(__DIR__ . '/data/isset.php'))); + FileWriter::write($expectedFile, $addComment(FileReader::read(__DIR__ . '/data/isset.php.fixed'))); + $this->fix($file, $expectedFile); + } finally { + @unlink($file); + @unlink($expectedFile); + } + } + public function testFixInTraitInSameFile(): void { $this->fix(__DIR__ . '/data/trait/same-file-trait.php', __DIR__ . '/data/trait/same-file-trait.php.fixed'); From e55c4df824b46fca90f98d283bfbfa9901dc3f11 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 05:19:16 +0000 Subject: [PATCH 18/24] Fix in rounds in RuleTestCase::fix() Like phpstan analyse --fix, the fixed code is analysed again until nothing is left to fix, so fixes that overlap with other fixes and fixes of errors caused by other fixes are applied too. Later rounds analyse copies of the files in a temporary directory, next to each other. A test whose fix does not make its error go away now fails, the same fix would not finish with --fix either. FixIssetRule renamed variables forever, it now renames each one once. --- src/Testing/RuleTestCase.php | 94 +++++++++++++++---- tests/PHPStan/Fixable/FixIssetRule.php | 6 ++ tests/PHPStan/Fixable/MultiFixRule.php | 7 +- tests/PHPStan/Fixable/RemoveNodeRuleTest.php | 5 + tests/PHPStan/Fixable/data/isset.php | 2 +- tests/PHPStan/Fixable/data/isset.php.fixed | 2 +- .../Fixable/data/remove-node-rounds.php | 10 ++ .../Fixable/data/remove-node-rounds.php.fixed | 10 ++ 8 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 tests/PHPStan/Fixable/data/remove-node-rounds.php create mode 100644 tests/PHPStan/Fixable/data/remove-node-rounds.php.fixed diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 45aabff128a..188c373c220 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -2,6 +2,7 @@ namespace PHPStan\Testing; +use Nette\Utils\FileSystem; use PhpParser\Node; use PHPStan\Analyser\Analyser; use PHPStan\Analyser\AnalyserResultFinalizer; @@ -30,15 +31,22 @@ use PHPStan\Rules\Properties\ReadWritePropertiesExtension; use PHPStan\Rules\Rule; use PHPStan\ShouldNotHappenException; +use function array_combine; +use function array_flip; +use function array_intersect_key; +use function array_key_exists; use function array_map; use function array_merge; use function array_unique; use function array_values; +use function basename; use function count; use function implode; use function sprintf; use function str_replace; use function strcmp; +use function sys_get_temp_dir; +use function uniqid; use function usort; /** @@ -48,6 +56,8 @@ abstract class RuleTestCase extends PHPStanTestCase { + private const FIX_ROUNDS_LIMIT = 10; + private ?Analyser $analyser = null; /** @@ -235,6 +245,11 @@ static function (Error $error) use ($strictlyTypedSprintf): string { $this->assertSame($expectedErrorsString, $actualErrorsString); } + /** + * Like `phpstan analyse --fix`, the fixed code is analysed again until nothing is left to fix, + * so fixes that overlap with other fixes and fixes of errors caused by other fixes are applied too. + * A fix that is fixable again fails the test, it would not finish with --fix either. + */ public function fix(string $file, string $expectedFile): void { $this->fixOtherFile($file, $file, $expectedFile); @@ -243,36 +258,77 @@ public function fix(string $file, string $expectedFile): void /** * Analyses $file and $fixedFile together and asserts the fixes of $fixedFile, * like a trait file or a file the rule points to with RuleErrorBuilder::file(). + * + * Fixes in rounds like fix(). Later rounds analyse copies of the files in a temporary directory, + * so they do not fix traits, which are always read from their original file. */ public function fixOtherFile(string $file, string $fixedFile, string $expectedFile): void { - $fixedFile = $this->getFileHelper()->normalizePath($fixedFile); + $fileHelper = $this->getFileHelper(); + $fixedFile = $fileHelper->normalizePath($fixedFile); // a trait is analysed only when its file is analysed too - [$errors] = $this->gatherAnalyserErrorsWithDelayedErrors(array_values(array_unique([$this->getFileHelper()->normalizePath($file), $fixedFile]))); - $diffGroups = []; + $analysedFiles = array_values(array_unique([$fileHelper->normalizePath($file), $fixedFile])); $contentsByFile = [$fixedFile => FileReader::read($fixedFile)]; - foreach ($errors as $error) { - if ($error->getFixedErrorDiffs() === []) { - continue; - } + // original path => path analysed in the current round + $roundPaths = array_combine($analysedFiles, $analysedFiles); + $patcher = self::getContainer()->getByType(Patcher::class); + $tmpDir = sys_get_temp_dir() . '/' . uniqid('phpstan-fix-', true); + + try { + for ($round = 1;; $round++) { + [$errors] = $this->gatherAnalyserErrorsWithDelayedErrors(array_values(array_intersect_key($roundPaths, array_flip($analysedFiles)))); + $originalPaths = array_flip($roundPaths); + $diffGroups = []; + foreach ($errors as $error) { + $diffs = []; + foreach ($error->getFixedErrorDiffs() as $diff) { + // the fix of an error applies to all its files or none, all of them take part + $diffFile = $fileHelper->normalizePath($diff->file); + if ($round > 1) { + if (!array_key_exists($diffFile, $originalPaths)) { + // a trait read from its original file + continue 2; + } + $diffFile = $originalPaths[$diffFile]; + } + $contentsByFile[$diffFile] ??= FileReader::read($diffFile); + $diffs[] = new FixedErrorDiff($diffFile, $diff->originalHash, $diff->diff); + } + if ($diffs === []) { + continue; + } + + $diffGroups[] = $diffs; + } + + if ($diffGroups === []) { + break; + } - $diffs = []; - foreach ($error->getFixedErrorDiffs() as $diff) { - // the fix of an error applies to all its files or none, all of them take part - $diffFile = $this->getFileHelper()->normalizePath($diff->file); - $contentsByFile[$diffFile] ??= FileReader::read($diffFile); - $diffs[] = new FixedErrorDiff($diffFile, $diff->originalHash, $diff->diff); + $patchResult = $patcher->apply($contentsByFile, $diffGroups); + $this->assertGreaterThan(0, $patchResult['appliedCount'], 'Some fixes overlap and could not be applied together.'); + $this->assertLessThan(self::FIX_ROUNDS_LIMIT, $round, sprintf('Fixing did not finish after %d rounds.', $round)); + $contentsByFile = $patchResult['contents']; + + // a new directory every round, so nothing cached for the contents of an earlier round is reused; + // files stay next to each other, unless their names clash + $roundDir = $tmpDir . '/' . $round; + $usedNames = []; + foreach ($contentsByFile as $originalPath => $contents) { + $name = basename($originalPath); + $roundPath = isset($usedNames[$name]) ? sprintf('%s/%d/%s', $roundDir, count($usedNames), $name) : $roundDir . '/' . $name; + $usedNames[$name] = true; + $roundPaths[$originalPath] = $fileHelper->normalizePath($roundPath); + FileSystem::write($roundPaths[$originalPath], $contents); + } } - $diffGroups[] = $diffs; + } finally { + FileSystem::delete($tmpDir); } - $patcher = self::getContainer()->getByType(Patcher::class); - $patchResult = $patcher->apply($contentsByFile, $diffGroups); - $this->assertSame(0, $patchResult['skippedCount'], 'Some fixes overlap and could not be applied together.'); - $fixedFileContents = FileReader::read($expectedFile); - $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($patchResult['contents'][$fixedFile])); + $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($contentsByFile[$fixedFile])); } private function normalizeLineEndings(string $string): string diff --git a/tests/PHPStan/Fixable/FixIssetRule.php b/tests/PHPStan/Fixable/FixIssetRule.php index 7d9231a95ca..c35447818c0 100644 --- a/tests/PHPStan/Fixable/FixIssetRule.php +++ b/tests/PHPStan/Fixable/FixIssetRule.php @@ -9,6 +9,7 @@ use PHPStan\Rules\RuleErrorBuilder; use function is_string; use function sprintf; +use function str_ends_with; use function substr; /** @@ -29,6 +30,11 @@ public function processNode(Node $node, Scope $scope): array } $lastCharacter = substr($node->name, -1); + if (str_ends_with($node->name, $lastCharacter . $lastCharacter)) { + // already renamed, a fix has to make its error go away + return []; + } + $newName = $node->name . $lastCharacter; return [ diff --git a/tests/PHPStan/Fixable/MultiFixRule.php b/tests/PHPStan/Fixable/MultiFixRule.php index 65bff404add..febb3439d09 100644 --- a/tests/PHPStan/Fixable/MultiFixRule.php +++ b/tests/PHPStan/Fixable/MultiFixRule.php @@ -37,16 +37,17 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - if (!$node->name instanceof Name || !$node->getArgs()[0]->value instanceof String_) { + if (!$node->name instanceof Name) { return []; } $name = $node->name->toLowerString(); - if ($name !== 'renameall' && $name !== 'renameallornothing') { + $args = $node->getArgs(); + if (($name !== 'renameall' && $name !== 'renameallornothing') || !isset($args[0]) || !$args[0]->value instanceof String_) { return []; } - $otherFile = dirname($scope->getFile()) . '/' . $node->getArgs()[0]->value->value; + $otherFile = dirname($scope->getFile()) . '/' . $args[0]->value->value; $builder = RuleErrorBuilder::message('Renaming foo() to bar().')->identifier('tests.multiFix'); foreach ($this->findFooCalls($scope->getFile()) as $call) { $builder->fixNode($call, static function (FuncCall $call): FuncCall { diff --git a/tests/PHPStan/Fixable/RemoveNodeRuleTest.php b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php index fd58d01724c..47e99f51274 100644 --- a/tests/PHPStan/Fixable/RemoveNodeRuleTest.php +++ b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php @@ -35,6 +35,11 @@ public function testFix(): void $this->fix(__DIR__ . '/data/remove-node.php', __DIR__ . '/data/remove-node.php.fixed'); } + public function testOverlappingFixesAreAppliedInRounds(): void + { + $this->fix(__DIR__ . '/data/remove-node-rounds.php', __DIR__ . '/data/remove-node-rounds.php.fixed'); + } + public function testNodeNotInArrayIsNotFixable(): void { $fixable = []; diff --git a/tests/PHPStan/Fixable/data/isset.php b/tests/PHPStan/Fixable/data/isset.php index 9f2357bc6be..0d118f4a37c 100644 --- a/tests/PHPStan/Fixable/data/isset.php +++ b/tests/PHPStan/Fixable/data/isset.php @@ -3,7 +3,7 @@ namespace FixIsset; function (): void { - echo $foo; + echo $baz; if (isset($bar)) { diff --git a/tests/PHPStan/Fixable/data/isset.php.fixed b/tests/PHPStan/Fixable/data/isset.php.fixed index 5e9d895d708..46a69da4cfa 100644 --- a/tests/PHPStan/Fixable/data/isset.php.fixed +++ b/tests/PHPStan/Fixable/data/isset.php.fixed @@ -3,7 +3,7 @@ namespace FixIsset; function (): void { - echo $fooo; + echo $bazz; if (isset($barr)) { diff --git a/tests/PHPStan/Fixable/data/remove-node-rounds.php b/tests/PHPStan/Fixable/data/remove-node-rounds.php new file mode 100644 index 00000000000..43b7288ddd6 --- /dev/null +++ b/tests/PHPStan/Fixable/data/remove-node-rounds.php @@ -0,0 +1,10 @@ + Date: Mon, 2 Nov 2026 05:31:11 +0000 Subject: [PATCH 19/24] Add ErrorFixer for applying fixes outside of --fix ErrorFixer::fix() applies the fixes of the given errors to the files and tells which errors were fixed and which were skipped because their fixes overlap. Error::isFixable() tells whether an error has a fix. Extensions like an error formatter can fix errors without the diffs and the Patcher, which stay internal. --fix uses it too. --- src/Analyser/Error.php | 9 +++ src/Command/AnalyseCommand.php | 31 ++++------ src/Fixable/ErrorFixer.php | 77 ++++++++++++++++++++++++ src/Fixable/FixResult.php | 55 +++++++++++++++++ src/Fixable/Patcher.php | 54 +++-------------- tests/PHPStan/Fixable/ErrorFixerTest.php | 51 ++++++++++++++++ 6 files changed, 210 insertions(+), 67 deletions(-) create mode 100644 src/Fixable/ErrorFixer.php create mode 100644 src/Fixable/FixResult.php create mode 100644 tests/PHPStan/Fixable/ErrorFixerTest.php diff --git a/src/Analyser/Error.php b/src/Analyser/Error.php index 04c11790513..b7ba807a7fe 100644 --- a/src/Analyser/Error.php +++ b/src/Analyser/Error.php @@ -376,6 +376,15 @@ public function getMetadata(): array return $this->metadata; } + /** + * Whether the rule attached a fix with RuleErrorBuilder::fixNode() or removeNode(), + * to be applied with ErrorFixer or `phpstan analyse --fix`. + */ + public function isFixable(): bool + { + return $this->fixedErrorDiffs !== []; + } + /** * @internal Experimental * @deprecated Use getFixedErrorDiffs(), a fix can change several files. diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 7e59516b034..07a6a8f44d2 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -6,7 +6,6 @@ use Nette\Utils\JsonException; use OndraM\CiDetector\CiDetector; use Override; -use PHPStan\Analyser\Error; use PHPStan\Analyser\InternalError; use PHPStan\Command\ErrorFormatter\BaselineNeonErrorFormatter; use PHPStan\Command\ErrorFormatter\BaselinePhpErrorFormatter; @@ -23,7 +22,8 @@ use PHPStan\File\ParentDirectoryRelativePathHelper; use PHPStan\File\PathNotFoundException; use PHPStan\File\RelativePathHelper; -use PHPStan\Fixable\Patcher; +use PHPStan\Fixable\ErrorFixer; +use PHPStan\Fixable\FixResult; use PHPStan\Internal\AgentDetector; use PHPStan\Internal\BytesHelper; use PHPStan\Internal\ComposerHelper; @@ -565,7 +565,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $fixableErrors = []; if ($fixReported) { foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { - if ($fileSpecificError->getFixedErrorDiffs() === []) { + if (!$fileSpecificError->isFixable()) { continue; } @@ -578,17 +578,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $patcher = $container->getByType(Patcher::class); + $errorFixer = $container->getByType(ErrorFixer::class); $fixableErrorsCount = count($fixableErrors); if ($fixRound) { - $patchResult = $patcher->applyToFiles(array_map( - static fn (Error $error): array => $error->getFixedErrorDiffs(), - $fixableErrors, - )); + $fixResult = $errorFixer->fix($fixableErrors); $inceptionResult->getStdOutput()->writeRaw(Json::encode([ 'fixable' => $fixableErrorsCount, - 'applied' => $patchResult['appliedCount'], - 'changedFiles' => $patchResult['changedFiles'], + 'applied' => count($fixResult->getFixedErrors()), + 'changedFiles' => $fixResult->getChangedFiles(), ])); return $inceptionResult->handleReturn(0, $analysisResult->getPeakMemoryUsageBytes(), $this->analysisStartTime, $analysisResult->getWorkerCount()); @@ -602,10 +599,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $inceptionResult, $input, $fixableErrorsCount, - $patcher->applyToFiles(array_map( - static fn (Error $error): array => $error->getFixedErrorDiffs(), - $fixableErrors, - )), + $errorFixer->fix($fixableErrors), ); } } else { @@ -651,20 +645,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int * in a new process, which also saves the result cache, and fixes what is still fixable. * This applies fixes skipped because of a conflict and fixes of errors the previous round caused. */ - /** - * @param array{changedFiles: list, appliedCount: int, skippedCount: int} $patchResult the first round - */ private function fixInRounds( InceptionResult $inceptionResult, InputInterface $input, int $fixableCount, - array $patchResult, + FixResult $fixResult, ): int { $errorOutput = $inceptionResult->getErrorOutput(); $stdOutput = $inceptionResult->getStdOutput(); - $appliedCount = $patchResult['appliedCount']; - $roundChangedFiles = $patchResult['changedFiles']; + $appliedCount = count($fixResult->getFixedErrors()); + $roundChangedFiles = $fixResult->getChangedFiles(); $fixedCount = 0; $changedFiles = []; $round = 1; diff --git a/src/Fixable/ErrorFixer.php b/src/Fixable/ErrorFixer.php new file mode 100644 index 00000000000..1bf52d8e68a --- /dev/null +++ b/src/Fixable/ErrorFixer.php @@ -0,0 +1,77 @@ + $errors + */ + public function fix(array $errors): FixResult + { + $fixableErrors = []; + $diffGroups = []; + $contentsByFile = []; + foreach ($errors as $error) { + if (!$error->isFixable()) { + continue; + } + + $fixableErrors[] = $error; + $diffGroups[] = $error->getFixedErrorDiffs(); + foreach ($error->getFixedErrorDiffs() as $diff) { + if (array_key_exists($diff->file, $contentsByFile) || !is_file($diff->file)) { + continue; + } + + $contentsByFile[$diff->file] = FileReader::read($diff->file); + } + } + + $result = $this->patcher->apply($contentsByFile, $diffGroups); + + $changedFiles = []; + foreach ($result['contents'] as $file => $contents) { + if ($contents === $contentsByFile[$file]) { + continue; + } + + FileWriter::write($file, $contents); + $changedFiles[] = $file; + } + + $skippedErrors = []; + foreach ($result['skippedGroups'] as $key) { + $skippedErrors[] = $fixableErrors[$key]; + unset($fixableErrors[$key]); + } + + return new FixResult(array_values($fixableErrors), $skippedErrors, $changedFiles); + } + +} diff --git a/src/Fixable/FixResult.php b/src/Fixable/FixResult.php new file mode 100644 index 00000000000..ec6ff71c676 --- /dev/null +++ b/src/Fixable/FixResult.php @@ -0,0 +1,55 @@ + $fixedErrors + * @param list $skippedErrors + * @param list $changedFiles + */ + public function __construct( + private array $fixedErrors, + private array $skippedErrors, + private array $changedFiles, + ) + { + } + + /** + * Errors whose fixes were applied. Two errors with the same fix, like an error + * in a trait reported for each class using it, are both fixed by one change. + * + * @return list + */ + public function getFixedErrors(): array + { + return $this->fixedErrors; + } + + /** + * Errors whose fixes overlap with the fix of another error or whose files changed since the analysis. + * + * @return list + */ + public function getSkippedErrors(): array + { + return $this->skippedErrors; + } + + /** + * @return list + */ + public function getChangedFiles(): array + { + return $this->changedFiles; + } + +} diff --git a/src/Fixable/Patcher.php b/src/Fixable/Patcher.php index 412f29aa090..22ad568d023 100644 --- a/src/Fixable/Patcher.php +++ b/src/Fixable/Patcher.php @@ -5,15 +5,11 @@ use Nette\Utils\Strings; use PHPStan\Analyser\FixedErrorDiff; use PHPStan\DependencyInjection\AutowiredService; -use PHPStan\File\FileReader; -use PHPStan\File\FileWriter; -use function array_key_exists; use function array_splice; use function count; use function hash; use function implode; use function intdiv; -use function is_file; use function str_starts_with; use function substr; use const PREG_SPLIT_DELIM_CAPTURE; @@ -37,7 +33,7 @@ final class Patcher /** * @param array $contentsByFile current contents of the files the diffs change * @param list> $diffGroups diffs of each error - * @return array{contents: array, appliedCount: int, skippedCount: int} contents of the files in $contentsByFile + * @return array{contents: array, appliedCount: int, skippedCount: int, skippedGroups: list} contents of the files in $contentsByFile, keys of the skipped $diffGroups */ public function apply(array $contentsByFile, array $diffGroups): array { @@ -49,12 +45,12 @@ public function apply(array $contentsByFile, array $diffGroups): array /** @var array}>> $acceptedRuns per file sorted by start, non-overlapping */ $acceptedRuns = []; $appliedCount = 0; - $skippedCount = 0; - foreach ($diffGroups as $diffs) { + $skippedGroups = []; + foreach ($diffGroups as $groupKey => $diffs) { $insertionsByFile = []; foreach ($diffs as $diff) { if (!isset($hashes[$diff->file]) || $hashes[$diff->file] !== $diff->originalHash) { - $skippedCount++; + $skippedGroups[] = $groupKey; continue 2; } @@ -63,7 +59,7 @@ public function apply(array $contentsByFile, array $diffGroups): array foreach (self::parseChangeRuns($diff->diff) as $run) { $index = self::findInsertionIndex($fileRuns, $run); if ($index === null) { - $skippedCount++; + $skippedGroups[] = $groupKey; continue 3; } if (isset($fileRuns[$index]) && $fileRuns[$index] === $run) { @@ -96,44 +92,8 @@ public function apply(array $contentsByFile, array $diffGroups): array return [ 'contents' => $result, 'appliedCount' => $appliedCount, - 'skippedCount' => $skippedCount, - ]; - } - - /** - * Applies the diffs to the files on disk and writes the changed files. - * - * @param list> $diffGroups diffs of each error - * @return array{changedFiles: list, appliedCount: int, skippedCount: int} - */ - public function applyToFiles(array $diffGroups): array - { - $contentsByFile = []; - foreach ($diffGroups as $diffs) { - foreach ($diffs as $diff) { - if (array_key_exists($diff->file, $contentsByFile) || !is_file($diff->file)) { - continue; - } - - $contentsByFile[$diff->file] = FileReader::read($diff->file); - } - } - - $result = $this->apply($contentsByFile, $diffGroups); - $changedFiles = []; - foreach ($result['contents'] as $file => $contents) { - if ($contents === $contentsByFile[$file]) { - continue; - } - - FileWriter::write($file, $contents); - $changedFiles[] = $file; - } - - return [ - 'changedFiles' => $changedFiles, - 'appliedCount' => $result['appliedCount'], - 'skippedCount' => $result['skippedCount'], + 'skippedCount' => count($skippedGroups), + 'skippedGroups' => $skippedGroups, ]; } diff --git a/tests/PHPStan/Fixable/ErrorFixerTest.php b/tests/PHPStan/Fixable/ErrorFixerTest.php new file mode 100644 index 00000000000..b230831eff8 --- /dev/null +++ b/tests/PHPStan/Fixable/ErrorFixerTest.php @@ -0,0 +1,51 @@ + + */ +class ErrorFixerTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new RemoveNodeRule(); + } + + public function testOverlappingFixesAreSkipped(): void + { + $file = tempnam(sys_get_temp_dir(), 'phpstan-error-fixer'); + try { + $code = FileReader::read(__DIR__ . '/data/remove-node-rounds.php'); + FileWriter::write($file, $code); + $errors = $this->gatherAnalyserErrors([$file]); + $this->assertCount(3, $errors); + $notFixable = new Error('Not fixable.', $file); + + $result = self::getContainer()->getByType(ErrorFixer::class)->fix([$notFixable, ...$errors]); + + // the three arguments are removed by three errors, their changes of the same line overlap + $this->assertSame([$errors[0]], $result->getFixedErrors()); + $this->assertSame([$errors[1], $errors[2]], $result->getSkippedErrors()); + $this->assertSame([$file], $result->getChangedFiles()); + $this->assertSame( + str_replace('doFoo(REMOVE_ARG, 1, REMOVE_ARG, REMOVE_ARG);', 'doFoo(1, REMOVE_ARG, REMOVE_ARG);', $code), + FileReader::read($file), + ); + } finally { + @unlink($file); + } + } + +} From 2044024dfeaab7240b25712f239b3320af8a73f0 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 06:44:40 +0000 Subject: [PATCH 20/24] Tell agents to run --fix when some errors are fixable The instructions for agents now say how many of the reported errors can be fixed automatically, so the agent runs --fix before fixing the rest by hand. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- .github/workflows/e2e-tests.yml | 3 +++ src/Command/AnalyseCommand.php | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 65ed8386f90..ac31c5bd29a 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -971,6 +971,9 @@ jobs: cd e2e/fix composer install rm -rf src cycle tmp && cp -r original src && cp -r cycle-original cycle + OUTPUT=$(AI_AGENT=1 ../bashunit assert exit_code "1" "../../bin/phpstan analyse --error-format raw") + echo "$OUTPUT" + ../bashunit assert contains '7 of the errors can be fixed automatically. Run PHPStan again with --fix' "$OUTPUT" OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix") echo "$OUTPUT" ../bashunit assert contains 'Analysing fixed code (round 4)...' "$OUTPUT" diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index 07a6a8f44d2..71e09a67492 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -6,6 +6,7 @@ use Nette\Utils\JsonException; use OndraM\CiDetector\CiDetector; use Override; +use PHPStan\Analyser\Error; use PHPStan\Analyser\InternalError; use PHPStan\Command\ErrorFormatter\BaselineNeonErrorFormatter; use PHPStan\Command\ErrorFormatter\BaselinePhpErrorFormatter; @@ -42,6 +43,7 @@ use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\Process\Process; use Throwable; +use function array_filter; use function array_intersect; use function array_key_exists; use function array_map; @@ -620,6 +622,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int $errorOutput->writeLineFormatted('Do not use assert() or inline @var PHPDoc tag to override PHPStan\'s inferred type.'); $errorOutput->writeLineFormatted('Do not add type casts just to silence errors.'); $errorOutput->writeLineFormatted('Do not widen parameter or return types just to make the error go away.'); + + $fixableErrorsCount = count(array_filter($analysisResult->getFileSpecificErrors(), static fn (Error $error): bool => $error->isFixable())); + if ($fixableErrorsCount > 0) { + $errorOutput->writeLineFormatted(''); + $errorOutput->writeLineFormatted(sprintf( + '%d of the errors can be fixed automatically. Run PHPStan again with --fix to fix them first, then fix the rest.', + $fixableErrorsCount, + )); + } } $exitCode = $errorFormatter->formatErrors($analysisResult, $inceptionResult->getStdOutput()); } From 3d496ca148005a2cfd0e47f6aab1e96e07c650c7 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 07:17:25 +0000 Subject: [PATCH 21/24] Let PhpDocEditor edit PHPDoc text with token indexes Format-preserving printing needs token indexes, which the PHPDoc parser used by analysis does not collect, so the editor parses with its own configuration. editText() edits a PHPDoc that is not attached to a node. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Fixable/PhpDoc/PhpDocEditor.php | 40 ++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Fixable/PhpDoc/PhpDocEditor.php b/src/Fixable/PhpDoc/PhpDocEditor.php index 85962e47cd6..ada6438d154 100644 --- a/src/Fixable/PhpDoc/PhpDocEditor.php +++ b/src/Fixable/PhpDoc/PhpDocEditor.php @@ -9,8 +9,11 @@ use PHPStan\PhpDocParser\Ast\NodeVisitor\CloningVisitor; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode; use PHPStan\PhpDocParser\Lexer\Lexer; +use PHPStan\PhpDocParser\Parser\ConstExprParser; use PHPStan\PhpDocParser\Parser\PhpDocParser; use PHPStan\PhpDocParser\Parser\TokenIterator; +use PHPStan\PhpDocParser\Parser\TypeParser; +use PHPStan\PhpDocParser\ParserConfig; use PHPStan\PhpDocParser\Printer\Printer; use function count; @@ -22,8 +25,17 @@ final class PhpDocEditor { - public function __construct(private Printer $printer, private Lexer $lexer, private PhpDocParser $phpDocParser) + private Lexer $lexer; + + private PhpDocParser $phpDocParser; + + public function __construct(private Printer $printer) { + // format-preserving printing needs token indexes, which the parser used by analysis does not collect + $config = new ParserConfig(['lines' => true, 'indexes' => true]); + $constExprParser = new ConstExprParser($config); + $this->lexer = new Lexer($config); + $this->phpDocParser = new PhpDocParser($config, new TypeParser($config, $constExprParser), $constExprParser); } /** @@ -32,11 +44,23 @@ public function __construct(private Printer $printer, private Lexer $lexer, priv public function edit(\PhpParser\Node $node, callable $callback): void { $doc = $node->getDocComment(); - if ($doc === null) { - $phpDoc = '/** */'; - } else { - $phpDoc = $doc->getText(); + $phpDoc = $this->editText($doc === null ? '/** */' : $doc->getText(), $callback); + if ($phpDoc === null) { + $node->setAttribute('comments', []); + return; } + + $node->setDocComment(new Doc($phpDoc)); + } + + /** + * Edits the text of a PHPDoc with format-preserving printing. + * + * @param callable(Node): (Node|Node[]|null) $callback + * @return string|null null when the PHPDoc is left without contents + */ + public function editText(string $phpDoc, callable $callback): ?string + { $tokens = new TokenIterator($this->lexer->tokenize($phpDoc)); $phpDocNode = $this->phpDocParser->parse($tokens); @@ -51,12 +75,10 @@ public function edit(\PhpParser\Node $node, callable $callback): void [$newPhpDocNode] = $traverser->traverse([$newPhpDocNode]); if (count($newPhpDocNode->children) === 0) { - $node->setAttribute('comments', []); - return; + return null; } - $doc = new Doc($this->printer->printFormatPreserving($newPhpDocNode, $phpDocNode, $tokens)); - $node->setDocComment($doc); + return $this->printer->printFormatPreserving($newPhpDocNode, $phpDocNode, $tokens); } } From fe1ed85262558110166434e3aa85ea9d5e56a8e9 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 07:01:24 +0000 Subject: [PATCH 22/24] Make unmatched inline ignores fixable ignore.unmatchedIdentifier removes the identifier from the @phpstan-ignore comment, or the whole ignore when it is the only one. ignore.unmatchedLine removes the @phpstan-ignore-line / -next-line ignore. Plain comments are edited as text and left alone when they have other contents. PHPDocs are edited with PhpDocEditor, so their other tags are kept. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- build/baseline-pre-8.0.neon | 24 ++ src/Analyser/AnalyserResultFinalizer.php | 33 +- src/Analyser/Ignore/UnmatchedIgnoreFixer.php | 345 ++++++++++++++++++ src/Analyser/RuleErrorTransformer.php | 8 + src/Testing/RuleTestCase.php | 2 + .../Analyser/AnalyserResultFinalizerTest.php | 2 + tests/PHPStan/Analyser/AnalyserTest.php | 13 + .../Analyser/CollectedDataRuleReuseTest.php | 2 + .../Ignore/UnmatchedIgnoreFixerTest.php | 179 +++++++++ 9 files changed, 604 insertions(+), 4 deletions(-) create mode 100644 src/Analyser/Ignore/UnmatchedIgnoreFixer.php create mode 100644 tests/PHPStan/Analyser/Ignore/UnmatchedIgnoreFixerTest.php diff --git a/build/baseline-pre-8.0.neon b/build/baseline-pre-8.0.neon index 42c4ae6b539..169e2146096 100644 --- a/build/baseline-pre-8.0.neon +++ b/build/baseline-pre-8.0.neon @@ -157,3 +157,27 @@ parameters: identifier: property.internalClass count: 3 path: ../src/Parser/RichParser.php + + - + rawMessage: Access to property $id of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony. + identifier: property.internalClass + count: 6 + path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php + + - + rawMessage: Access to property $line of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony. + identifier: property.internalClass + count: 7 + path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php + + - + rawMessage: Access to property $pos of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony. + identifier: property.internalClass + count: 1 + path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php + + - + rawMessage: Access to property $text of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony. + identifier: property.internalClass + count: 2 + path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php diff --git a/src/Analyser/AnalyserResultFinalizer.php b/src/Analyser/AnalyserResultFinalizer.php index ffe1cf8e238..442de9ce6a4 100644 --- a/src/Analyser/AnalyserResultFinalizer.php +++ b/src/Analyser/AnalyserResultFinalizer.php @@ -4,6 +4,7 @@ use Closure; use PHPStan\AnalysedCodeException; +use PHPStan\Analyser\Ignore\UnmatchedIgnoreFixer; use PHPStan\Analyser\ResultCache\LazyCollectedData; use PHPStan\BetterReflection\NodeCompiler\Exception\UnableToCompileNode; use PHPStan\BetterReflection\Reflection\Exception\CircularReference; @@ -12,6 +13,7 @@ use PHPStan\DependencyInjection\AutowiredParameter; use PHPStan\DependencyInjection\AutowiredService; use PHPStan\DependencyInjection\ExtensionsCollection; +use PHPStan\File\FileReader; use PHPStan\Node\CollectedDataNode; use PHPStan\Node\CollectedDataNodeReads; use PHPStan\Rules\Registry as RuleRegistry; @@ -44,6 +46,7 @@ public function __construct( private RuleErrorTransformer $ruleErrorTransformer, private ScopeFactory $scopeFactory, private LocalIgnoresProcessor $localIgnoresProcessor, + private UnmatchedIgnoreFixer $unmatchedIgnoreFixer, #[AutowiredParameter] private bool $reportUnmatchedIgnoredErrors, private ValueDependencyCollector $valueDependencyCollector, @@ -399,6 +402,23 @@ private function mergeFilteredPhpErrors(AnalyserResult $analyserResult): Analyse ); } + /** + * @return list + */ + private function fixUnmatchedIgnore(string $file, ?string $code, int $line, ?string $identifier): array + { + if ($code === null) { + return []; + } + + $newCode = $this->unmatchedIgnoreFixer->fix($code, $line, $identifier); + if ($newCode === null) { + return []; + } + + return [$this->ruleErrorTransformer->createFixedErrorDiff($file, $code, $newCode)]; + } + /** * @param list $collectorErrors * @param list $locallyIgnoredCollectorErrors @@ -423,26 +443,31 @@ private function addUnmatchedIgnoredErrors( continue; } + $code = is_file($file) ? FileReader::read($file) : null; foreach ($lines as $line => $identifiers) { if ($identifiers === null) { - $errors[] = (new Error( + $errors[] = new Error( sprintf('No error to ignore is reported on line %d.', $line), $file, $line, false, $file, - ))->withIdentifier('ignore.unmatchedLine'); + identifier: 'ignore.unmatchedLine', + fixedErrorDiffs: $this->fixUnmatchedIgnore($file, $code, $line, null), + ); continue; } foreach ($identifiers as $identifier) { - $errors[] = (new Error( + $errors[] = new Error( sprintf('No error with identifier %s is reported on line %d.', $identifier['name'], $line), $file, $line, false, $file, - ))->withIdentifier('ignore.unmatchedIdentifier'); + identifier: 'ignore.unmatchedIdentifier', + fixedErrorDiffs: $this->fixUnmatchedIgnore($file, $code, $line, $identifier['name']), + ); } } } diff --git a/src/Analyser/Ignore/UnmatchedIgnoreFixer.php b/src/Analyser/Ignore/UnmatchedIgnoreFixer.php new file mode 100644 index 00000000000..460e483ccfb --- /dev/null +++ b/src/Analyser/Ignore/UnmatchedIgnoreFixer.php @@ -0,0 +1,345 @@ + $token) { + if ($token->id !== T_COMMENT && $token->id !== T_DOC_COMMENT) { + if ($token->id !== T_WHITESPACE) { + $previous = $token; + } + continue; + } + + $text = $token->text; + if (!str_contains($text, self::IGNORE_TAG)) { + continue; + } + + $endLine = $token->line + substr_count($text, "\n"); + $isNextLine = str_contains($text, '@phpstan-ignore-next-line'); + if ($isNextLine || str_contains($text, '@phpstan-ignore-line')) { + if ($identifier !== null) { + continue; + } + if ($token->id === T_DOC_COMMENT) { + $newText = $this->removePhpDocLineTag($text, $token->line, $line); + if ($newText === false) { + continue; + } + + return self::replaceComment($code, $token, $newText); + } + if ($endLine + ($isNextLine ? 1 : 0) !== $line) { + continue; + } + if (preg_match('~^(?://|#|/\*)\s*@phpstan-ignore-(?:next-)?line\b~', $text) !== 1) { + return null; + } + + return self::replaceComment($code, $token, null); + } + + if ($identifier === null) { + continue; + } + + if ($previous !== null && $previous->line === $token->line) { + $ignoredLine = $token->line; + } else { + $ignoredLine = $endLine; + $next = self::findNextCodeToken($tokens, $i); + if ($next !== null && $next->line === $endLine + 1) { + $ignoredLine = $next->line; + } + } + if ($ignoredLine !== $line) { + continue; + } + + $newText = $token->id === T_DOC_COMMENT + ? $this->removePhpDocIdentifier($text, $identifier) + : $this->removeCommentIdentifier($text, $identifier); + if ($newText === false) { + continue; + } + if ($newText === true) { + return null; + } + + return self::replaceComment($code, $token, $newText); + } + + return null; + } + + /** + * @return string|bool|null new text of the comment, null when the whole comment should be removed, + * false when the identifier is not there, true when the comment has other contents + */ + private function removeCommentIdentifier(string $text, string $identifier): string|bool|null + { + $listStart = (int) strpos($text, self::IGNORE_TAG) + strlen(self::IGNORE_TAG); + $result = $this->removeIdentifierFromList(substr($text, $listStart), $identifier); + if ($result === false) { + return false; + } + + [$newList, $listEnd] = $result; + if ($newList !== null) { + return substr($text, 0, $listStart) . $newList; + } + + $isOnlyIgnore = preg_match('~^(?://|#|/\*)\s*$~', substr($text, 0, $listStart - strlen(self::IGNORE_TAG))) === 1 + && preg_match('~^\s*(?:\*/)?$~', substr($text, $listStart + $listEnd)) === 1; + + return $isOnlyIgnore ? null : true; + } + + /** + * @return string|false|null new text of the PHPDoc, null when the whole PHPDoc should be removed, + * false when the identifier is not there + */ + private function removePhpDocIdentifier(string $text, string $identifier): string|false|null + { + $found = false; + $newText = $this->phpDocEditor->editText($text, function (Node $node) use ($identifier, &$found): Node { + if (!$node instanceof PhpDocNode) { + return $node; + } + + foreach ($node->children as $k => $child) { + if (!$child instanceof PhpDocTagNode || $child->name !== self::IGNORE_TAG) { + continue; + } + + // only the first ignore of a PHPDoc applies + if ($child->value instanceof GenericTagValueNode) { + $result = $this->removeIdentifierFromList($child->value->value, $identifier); + if ($result !== false) { + $found = true; + if ($result[0] === null) { + unset($node->children[$k]); + $node->children = array_values($node->children); + } else { + $child->value->value = $result[0]; + } + } + } + break; + } + + return $node; + }); + + return $found ? $newText : false; + } + + /** + * Removes the -line or -next-line tag of a PHPDoc that ignores $line, the same lines RichParser ignores for them. + * + * @return string|false|null new text of the PHPDoc, null when the whole PHPDoc should be removed, + * false when no such tag ignores $line + */ + private function removePhpDocLineTag(string $text, int $startLine, int $line): string|false|null + { + $endLine = $startLine + substr_count($text, "\n"); + $found = false; + $newText = $this->phpDocEditor->editText($text, static function (Node $node) use ($text, $startLine, $endLine, $line, &$found): Node { + if (!$node instanceof PhpDocNode) { + return $node; + } + + $offsets = []; + $candidates = []; + $lastTagKey = null; + foreach ($node->children as $k => $child) { + if (!$child instanceof PhpDocTagNode) { + continue; + } + + $lastTagKey = $k; + if ($child->name !== '@phpstan-ignore-line' && $child->name !== '@phpstan-ignore-next-line') { + continue; + } + + $offset = strpos($text, $child->name, $offsets[$child->name] ?? 0); + if ($offset === false) { + return $node; + } + $offsets[$child->name] = $offset + 1; + + $candidates[$k] = $startLine + substr_count(substr($text, 0, $offset), "\n") + ($child->name === '@phpstan-ignore-next-line' ? 1 : 0); + } + + foreach ($candidates as $k => $ignoredLine) { + // the last tag of a PHPDoc ignores the line after it + $child = $node->children[$k]; + if ($k === $lastTagKey && $child instanceof PhpDocTagNode && $child->name === '@phpstan-ignore-next-line') { + $ignoredLine = $endLine + 1; + } + if ($ignoredLine !== $line) { + continue; + } + + $found = true; + unset($node->children[$k]); + $node->children = array_values($node->children); + break; + } + + return $node; + }); + + return $found ? $newText : false; + } + + /** + * @return array{string|null, int}|false new list, null when the identifier was the only one, and where the list ends; + * false when the identifier is not there + */ + private function removeIdentifierFromList(string $list, string $identifier): array|false + { + $offset = 0; + $depth = 0; + $items = []; + $item = null; + foreach ($this->ignoreLexer->tokenize($list) as [$value, $type]) { + if ($depth === 0 && $type === IgnoreLexer::TOKEN_END) { + break; + } + + $end = $offset + strlen($value); + if ($type === IgnoreLexer::TOKEN_OPEN_PARENTHESIS) { + $depth++; + } elseif ($type === IgnoreLexer::TOKEN_CLOSE_PARENTHESIS) { + $depth--; + if ($depth === 0 && $item !== null) { + // the comment in parentheses belongs to the identifier + $item['end'] = $end; + } + } elseif ($depth === 0 && $type === IgnoreLexer::TOKEN_IDENTIFIER) { + if ($item !== null) { + $items[] = $item; + } + $item = ['name' => $value, 'start' => $offset, 'end' => $end]; + } + $offset = $end; + } + if ($item !== null) { + $items[] = $item; + } + + foreach ($items as $k => $item) { + if ($item['name'] !== $identifier) { + continue; + } + + if (count($items) === 1) { + return [null, $offset]; + } + + // with the comma and the whitespace next to it + if ($k < count($items) - 1) { + return [substr($list, 0, $item['start']) . substr($list, $items[$k + 1]['start']), $offset]; + } + + return [substr($list, 0, $items[$k - 1]['end']) . substr($list, $item['end']), $offset]; + } + + return false; + } + + /** + * @param Token[] $tokens + */ + private static function findNextCodeToken(array $tokens, int $i): ?Token + { + for ($j = $i + 1; $j < count($tokens); $j++) { + $id = $tokens[$j]->id; + if ($id !== T_WHITESPACE && $id !== T_COMMENT && $id !== T_DOC_COMMENT) { + return $tokens[$j]; + } + } + + return null; + } + + /** + * Replaces the comment with $newText. Without $newText, removes the line of a comment that is alone on it, + * otherwise the comment and the whitespace that separates it from the code. + */ + private static function replaceComment(string $code, Token $token, ?string $newText): string + { + $start = $token->pos; + $end = $start + strlen($token->text); + if ($newText !== null) { + return substr($code, 0, $start) . $newText . substr($code, $end); + } + + $lineStartPos = strrpos(substr($code, 0, $start), "\n"); + $lineStart = $lineStartPos === false ? 0 : $lineStartPos + 1; + $lineEnd = strpos($code, "\n", $end); + $before = substr($code, $lineStart, $start - $lineStart); + $after = substr($code, $end, ($lineEnd === false ? strlen($code) : $lineEnd) - $end); + + if (trim($before) === '' && trim($after) === '') { + return substr($code, 0, $lineStart) . ($lineEnd === false ? '' : substr($code, $lineEnd + 1)); + } + + if (trim($before) !== '') { + $start = $lineStart + strlen(rtrim($before, " \t")); + } else { + $end += strspn($after, " \t"); + } + + return substr($code, 0, $start) . substr($code, $end); + } + +} diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index 325cc0b8871..9bc3bb82609 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -247,6 +247,14 @@ private function fix(string $fixingFile, array $fileNodes, array $fixes): ?Fixed return new FixedErrorDiff($fixingFile, $parsedFile['hash'], $this->diff($parsedFile['code'], $newCode)); } + /** + * A fix that is not made through nodes, like removing a comment. + */ + public function createFixedErrorDiff(string $file, string $originalCode, string $newCode): FixedErrorDiff + { + return new FixedErrorDiff($file, hash('sha256', $originalCode), $this->diff($originalCode, $newCode)); + } + /** * Same output as Differ::diff(), but the common leading and trailing lines are found here in linear time. * Differ strips them too, but in quadratic time, which made each fix in a large file cost up to a second. diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 188c373c220..f853db70f66 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -11,6 +11,7 @@ use PHPStan\Analyser\FileAnalyser; use PHPStan\Analyser\FixedErrorDiff; use PHPStan\Analyser\Generics\TemplateArgumentObserver; +use PHPStan\Analyser\Ignore\UnmatchedIgnoreFixer; use PHPStan\Analyser\IgnoreErrorExtension; use PHPStan\Analyser\InternalError; use PHPStan\Analyser\LocalIgnoresProcessor; @@ -383,6 +384,7 @@ private function gatherAnalyserErrorsWithDelayedErrors(array $files): array self::getContainer()->getByType(RuleErrorTransformer::class), self::createScopeFactory($reflectionProvider, self::getContainer()->getService('typeSpecifier')), new LocalIgnoresProcessor(), + self::getContainer()->getByType(UnmatchedIgnoreFixer::class), true, self::getContainer()->getByType(ValueDependencyCollector::class), false, diff --git a/tests/PHPStan/Analyser/AnalyserResultFinalizerTest.php b/tests/PHPStan/Analyser/AnalyserResultFinalizerTest.php index 2d325e229b0..ae07a41cf89 100644 --- a/tests/PHPStan/Analyser/AnalyserResultFinalizerTest.php +++ b/tests/PHPStan/Analyser/AnalyserResultFinalizerTest.php @@ -3,6 +3,7 @@ namespace PHPStan\Analyser; use PhpParser\Node; +use PHPStan\Analyser\Ignore\UnmatchedIgnoreFixer; use PHPStan\Analyser\ResultCache\LazyCollectedData; use PHPStan\DependencyInjection\DirectExtensionsCollection; use PHPStan\Node\CollectedDataNode; @@ -89,6 +90,7 @@ private function createFinalizer(array $rules): AnalyserResultFinalizer self::getContainer()->getService('typeSpecifier'), ), new LocalIgnoresProcessor(), + self::getContainer()->getByType(UnmatchedIgnoreFixer::class), false, self::getContainer()->getByType(ValueDependencyCollector::class), false, diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index 8c68cedc877..2c571c8eda8 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -9,9 +9,12 @@ use PHPStan\Analyser\Generics\TemplateArgumentObserver; use PHPStan\Analyser\Ignore\IgnoredErrorHelper; use PHPStan\Analyser\Ignore\IgnoreLexer; +use PHPStan\Analyser\Ignore\UnmatchedIgnoreFixer; use PHPStan\Collectors\Registry as CollectorRegistry; use PHPStan\Dependency\DependencyResolver; use PHPStan\DependencyInjection\DirectExtensionsCollection; +use PHPStan\File\FileReader; +use PHPStan\Fixable\Patcher; use PHPStan\Parser\RichParser; use PHPStan\Rules\AlwaysFailRule; use PHPStan\Rules\DirectRegistry as DirectRuleRegistry; @@ -669,6 +672,15 @@ public function testIgnoreNextLineUnmatched(): void $this->assertStringContainsString('No error to ignore is reported on line', $result[$i]->getMessage()); $this->assertSame($line, $result[$i]->getLine()); } + + $file = $result[0]->getFilePath(); + $contents = FileReader::read($file); + $patched = (new Patcher())->apply([$file => $contents], [$result[0]->getFixedErrorDiffs(), $result[1]->getFixedErrorDiffs()]); + $this->assertSame(2, $patched['appliedCount']); + $this->assertSame( + str_replace(["\t\t/** @phpstan-ignore-next-line */\n", "\t\t * @phpstan-ignore-next-line\n"], '', $contents), + $patched['contents'][$file], + ); } #[DataProvider('dataTrueAndFalse')] @@ -811,6 +823,7 @@ private function runAnalyser( self::getContainer()->getService('typeSpecifier'), ), new LocalIgnoresProcessor(), + self::getContainer()->getByType(UnmatchedIgnoreFixer::class), $reportUnmatchedIgnoredErrors, self::getContainer()->getByType(ValueDependencyCollector::class), false, diff --git a/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php b/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php index b514e5bdd88..913691b1481 100644 --- a/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php +++ b/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php @@ -11,6 +11,7 @@ use PHPStan\Analyser\CollectedDataReuse\ThrowingRule; use PHPStan\Analyser\CollectedDataReuse\TrackingRule; use PHPStan\Analyser\CollectedDataReuse\UnregisteredValueRule; +use PHPStan\Analyser\Ignore\UnmatchedIgnoreFixer; use PHPStan\Analyser\ResultCache\LazyCollectedData; use PHPStan\Analyser\ResultCache\ResultCacheValueExtension; use PHPStan\Collectors\CollectedData; @@ -342,6 +343,7 @@ private function finalize(array $rules, array $collectedData, bool $onlyFiles, a self::getContainer()->getByType(RuleErrorTransformer::class), self::createScopeFactory(self::createReflectionProvider(), self::getContainer()->getService('typeSpecifier')), new LocalIgnoresProcessor(), + self::getContainer()->getByType(UnmatchedIgnoreFixer::class), false, $valueDependencyCollector ?? self::getContainer()->getByType(ValueDependencyCollector::class), $reuse, diff --git a/tests/PHPStan/Analyser/Ignore/UnmatchedIgnoreFixerTest.php b/tests/PHPStan/Analyser/Ignore/UnmatchedIgnoreFixerTest.php new file mode 100644 index 00000000000..a6b50d515d0 --- /dev/null +++ b/tests/PHPStan/Analyser/Ignore/UnmatchedIgnoreFixerTest.php @@ -0,0 +1,179 @@ + [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + "assertSame($expected, self::getContainer()->getByType(UnmatchedIgnoreFixer::class)->fix($code, $line, $identifier)); + } + + public static function dataNotFixable(): Generator + { + yield 'comment on its own line ignores the next line, not its own' => [ + " [ + " [ + " [ + " [ + "assertNull(self::getContainer()->getByType(UnmatchedIgnoreFixer::class)->fix($code, $line, $identifier)); + } + +} From 1d0a31e59dab4855d80135bcf2c84a194a51ead6 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 07:41:09 +0000 Subject: [PATCH 23/24] Report fixable errors in JSON error format Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- src/Command/ErrorFormatter/JsonErrorFormatter.php | 4 ++++ .../ErrorFormatter/JsonErrorFormatterTest.php | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Command/ErrorFormatter/JsonErrorFormatter.php b/src/Command/ErrorFormatter/JsonErrorFormatter.php index 0a4174d4e02..eaa19c5494e 100644 --- a/src/Command/ErrorFormatter/JsonErrorFormatter.php +++ b/src/Command/ErrorFormatter/JsonErrorFormatter.php @@ -54,6 +54,10 @@ public function formatErrors(AnalysisResult $analysisResult, Output $output): in $message['identifier'] = $fileSpecificError->getIdentifier(); } + if ($fileSpecificError->isFixable()) { + $message['fixable'] = true; + } + $errorsArray['files']->$file['messages'][] = $message; } diff --git a/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php index 19d05899f28..da63c9227eb 100644 --- a/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/JsonErrorFormatterTest.php @@ -4,6 +4,7 @@ use Nette\Utils\Json; use PHPStan\Analyser\Error; +use PHPStan\Analyser\FixedErrorDiff; use PHPStan\Command\AnalysisResult; use PHPStan\Testing\ErrorFormatterTestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -252,4 +253,17 @@ public function testFormatTip(string $tip, string $expectedTip): void $this->assertSame($expectedTip, $json['files']['/foo/bar.php']['messages'][0]['tip']); } + public function testFormatFixable(): void + { + $formatter = new JsonErrorFormatter(false); + $formatter->formatErrors(new AnalysisResult([ + new Error('Fixable', '/foo/bar.php', 1, fixedErrorDiffs: [new FixedErrorDiff('/foo/bar.php', 'hash', 'diff')]), + new Error('Not fixable', '/foo/bar.php', 2), + ], [], [], [], [], false, null, true, 0, false, []), $this->getOutput()); + + $json = Json::decode($this->getOutputContent(), Json::FORCE_ARRAY); + $this->assertTrue($json['files']['/foo/bar.php']['messages'][0]['fixable']); + $this->assertArrayNotHasKey('fixable', $json['files']['/foo/bar.php']['messages'][1]); + } + } From 0933083e30d16ee9e17c0384fe4f118f76bd83ea Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Mon, 2 Nov 2026 07:41:09 +0000 Subject: [PATCH 24/24] =?UTF-8?q?Issue=20bot:=20append=20=F0=9F=94=A7=20to?= =?UTF-8?q?=20messages=20of=20fixable=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Matches the table output, so an error becoming fixable or no longer fixable shows up in the diff. Amp-Thread-ID: https://ampcode.com/threads/T-01a198ef-d81e-7532-81f4-438bae7a4db3 --- .github/workflows/issue-bot.yml | 4 ++-- issue-bot/src/Console/RunCommand.php | 2 +- issue-bot/src/Playground/PlaygroundClient.php | 2 +- issue-bot/src/Playground/PlaygroundError.php | 5 +++-- issue-bot/tests/Console/RunCommandTest.php | 3 ++- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/issue-bot.yml b/.github/workflows/issue-bot.yml index 7b981a85250..989b8c7cc07 100644 --- a/.github/workflows/issue-bot.yml +++ b/.github/workflows/issue-bot.yml @@ -54,9 +54,9 @@ jobs: uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./issue-bot/tmp - key: "issue-bot-download-v8-${{ github.run_id }}" + key: "issue-bot-download-v9-${{ github.run_id }}" restore-keys: | - issue-bot-download-v8- + issue-bot-download-v9- - name: "Download data" working-directory: "issue-bot" diff --git a/issue-bot/src/Console/RunCommand.php b/issue-bot/src/Console/RunCommand.php index b6a88fad113..486b2f2aea1 100644 --- a/issue-bot/src/Console/RunCommand.php +++ b/issue-bot/src/Console/RunCommand.php @@ -262,7 +262,7 @@ public static function extractErrors(array $json, string $hash): array if (strpos($messageText, 'Internal error') !== false) { throw new Exception(sprintf('While analysing %s: %s', $hash, $messageText)); } - $errors[] = new PlaygroundError($message['line'] ?? -1, $messageText, $message['identifier'] ?? null); + $errors[] = new PlaygroundError($message['line'] ?? -1, $messageText, $message['identifier'] ?? null, $message['fixable'] ?? false); } } diff --git a/issue-bot/src/Playground/PlaygroundClient.php b/issue-bot/src/Playground/PlaygroundClient.php index d6f67cb0df6..c436ad074f3 100644 --- a/issue-bot/src/Playground/PlaygroundClient.php +++ b/issue-bot/src/Playground/PlaygroundClient.php @@ -25,7 +25,7 @@ public function getResult(string $hash): PlaygroundResult $versionedErrors = []; foreach ($json['versionedErrors'] as ['phpVersion' => $phpVersion, 'errors' => $errors]) { - $versionedErrors[(int) $phpVersion] = array_map(static fn (array $error) => new PlaygroundError($error['line'] ?? -1, $error['message'], $error['identifier'] ?? null), array_values($errors)); + $versionedErrors[(int) $phpVersion] = array_map(static fn (array $error) => new PlaygroundError($error['line'] ?? -1, $error['message'], $error['identifier'] ?? null, $error['fixable'] ?? false), array_values($errors)); } $options = []; diff --git a/issue-bot/src/Playground/PlaygroundError.php b/issue-bot/src/Playground/PlaygroundError.php index 1e55ac88b31..1a79fc012e3 100644 --- a/issue-bot/src/Playground/PlaygroundError.php +++ b/issue-bot/src/Playground/PlaygroundError.php @@ -5,7 +5,7 @@ class PlaygroundError { - public function __construct(private int $line, private string $message, private ?string $identifier) + public function __construct(private int $line, private string $message, private ?string $identifier, private bool $fixable = false) { } @@ -16,7 +16,8 @@ public function getLine(): int public function getMessage(): string { - return $this->message; + // shown like in the table output, so that an error becoming fixable shows up in the diff + return $this->fixable ? $this->message . ' 🔧' : $this->message; } public function getIdentifier(): ?string diff --git a/issue-bot/tests/Console/RunCommandTest.php b/issue-bot/tests/Console/RunCommandTest.php index b0866a7e144..0e08bbe3f1a 100644 --- a/issue-bot/tests/Console/RunCommandTest.php +++ b/issue-bot/tests/Console/RunCommandTest.php @@ -19,7 +19,7 @@ public function testExtractFileErrors(): void 'errors' => 2, 'messages' => [ ['message' => 'Dumped type: int', 'line' => 5, 'identifier' => 'phpstan.dumpType'], - ['message' => 'Something else', 'line' => 7, 'identifier' => 'foo.bar'], + ['message' => 'Something else', 'line' => 7, 'identifier' => 'foo.bar', 'fixable' => true], ], ], ], @@ -33,6 +33,7 @@ public function testExtractFileErrors(): void self::assertSame('Dumped type: int', $errors[0]->getMessage()); self::assertSame('phpstan.dumpType', $errors[0]->getIdentifier()); self::assertSame(7, $errors[1]->getLine()); + self::assertSame('Something else 🔧', $errors[1]->getMessage()); } public function testExtractTopLevelErrorsWhenNoFileErrors(): void