diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 99db5336ea1..ac31c5bd29a 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -967,6 +967,32 @@ 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 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" + ../bashunit assert not_contains 'round 5' "$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") + echo "$OUTPUT" + ../bashunit assert contains '[OK] 2 errors fixed' "$OUTPUT" + diff -u expected/Foo.php src/Foo.php + 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/.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/.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/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/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/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/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/e2e/fix/.gitignore b/e2e/fix/.gitignore new file mode 100644 index 00000000000..67962ade64f --- /dev/null +++ b/e2e/fix/.gitignore @@ -0,0 +1,5 @@ +/src +/cycle +/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/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 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; + } + +} + +/** + * Renames ping() to pong() and back, so fixing never ends. + * + * @implements Rule + */ +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/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 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/Analyser/AnalyserResultFinalizer.php b/src/Analyser/AnalyserResultFinalizer.php index 93826adf642..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; @@ -20,6 +22,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; @@ -42,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, @@ -307,6 +312,15 @@ 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) { + foreach ($error->getFixedErrorDiffs() as $fixedErrorDiff) { + if (!is_file($fixedErrorDiff->file) || hash_file('sha256', $fixedErrorDiff->file) !== $fixedErrorDiff->originalHash) { + return false; + } + } + } + return true; } @@ -388,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 @@ -412,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/Error.php b/src/Analyser/Error.php index 9d116266e4f..b7ba807a7fe 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, ); } @@ -373,12 +376,45 @@ 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. */ 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 +424,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 +436,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 +446,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 +463,7 @@ public static function decode(array $json): self $json['nodeType'] ?? null, $json['identifier'] ?? null, $json['metadata'] ?? [], - $fixedErrorDiff, + $fixedErrorDiffs, $json['traitContexts'] ?? [], ); } @@ -457,7 +485,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/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 44fba3671e4..9bc3bb82609 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -16,11 +16,14 @@ 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; 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; @@ -30,11 +33,17 @@ 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 is_file; +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 +55,8 @@ final class RuleErrorTransformer private Differ $differ; + private UnifiedDiffOutputBuilder $diffOutputBuilder; + /** @var array */ private array $parsedFiles = []; @@ -55,9 +66,12 @@ final class RuleErrorTransformer public function __construct( #[AutowiredParameter(ref: '@currentPhpVersionPhpParser')] private Parser $parser, + #[AutowiredParameter(ref: '@defaultAnalysisParser')] + private AnalysisParser $analysisParser, ) { - $this->differ = new Differ(new UnifiedDiffOutputBuilder('', addLineNumbers: true)); + $this->diffOutputBuilder = new UnifiedDiffOutputBuilder('', addLineNumbers: true); + $this->differ = new Differ($this->diffOutputBuilder); } /** @@ -89,6 +103,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 @@ -120,18 +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; } - $fixedErrorDiff = $this->fix( - $traitFilePath ?? $filePath, - $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( @@ -146,18 +176,35 @@ public function transform( get_class($node), $identifier, $metadata, - $fixedErrorDiff, + $fixedErrorDiffs, ); } /** + * Without $fileNodes (errors of CollectedDataNode rules, errors transformed inside collectors, + * 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 - * @param callable(Node): 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 === []) { - 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); @@ -169,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 */ @@ -188,7 +235,7 @@ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, c } } - if (!$replacingVisitor->isFound()) { + if (!$replacingVisitor->isComplete()) { return null; } @@ -197,7 +244,75 @@ 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($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. + * 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; } /** @@ -205,11 +320,13 @@ private function fix(string $fixingFile, array $fileNodes, Node $originalNode, c */ 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/src/Command/AnalyseApplication.php b/src/Command/AnalyseApplication.php index 7155cfcaf09..d9c223b153d 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->getFixedErrorDiffs() === []) { + continue; + } + + $fixableIgnoredErrors[] = $ignoredError; + } + foreach ($analyserResult->getLocallyIgnoredErrors() as $locallyIgnoredError) { + if ($locallyIgnoredError->getFixedErrorDiffs() === []) { + 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 b8a93670725..71e09a67492 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -2,8 +2,11 @@ namespace PHPStan\Command; +use Nette\Utils\Json; +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; @@ -20,14 +23,14 @@ use PHPStan\File\ParentDirectoryRelativePathHelper; use PHPStan\File\PathNotFoundException; use PHPStan\File\RelativePathHelper; -use PHPStan\Fixable\FileChangedException; -use PHPStan\Fixable\MergeConflictException; -use PHPStan\Fixable\Patcher; +use PHPStan\Fixable\ErrorFixer; +use PHPStan\Fixable\FixResult; use PHPStan\Internal\AgentDetector; use PHPStan\Internal\BytesHelper; 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; @@ -38,10 +41,13 @@ 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_filter; 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; @@ -64,6 +70,7 @@ use function stream_get_contents; use function strlen; use function substr; +use function trim; use const PATHINFO_BASENAME; use const PATHINFO_EXTENSION; @@ -86,6 +93,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 +129,8 @@ 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(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'), @@ -156,7 +170,10 @@ 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; + $fixRound = (bool) $input->getOption(self::OPTION_FIX_ROUND); $failWithoutResultCache = (bool) $input->getOption('fail-without-result-cache'); /** @var string|false|null $generateBaselineFile */ @@ -222,7 +239,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); } } @@ -233,7 +250,6 @@ 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'); } $errorOutput = $inceptionResult->getErrorOutput(); @@ -370,7 +386,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int throw new ShouldNotHappenException(); } - if ($fix) { + if ($fix && !$fixRound) { $inceptionResult->getErrorOutput()->writeLineFormatted('Analysing files...'); } @@ -549,70 +565,44 @@ 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->isFixable()) { + continue; + } - $fixableErrors[] = $fileSpecificError; + $fixableErrors[] = $fileSpecificError; + } + } + if ($fixIgnored) { + foreach ($analysisResult->getFixableIgnoredErrors() as $fixableIgnoredError) { + $fixableErrors[] = $fixableIgnoredError; + } } + $errorFixer = $container->getByType(ErrorFixer::class); $fixableErrorsCount = count($fixableErrors); + if ($fixRound) { + $fixResult = $errorFixer->fix($fixableErrors); + $inceptionResult->getStdOutput()->writeRaw(Json::encode([ + 'fixable' => $fixableErrorsCount, + 'applied' => count($fixResult->getFixedErrors()), + 'changedFiles' => $fixResult->getChangedFiles(), + ])); + + return $inceptionResult->handleReturn(0, $analysisResult->getPeakMemoryUsageBytes(), $this->analysisStartTime, $analysisResult->getWorkerCount()); + } + if ($fixableErrorsCount === 0) { $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 { - $finalFileContents = $patcher->applyDiffs($file, $diffs); - $errorOutput->getStyle()->progressAdvance($diffsCount); - } catch (FileChangedException | MergeConflictException) { - $skippedCount += $diffsCount; - $errorOutput->getStyle()->progressAdvance($diffsCount); - continue; - } - - FileWriter::write($file, $finalFileContents); - } - - $errorOutput->getStyle()->progressFinish(); - - if ($skippedCount > 0) { - $inceptionResult->getStdOutput()->getStyle()->warning(sprintf( - '%d %s fixed, %d %s skipped', - $fixableErrorsCount, - $fixableErrorsCount === 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, + $errorFixer->fix($fixableErrors), + ); } } else { if (AgentDetector::isRunningInAgent() && count($analysisResult->getFileSpecificErrors()) > 0) { @@ -632,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()); } @@ -652,6 +651,114 @@ 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, + FixResult $fixResult, + ): int + { + $errorOutput = $inceptionResult->getErrorOutput(); + $stdOutput = $inceptionResult->getStdOutput(); + $appliedCount = count($fixResult->getFixedErrors()); + $roundChangedFiles = $fixResult->getChangedFiles(); + $fixedCount = 0; + $changedFiles = []; + $round = 1; + 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', + )); + } + + 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, $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); + // 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, changedFiles: list} $roundResult */ + $roundResult = Json::decode($process->getOutput(), Json::FORCE_ARRAY); + } catch (JsonException) { + $stdOutput->getStyle()->error(sprintf( + "%d %s fixed, but analysing the fixed code failed:\n%s", + $fixedCount, + $fixedCount === 1 ? 'error' : 'errors', + trim($process->getOutput()), + )); + + return 1; + } + + $fixableCount = $roundResult['fixable']; + $appliedCount = $roundResult['applied']; + $roundChangedFiles = $roundResult['changedFiles']; + } + + $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 { + $stdOutput->getStyle()->success($summary); + + 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 ( 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/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/src/Command/ErrorFormatter/TableErrorFormatter.php b/src/Command/ErrorFormatter/TableErrorFormatter.php index cfc3cb33a0c..508555837e0 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()) { @@ -95,7 +96,11 @@ public function formatErrors( /** @var array $fileErrors */ $fileErrors = []; + $fixableErrorsCount = 0; foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { + if ($fileSpecificError->getFixedErrorDiffs() !== []) { + $fixableErrorsCount++; + } if (!isset($fileErrors[$fileSpecificError->getFile()])) { $fileErrors[$fileSpecificError->getFile()] = []; } @@ -116,6 +121,9 @@ public function formatErrors( ) { $message = '' . OutputFormatter::escape($message) . ''; } + if ($error->getFixedErrorDiffs() !== []) { + $message .= ' šŸ”§'; + } if ($error->getIdentifier() !== null) { $message .= "\n"; $message .= '🪪 ' . $error->getIdentifier(); @@ -214,9 +222,28 @@ 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')); + 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/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/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 @@ - $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/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 - * @throws FileChangedException - * @throws MergeConflictException + * @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, skippedGroups: list} contents of the files in $contentsByFile, keys of the skipped $diffGroups */ - public function applyDiffs(string $fileName, array $diffs): string + public function apply(array $contentsByFile, array $diffGroups): 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))); + $hashes = []; + foreach ($contentsByFile as $file => $contents) { + $hashes[$file] = hash('sha256', $contents); } - if (count($diffHunks) === 0) { - return $fileContents; - } - - $baseLines = Line::createArray(array_map( - static fn ($l) => [$l, Differ::OLD], - self::splitStringByLines($fileContents), - )); + /** @var array}>> $acceptedRuns per file sorted by start, non-overlapping */ + $acceptedRuns = []; + $appliedCount = 0; + $skippedGroups = []; + foreach ($diffGroups as $groupKey => $diffs) { + $insertionsByFile = []; + foreach ($diffs as $diff) { + if (!isset($hashes[$diff->file]) || $hashes[$diff->file] !== $diff->originalHash) { + $skippedGroups[] = $groupKey; + continue 2; + } - $refMerge = new ReflectionClass(PhpMerge::class); - $refMergeMethod = $refMerge->getMethod('mergeHunks'); - if (PHP_VERSION_ID < 80100) { - $refMergeMethod->setAccessible(true); - } + $fileRuns = $acceptedRuns[$diff->file] ?? []; + $insertions = []; + foreach (self::parseChangeRuns($diff->diff) as $run) { + $index = self::findInsertionIndex($fileRuns, $run); + if ($index === null) { + $skippedGroups[] = $groupKey; + continue 3; + } + if (isset($fileRuns[$index]) && $fileRuns[$index] === $run) { + // another error makes the exact same change + continue; + } + $insertions[] = [$index, $run]; + } - $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(); + $insertionsByFile[$diff->file] = $insertions; } - $result = Line::createArray(array_map( - static fn ($l) => [$l, Differ::OLD], - $merged, - )); + 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 implode('', array_map(static fn ($l) => $l->getContent(), $result)); + return [ + 'contents' => $result, + 'appliedCount' => $appliedCount, + 'skippedCount' => count($skippedGroups), + 'skippedGroups' => $skippedGroups, + ]; } /** - * @return array + * @param list}> $runs */ - private function reconstructFullDiff(string $originalText, string $unifiedDiff): array + private static function splice(string $fileContents, array $runs): string { - $originalLines = self::splitStringByLines($originalText); - $diffLines = self::splitStringByLines($unifiedDiff); + $baseLines = self::splitStringByLines($fileContents); $result = []; + $position = 0; + foreach ($runs as [$start, $removedCount, $addedLines]) { + for (; $position < $start; $position++) { + $result[] = $baseLines[$position]; + } + foreach ($addedLines as $addedLine) { + $result[] = $addedLine; + } + $position += $removedCount; + } + for ($baseLinesCount = count($baseLines); $position < $baseLinesCount; $position++) { + $result[] = $baseLines[$position]; + } - $origLineNo = 0; - $diffPos = 0; + return implode('', $result); + } + + /** + * 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 static function findInsertionIndex(array $acceptedRuns, array $run): ?int + { + // 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; + } + } - while ($diffPos < count($diffLines)) { - $line = $diffLines[$diffPos]; + 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; + } - $matches = Strings::match($line, '/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/'); - if ($matches !== null) { - // Parse hunk header - $origStart = (int) $matches[1] - 1; // 0-based - $diffPos++; + return $low; + } - // Emit kept lines before hunk - while ($origLineNo < $origStart) { - $result[] = [$originalLines[$origLineNo], Differ::OLD]; - $origLineNo++; - } + /** + * @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; + } - // Process hunk - while ($diffPos < count($diffLines)) { - $line = $diffLines[$diffPos]; - if (str_starts_with($line, '@@')) { - break; // next hunk - } + return $a[0] + $a[1] <= $b[0]; + } - $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]; - } + /** + * @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; + } - $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/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); } } diff --git a/src/Fixable/ReplacingNodeVisitor.php b/src/Fixable/ReplacingNodeVisitor.php index 1a7cd8ada2d..99081afc3b2 100644 --- a/src/Fixable/ReplacingNodeVisitor.php +++ b/src/Fixable/ReplacingNodeVisitor.php @@ -4,53 +4,160 @@ use Override; use PhpParser\Node; +use PhpParser\NodeVisitor; use PhpParser\NodeVisitorAbstract; use PHPStan\Node\VirtualNode; +use PHPStan\Rules\NodeFix; use PHPStan\ShouldNotHappenException; +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 { - private bool $found = false; + /** @var array> */ + private array $callbacks = []; + + /** @var array nodes in an array, those can be removed */ + private array $removable = []; + + private int $appliedCount = 0; + + private bool $failed = false; /** - * @param callable(Node): Node $newNodeCallable + * @param non-empty-list $fixes */ - public function __construct(private Node $originalNode, private $newNodeCallable) + public function __construct(array $fixes) { + foreach ($fixes as $fix) { + // 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; + } + } + + /** + * CloningVisitor has just cloned $node, its subnodes are still the original nodes. + */ + #[Override] + public function enterNode(Node $node): ?Node + { + foreach ($node->getSubNodeNames() as $subNodeName) { + $subNode = $node->$subNodeName; + if (!is_array($subNode)) { + continue; + } + + foreach ($subNode as $item) { + if (!$item instanceof Node) { + continue; + } + + $key = self::getKey($item); + if ($key === null || !array_key_exists($key, $this->callbacks)) { + continue; + } + + $this->removable[$key] = true; + } + } + + 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. + * whose children have already been cloned and fixed. */ #[Override] - public function leaveNode(Node $node): ?Node + public function leaveNode(Node $node): Node|int|null { - if ($this->found) { + $origNode = $node->getAttribute('origNode'); + if (!$origNode instanceof Node) { return null; } - $origNode = $node->getAttribute('origNode'); - if ($origNode !== $this->originalNode) { + $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; + } + return null; } - $this->found = true; + $this->appliedCount++; + $newNode = $node; + foreach ($this->callbacks[$key] as $callback) { + $newNode = $callback($newNode); + if ($newNode === NodeVisitor::REMOVE_NODE) { + if (!array_key_exists($key, $this->removable)) { + $this->failed = true; + return null; + } + + return NodeVisitor::REMOVE_NODE; + } - $callable = $this->newNodeCallable; - $newNode = $callable($node); - if ($newNode instanceof VirtualNode) { - throw new ShouldNotHappenException('Cannot print VirtualNode.'); + if ($newNode instanceof VirtualNode) { + throw new ShouldNotHappenException('Cannot print VirtualNode.'); + } } return $newNode; } - public function isFound(): bool + /** + * Whether every node was found and fixed. + */ + public function isComplete(): bool + { + return !$this->failed && $this->appliedCount === count($this->callbacks); + } + + private static function getKey(Node $node): ?string { - return $this->found; + $start = $node->getStartFilePos(); + if ($start < 0) { + return null; + } + + return get_class($node) . ':' . $start . ':' . $node->getEndFilePos(); + } + + /** + * @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/src/Rules/FixableNodeRuleError.php b/src/Rules/FixableNodeRuleError.php index bdb5c973f10..4244f86a44a 100644 --- a/src/Rules/FixableNodeRuleError.php +++ b/src/Rules/FixableNodeRuleError.php @@ -2,14 +2,10 @@ namespace PHPStan\Rules; -use PhpParser\Node; - interface FixableNodeRuleError extends RuleError { - public function getOriginalNode(): Node; - - /** @return callable(Node): 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 1e60d7129c1..c583bbbb796 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; @@ -122,14 +123,9 @@ public static function getRuleErrorTypes(): array FixableNodeRuleError::class, [ [ - 'originalNode', - '\PhpParser\Node', - '\PhpParser\Node', - ], - [ - 'newNodeCallable', - null, - 'callable(\PhpParser\Node): \PhpParser\Node', + 'nodeFixes', + 'array', + 'non-empty-list<\PHPStan\Rules\NodeFix>', ], ], ], @@ -319,22 +315,39 @@ public function nonIgnorable(): self } /** - * @internal Experimental + * 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. + * * @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() + * @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; } + /** + * 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. + * + * @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, ?string $file = null): self + { + return $this->fixNode($node, static fn (): int => NodeVisitor::REMOVE_NODE, $file); + } + /** * @return T */ diff --git a/src/Rules/RuleErrors/RuleError129.php b/src/Rules/RuleErrors/RuleError129.php index bd003c4f5a2..046e9dbd1a7 100644 --- a/src/Rules/RuleErrors/RuleError129.php +++ b/src/Rules/RuleErrors/RuleError129.php @@ -2,8 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -14,27 +14,20 @@ final class RuleError129 implements RuleError, FixableNodeRuleError public string $message; - public Node $originalNode; - - /** @var callable(Node): 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 + * @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 ba607b957e3..a5a5b44897c 100644 --- a/src/Rules/RuleErrors/RuleError131.php +++ b/src/Rules/RuleErrors/RuleError131.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -17,10 +17,8 @@ final class RuleError131 implements RuleError, LineRuleError, FixableNodeRuleErr public int $line; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -32,17 +30,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 481c6f0bcf5..f13e6157a6c 100644 --- a/src/Rules/RuleErrors/RuleError133.php +++ b/src/Rules/RuleErrors/RuleError133.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -19,10 +19,8 @@ final class RuleError133 implements RuleError, FileRuleError, FixableNodeRuleErr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -39,17 +37,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 11f52de24ae..6bf76168a6e 100644 --- a/src/Rules/RuleErrors/RuleError135.php +++ b/src/Rules/RuleErrors/RuleError135.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -22,10 +22,8 @@ final class RuleError135 implements RuleError, LineRuleError, FileRuleError, Fix public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -47,17 +45,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 47925389f35..7e6fd73d2d5 100644 --- a/src/Rules/RuleErrors/RuleError137.php +++ b/src/Rules/RuleErrors/RuleError137.php @@ -2,8 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -17,10 +17,8 @@ final class RuleError137 implements RuleError, TipRuleError, FixableNodeRuleErro public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -32,17 +30,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 d40a1721d6f..fc85c3859f6 100644 --- a/src/Rules/RuleErrors/RuleError139.php +++ b/src/Rules/RuleErrors/RuleError139.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -20,10 +20,8 @@ final class RuleError139 implements RuleError, LineRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -40,17 +38,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 5713a025ba4..42c3151c243 100644 --- a/src/Rules/RuleErrors/RuleError141.php +++ b/src/Rules/RuleErrors/RuleError141.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +22,8 @@ final class RuleError141 implements RuleError, FileRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -47,17 +45,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 1a08b2cf53f..6b5b5442ba1 100644 --- a/src/Rules/RuleErrors/RuleError143.php +++ b/src/Rules/RuleErrors/RuleError143.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -25,10 +25,8 @@ final class RuleError143 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -55,17 +53,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 f23ae4b9e7c..6c87a27fcea 100644 --- a/src/Rules/RuleErrors/RuleError145.php +++ b/src/Rules/RuleErrors/RuleError145.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -17,10 +17,8 @@ final class RuleError145 implements RuleError, IdentifierRuleError, FixableNodeR public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -32,17 +30,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 47a80d87d8d..a578aeaa99b 100644 --- a/src/Rules/RuleErrors/RuleError147.php +++ b/src/Rules/RuleErrors/RuleError147.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -20,10 +20,8 @@ final class RuleError147 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -40,17 +38,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 802779e5600..14a39aeff80 100644 --- a/src/Rules/RuleErrors/RuleError149.php +++ b/src/Rules/RuleErrors/RuleError149.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -22,10 +22,8 @@ final class RuleError149 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -47,17 +45,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 284a5700c51..2a719c715f8 100644 --- a/src/Rules/RuleErrors/RuleError151.php +++ b/src/Rules/RuleErrors/RuleError151.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -25,10 +25,8 @@ final class RuleError151 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -55,17 +53,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 24052dc8c9c..e34eeab3d94 100644 --- a/src/Rules/RuleErrors/RuleError153.php +++ b/src/Rules/RuleErrors/RuleError153.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -20,10 +20,8 @@ final class RuleError153 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -40,17 +38,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 038f19d0797..f75dca0a9d6 100644 --- a/src/Rules/RuleErrors/RuleError155.php +++ b/src/Rules/RuleErrors/RuleError155.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +23,8 @@ final class RuleError155 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -48,17 +46,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 a2a71b9acae..7356ab049c6 100644 --- a/src/Rules/RuleErrors/RuleError157.php +++ b/src/Rules/RuleErrors/RuleError157.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -25,10 +25,8 @@ final class RuleError157 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -55,17 +53,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 638054207c6..3db8d021fdd 100644 --- a/src/Rules/RuleErrors/RuleError159.php +++ b/src/Rules/RuleErrors/RuleError159.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -28,10 +28,8 @@ final class RuleError159 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -63,17 +61,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 008cfef2de8..1d47ef9e1be 100644 --- a/src/Rules/RuleErrors/RuleError161.php +++ b/src/Rules/RuleErrors/RuleError161.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -18,10 +18,8 @@ final class RuleError161 implements RuleError, MetadataRuleError, FixableNodeRul /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -36,17 +34,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 840450cce04..7d88b27a85d 100644 --- a/src/Rules/RuleErrors/RuleError163.php +++ b/src/Rules/RuleErrors/RuleError163.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -21,10 +21,8 @@ final class RuleError163 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -44,17 +42,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 79eb32732d1..e62ecb64977 100644 --- a/src/Rules/RuleErrors/RuleError165.php +++ b/src/Rules/RuleErrors/RuleError165.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -23,10 +23,8 @@ final class RuleError165 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -51,17 +49,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 ccc7d2f3e83..11fce81716d 100644 --- a/src/Rules/RuleErrors/RuleError167.php +++ b/src/Rules/RuleErrors/RuleError167.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -26,10 +26,8 @@ final class RuleError167 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -59,17 +57,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 7f106fec80b..87da8b7579f 100644 --- a/src/Rules/RuleErrors/RuleError169.php +++ b/src/Rules/RuleErrors/RuleError169.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -21,10 +21,8 @@ final class RuleError169 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -44,17 +42,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 bd01419ffbb..6782baf324c 100644 --- a/src/Rules/RuleErrors/RuleError171.php +++ b/src/Rules/RuleErrors/RuleError171.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -24,10 +24,8 @@ final class RuleError171 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -52,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 17e1855459f..f24b785db97 100644 --- a/src/Rules/RuleErrors/RuleError173.php +++ b/src/Rules/RuleErrors/RuleError173.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -26,10 +26,8 @@ final class RuleError173 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -59,17 +57,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 ed0f4965f7b..6c36d9f2e72 100644 --- a/src/Rules/RuleErrors/RuleError175.php +++ b/src/Rules/RuleErrors/RuleError175.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -29,10 +29,8 @@ final class RuleError175 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -67,17 +65,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 2acb39c8657..4b533d9704d 100644 --- a/src/Rules/RuleErrors/RuleError177.php +++ b/src/Rules/RuleErrors/RuleError177.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -21,10 +21,8 @@ final class RuleError177 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -44,17 +42,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 128b9187435..bb155fc9f8a 100644 --- a/src/Rules/RuleErrors/RuleError179.php +++ b/src/Rules/RuleErrors/RuleError179.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -24,10 +24,8 @@ final class RuleError179 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -52,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 601aaf38c8e..93863a58fd7 100644 --- a/src/Rules/RuleErrors/RuleError181.php +++ b/src/Rules/RuleErrors/RuleError181.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -26,10 +26,8 @@ final class RuleError181 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -59,17 +57,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 61f5965218d..0cee596d2ed 100644 --- a/src/Rules/RuleErrors/RuleError183.php +++ b/src/Rules/RuleErrors/RuleError183.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; /** @@ -29,10 +29,8 @@ final class RuleError183 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -67,17 +65,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 14dd4f7a9d0..7a9fefbb890 100644 --- a/src/Rules/RuleErrors/RuleError185.php +++ b/src/Rules/RuleErrors/RuleError185.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -24,10 +24,8 @@ final class RuleError185 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -52,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 a76455ad719..d2f0b1fb2fb 100644 --- a/src/Rules/RuleErrors/RuleError187.php +++ b/src/Rules/RuleErrors/RuleError187.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError187 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -60,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 d6b044c4265..0469c572a27 100644 --- a/src/Rules/RuleErrors/RuleError189.php +++ b/src/Rules/RuleErrors/RuleError189.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -29,10 +29,8 @@ final class RuleError189 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -67,17 +65,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 55b9f266627..bbc51f0df35 100644 --- a/src/Rules/RuleErrors/RuleError191.php +++ b/src/Rules/RuleErrors/RuleError191.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -32,10 +32,8 @@ final class RuleError191 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -75,17 +73,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 452a3d7195b..61ead7b5bfc 100644 --- a/src/Rules/RuleErrors/RuleError193.php +++ b/src/Rules/RuleErrors/RuleError193.php @@ -2,8 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -15,27 +15,20 @@ final class RuleError193 implements RuleError, NonIgnorableRuleError, FixableNod public string $message; - public Node $originalNode; - - /** @var callable(Node): 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 + * @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 0c662f1da3d..10ea9632f40 100644 --- a/src/Rules/RuleErrors/RuleError195.php +++ b/src/Rules/RuleErrors/RuleError195.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -18,10 +18,8 @@ final class RuleError195 implements RuleError, LineRuleError, NonIgnorableRuleEr public int $line; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -33,17 +31,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e2b5af378ca..084a5f3e3e2 100644 --- a/src/Rules/RuleErrors/RuleError197.php +++ b/src/Rules/RuleErrors/RuleError197.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -20,10 +20,8 @@ final class RuleError197 implements RuleError, FileRuleError, NonIgnorableRuleEr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -40,17 +38,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 c9ed6c09016..7bc6d8791df 100644 --- a/src/Rules/RuleErrors/RuleError199.php +++ b/src/Rules/RuleErrors/RuleError199.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -23,10 +23,8 @@ final class RuleError199 implements RuleError, LineRuleError, FileRuleError, Non public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -48,17 +46,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 2ecf6acaadd..97dd1f05b5f 100644 --- a/src/Rules/RuleErrors/RuleError201.php +++ b/src/Rules/RuleErrors/RuleError201.php @@ -2,8 +2,8 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -18,10 +18,8 @@ final class RuleError201 implements RuleError, TipRuleError, NonIgnorableRuleErr public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -33,17 +31,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 a04fc867b2c..3aa56ecce08 100644 --- a/src/Rules/RuleErrors/RuleError203.php +++ b/src/Rules/RuleErrors/RuleError203.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -21,10 +21,8 @@ final class RuleError203 implements RuleError, LineRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -41,17 +39,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 697c9eb673d..6c8c91dd0fc 100644 --- a/src/Rules/RuleErrors/RuleError205.php +++ b/src/Rules/RuleErrors/RuleError205.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +23,8 @@ final class RuleError205 implements RuleError, FileRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -48,17 +46,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 8ee9144bc41..7430c5826e1 100644 --- a/src/Rules/RuleErrors/RuleError207.php +++ b/src/Rules/RuleErrors/RuleError207.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError207 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -56,17 +54,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e007d8ed6c8..31b7bce3367 100644 --- a/src/Rules/RuleErrors/RuleError209.php +++ b/src/Rules/RuleErrors/RuleError209.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -18,10 +18,8 @@ final class RuleError209 implements RuleError, IdentifierRuleError, NonIgnorable public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -33,17 +31,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 6e56086b320..fe5ae8c0d59 100644 --- a/src/Rules/RuleErrors/RuleError211.php +++ b/src/Rules/RuleErrors/RuleError211.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -21,10 +21,8 @@ final class RuleError211 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -41,17 +39,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 a9e6203b319..de954e9ef18 100644 --- a/src/Rules/RuleErrors/RuleError213.php +++ b/src/Rules/RuleErrors/RuleError213.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -23,10 +23,8 @@ final class RuleError213 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -48,17 +46,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 01c82029576..51be06114e1 100644 --- a/src/Rules/RuleErrors/RuleError215.php +++ b/src/Rules/RuleErrors/RuleError215.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError215 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -56,17 +54,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e78f445f2ba..896cac199d4 100644 --- a/src/Rules/RuleErrors/RuleError217.php +++ b/src/Rules/RuleErrors/RuleError217.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -21,10 +21,8 @@ final class RuleError217 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -41,17 +39,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 2bdc632dc07..fbd9f427308 100644 --- a/src/Rules/RuleErrors/RuleError219.php +++ b/src/Rules/RuleErrors/RuleError219.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -24,10 +24,8 @@ final class RuleError219 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -49,17 +47,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 d43a6004fa6..29ca8a4000e 100644 --- a/src/Rules/RuleErrors/RuleError221.php +++ b/src/Rules/RuleErrors/RuleError221.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError221 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -56,17 +54,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 b3287c9a056..5fbaca86e56 100644 --- a/src/Rules/RuleErrors/RuleError223.php +++ b/src/Rules/RuleErrors/RuleError223.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -29,10 +29,8 @@ final class RuleError223 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -64,17 +62,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 06ef862f283..8ae53206b26 100644 --- a/src/Rules/RuleErrors/RuleError225.php +++ b/src/Rules/RuleErrors/RuleError225.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -19,10 +19,8 @@ final class RuleError225 implements RuleError, MetadataRuleError, NonIgnorableRu /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -37,17 +35,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 633cee8a5c4..83bc7c1e5aa 100644 --- a/src/Rules/RuleErrors/RuleError227.php +++ b/src/Rules/RuleErrors/RuleError227.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -22,10 +22,8 @@ final class RuleError227 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -45,17 +43,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 42c17069737..c168e20470e 100644 --- a/src/Rules/RuleErrors/RuleError229.php +++ b/src/Rules/RuleErrors/RuleError229.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -24,10 +24,8 @@ final class RuleError229 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -52,17 +50,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 bbbdb5a38f6..9277017490c 100644 --- a/src/Rules/RuleErrors/RuleError231.php +++ b/src/Rules/RuleErrors/RuleError231.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError231 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -60,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 b80cc0c36de..c3d3be1d9c4 100644 --- a/src/Rules/RuleErrors/RuleError233.php +++ b/src/Rules/RuleErrors/RuleError233.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +22,8 @@ final class RuleError233 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -45,17 +43,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 aaf1c80deeb..d50acf5ccb5 100644 --- a/src/Rules/RuleErrors/RuleError235.php +++ b/src/Rules/RuleErrors/RuleError235.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -25,10 +25,8 @@ final class RuleError235 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -53,17 +51,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 1d4abc43324..8a638eda137 100644 --- a/src/Rules/RuleErrors/RuleError237.php +++ b/src/Rules/RuleErrors/RuleError237.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError237 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -60,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 5ee0033dc21..f56a1a38804 100644 --- a/src/Rules/RuleErrors/RuleError239.php +++ b/src/Rules/RuleErrors/RuleError239.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -30,10 +30,8 @@ final class RuleError239 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -68,17 +66,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 65d853915a1..029871acba0 100644 --- a/src/Rules/RuleErrors/RuleError241.php +++ b/src/Rules/RuleErrors/RuleError241.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -22,10 +22,8 @@ final class RuleError241 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -45,17 +43,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e5762ee32b3..2d8a7946c89 100644 --- a/src/Rules/RuleErrors/RuleError243.php +++ b/src/Rules/RuleErrors/RuleError243.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -25,10 +25,8 @@ final class RuleError243 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -53,17 +51,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 369e7cbee33..24fac503e76 100644 --- a/src/Rules/RuleErrors/RuleError245.php +++ b/src/Rules/RuleErrors/RuleError245.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError245 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -60,17 +58,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 0a482fa833b..f030c5dfa9d 100644 --- a/src/Rules/RuleErrors/RuleError247.php +++ b/src/Rules/RuleErrors/RuleError247.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -30,10 +30,8 @@ final class RuleError247 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -68,17 +66,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 ed86576c33f..93fc5e3cdd6 100644 --- a/src/Rules/RuleErrors/RuleError249.php +++ b/src/Rules/RuleErrors/RuleError249.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -25,10 +25,8 @@ final class RuleError249 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -53,17 +51,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 b77d8060f82..660013fec41 100644 --- a/src/Rules/RuleErrors/RuleError251.php +++ b/src/Rules/RuleErrors/RuleError251.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -28,10 +28,8 @@ final class RuleError251 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -61,17 +59,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 17fad64bc19..51cc012e2ab 100644 --- a/src/Rules/RuleErrors/RuleError253.php +++ b/src/Rules/RuleErrors/RuleError253.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -30,10 +30,8 @@ final class RuleError253 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -68,17 +66,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 61d6fbd5055..b8bf2c5bbc6 100644 --- a/src/Rules/RuleErrors/RuleError255.php +++ b/src/Rules/RuleErrors/RuleError255.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -33,10 +33,8 @@ final class RuleError255 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; public function getMessage(): string { @@ -76,17 +74,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 8e5885de9dc..ce50b42aa32 100644 --- a/src/Rules/RuleErrors/RuleError385.php +++ b/src/Rules/RuleErrors/RuleError385.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -15,10 +15,8 @@ final class RuleError385 implements RuleError, FixableNodeRuleError, FileDepende public string $message; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -28,17 +26,12 @@ public function getMessage(): string return $this->message; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 f86720e5f7f..e56c2a7cedc 100644 --- a/src/Rules/RuleErrors/RuleError387.php +++ b/src/Rules/RuleErrors/RuleError387.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -18,10 +18,8 @@ final class RuleError387 implements RuleError, LineRuleError, FixableNodeRuleErr public int $line; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -36,17 +34,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 34208dc7f69..f48e60781af 100644 --- a/src/Rules/RuleErrors/RuleError389.php +++ b/src/Rules/RuleErrors/RuleError389.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -20,10 +20,8 @@ final class RuleError389 implements RuleError, FileRuleError, FixableNodeRuleErr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -43,17 +41,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 987c953124b..286726ae123 100644 --- a/src/Rules/RuleErrors/RuleError391.php +++ b/src/Rules/RuleErrors/RuleError391.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -23,10 +23,8 @@ final class RuleError391 implements RuleError, LineRuleError, FileRuleError, Fix public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -51,17 +49,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 203005cb45c..750c7486fb9 100644 --- a/src/Rules/RuleErrors/RuleError393.php +++ b/src/Rules/RuleErrors/RuleError393.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -18,10 +18,8 @@ final class RuleError393 implements RuleError, TipRuleError, FixableNodeRuleErro public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -36,17 +34,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 08db496f89e..1c5097476bc 100644 --- a/src/Rules/RuleErrors/RuleError395.php +++ b/src/Rules/RuleErrors/RuleError395.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -21,10 +21,8 @@ final class RuleError395 implements RuleError, LineRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -44,17 +42,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 8753b690c93..c52d5986aed 100644 --- a/src/Rules/RuleErrors/RuleError397.php +++ b/src/Rules/RuleErrors/RuleError397.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -23,10 +23,8 @@ final class RuleError397 implements RuleError, FileRuleError, TipRuleError, Fixa public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -51,17 +49,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 5422e84ee62..4be9084f0bc 100644 --- a/src/Rules/RuleErrors/RuleError399.php +++ b/src/Rules/RuleErrors/RuleError399.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError399 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -59,17 +57,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 7895154f147..b6d681fb363 100644 --- a/src/Rules/RuleErrors/RuleError401.php +++ b/src/Rules/RuleErrors/RuleError401.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -18,10 +18,8 @@ final class RuleError401 implements RuleError, IdentifierRuleError, FixableNodeR public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -36,17 +34,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 c5cb7e881fb..062658d2392 100644 --- a/src/Rules/RuleErrors/RuleError403.php +++ b/src/Rules/RuleErrors/RuleError403.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -21,10 +21,8 @@ final class RuleError403 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -44,17 +42,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 69a3896c029..fbd2379add8 100644 --- a/src/Rules/RuleErrors/RuleError405.php +++ b/src/Rules/RuleErrors/RuleError405.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -23,10 +23,8 @@ final class RuleError405 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -51,17 +49,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 01fa71e9b80..97b05d1386f 100644 --- a/src/Rules/RuleErrors/RuleError407.php +++ b/src/Rules/RuleErrors/RuleError407.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; /** @@ -26,10 +26,8 @@ final class RuleError407 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -59,17 +57,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 3ca74e13257..c00c00d6c9e 100644 --- a/src/Rules/RuleErrors/RuleError409.php +++ b/src/Rules/RuleErrors/RuleError409.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -21,10 +21,8 @@ final class RuleError409 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -44,17 +42,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 fa4978f580b..e81f89b0934 100644 --- a/src/Rules/RuleErrors/RuleError411.php +++ b/src/Rules/RuleErrors/RuleError411.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -24,10 +24,8 @@ final class RuleError411 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -52,17 +50,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 beb048bdc46..2dc52407995 100644 --- a/src/Rules/RuleErrors/RuleError413.php +++ b/src/Rules/RuleErrors/RuleError413.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError413 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -59,17 +57,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 f40215bb513..a34fa3b5b0f 100644 --- a/src/Rules/RuleErrors/RuleError415.php +++ b/src/Rules/RuleErrors/RuleError415.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -29,10 +29,8 @@ final class RuleError415 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -67,17 +65,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e9ddea4f749..90b68b0fdd8 100644 --- a/src/Rules/RuleErrors/RuleError417.php +++ b/src/Rules/RuleErrors/RuleError417.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -19,10 +19,8 @@ final class RuleError417 implements RuleError, MetadataRuleError, FixableNodeRul /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -40,17 +38,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 398afb991e0..0ecfe959443 100644 --- a/src/Rules/RuleErrors/RuleError419.php +++ b/src/Rules/RuleErrors/RuleError419.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -22,10 +22,8 @@ final class RuleError419 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -48,17 +46,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 8c06e75f948..d3b28b75fb4 100644 --- a/src/Rules/RuleErrors/RuleError421.php +++ b/src/Rules/RuleErrors/RuleError421.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -24,10 +24,8 @@ final class RuleError421 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -55,17 +53,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 97869af2410..176523a3dde 100644 --- a/src/Rules/RuleErrors/RuleError423.php +++ b/src/Rules/RuleErrors/RuleError423.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; /** @@ -27,10 +27,8 @@ final class RuleError423 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -63,17 +61,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 6543bc97e72..24cabb6a190 100644 --- a/src/Rules/RuleErrors/RuleError425.php +++ b/src/Rules/RuleErrors/RuleError425.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -22,10 +22,8 @@ final class RuleError425 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -48,17 +46,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 41ba1720843..41d442e175c 100644 --- a/src/Rules/RuleErrors/RuleError427.php +++ b/src/Rules/RuleErrors/RuleError427.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -25,10 +25,8 @@ final class RuleError427 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -56,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 4979227ea00..b9c0cfde238 100644 --- a/src/Rules/RuleErrors/RuleError429.php +++ b/src/Rules/RuleErrors/RuleError429.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError429 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -63,17 +61,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 dbd6a108055..e087e558321 100644 --- a/src/Rules/RuleErrors/RuleError431.php +++ b/src/Rules/RuleErrors/RuleError431.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -30,10 +30,8 @@ final class RuleError431 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -71,17 +69,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 da53294f0e3..6b20bd67392 100644 --- a/src/Rules/RuleErrors/RuleError433.php +++ b/src/Rules/RuleErrors/RuleError433.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\RuleError; /** @@ -22,10 +22,8 @@ final class RuleError433 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -48,17 +46,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 8af4dd90b00..043626532e5 100644 --- a/src/Rules/RuleErrors/RuleError435.php +++ b/src/Rules/RuleErrors/RuleError435.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; /** @@ -25,10 +25,8 @@ final class RuleError435 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -56,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 ac904a8f2c5..1f899bc07d4 100644 --- a/src/Rules/RuleErrors/RuleError437.php +++ b/src/Rules/RuleErrors/RuleError437.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; /** @@ -27,10 +27,8 @@ final class RuleError437 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -63,17 +61,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 3de3e430a95..8a3beef3da4 100644 --- a/src/Rules/RuleErrors/RuleError439.php +++ b/src/Rules/RuleErrors/RuleError439.php @@ -2,13 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; /** @@ -30,10 +30,8 @@ final class RuleError439 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -71,17 +69,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 117836e7f1c..7abb7b7baee 100644 --- a/src/Rules/RuleErrors/RuleError441.php +++ b/src/Rules/RuleErrors/RuleError441.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -25,10 +25,8 @@ final class RuleError441 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -56,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 3df637ed000..3d241d34a0f 100644 --- a/src/Rules/RuleErrors/RuleError443.php +++ b/src/Rules/RuleErrors/RuleError443.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -28,10 +28,8 @@ final class RuleError443 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -64,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 207824e9cbe..5606b774f32 100644 --- a/src/Rules/RuleErrors/RuleError445.php +++ b/src/Rules/RuleErrors/RuleError445.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -30,10 +30,8 @@ final class RuleError445 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -71,17 +69,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e8334196ed4..5100c91f309 100644 --- a/src/Rules/RuleErrors/RuleError447.php +++ b/src/Rules/RuleErrors/RuleError447.php @@ -2,13 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -33,10 +33,8 @@ final class RuleError447 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -79,17 +77,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 14b459f2cc2..bf1b0e8965e 100644 --- a/src/Rules/RuleErrors/RuleError449.php +++ b/src/Rules/RuleErrors/RuleError449.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -16,10 +16,8 @@ final class RuleError449 implements RuleError, NonIgnorableRuleError, FixableNod public string $message; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -29,17 +27,12 @@ public function getMessage(): string return $this->message; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 6ec124edf8e..8479ccd0c79 100644 --- a/src/Rules/RuleErrors/RuleError451.php +++ b/src/Rules/RuleErrors/RuleError451.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\LineRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -19,10 +19,8 @@ final class RuleError451 implements RuleError, LineRuleError, NonIgnorableRuleEr public int $line; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -37,17 +35,12 @@ public function getLine(): int return $this->line; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 286a12f67f1..3db549031dd 100644 --- a/src/Rules/RuleErrors/RuleError453.php +++ b/src/Rules/RuleErrors/RuleError453.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -21,10 +21,8 @@ final class RuleError453 implements RuleError, FileRuleError, NonIgnorableRuleEr public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -44,17 +42,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 ce1b5300c11..880c74ceb8a 100644 --- a/src/Rules/RuleErrors/RuleError455.php +++ b/src/Rules/RuleErrors/RuleError455.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -24,10 +24,8 @@ final class RuleError455 implements RuleError, LineRuleError, FileRuleError, Non public string $fileDescription; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -52,17 +50,12 @@ public function getFileDescription(): string return $this->fileDescription; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 12b08b04de3..1fb0f9604a6 100644 --- a/src/Rules/RuleErrors/RuleError457.php +++ b/src/Rules/RuleErrors/RuleError457.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; @@ -19,10 +19,8 @@ final class RuleError457 implements RuleError, TipRuleError, NonIgnorableRuleErr public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -37,17 +35,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 f4d4378b67d..f11e22ba81d 100644 --- a/src/Rules/RuleErrors/RuleError459.php +++ b/src/Rules/RuleErrors/RuleError459.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -22,10 +22,8 @@ final class RuleError459 implements RuleError, LineRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -45,17 +43,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 83e2833e84b..67cceada863 100644 --- a/src/Rules/RuleErrors/RuleError461.php +++ b/src/Rules/RuleErrors/RuleError461.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -24,10 +24,8 @@ final class RuleError461 implements RuleError, FileRuleError, TipRuleError, NonI public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -52,17 +50,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 c94ed698c44..d1fb6cdb033 100644 --- a/src/Rules/RuleErrors/RuleError463.php +++ b/src/Rules/RuleErrors/RuleError463.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError463 implements RuleError, LineRuleError, FileRuleError, Tip public string $tip; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -60,17 +58,12 @@ public function getTip(): string return $this->tip; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 aa850ba143a..939f1972245 100644 --- a/src/Rules/RuleErrors/RuleError465.php +++ b/src/Rules/RuleErrors/RuleError465.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\IdentifierRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -19,10 +19,8 @@ final class RuleError465 implements RuleError, IdentifierRuleError, NonIgnorable public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -37,17 +35,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 239b4bc8961..fed6fcd0dcc 100644 --- a/src/Rules/RuleErrors/RuleError467.php +++ b/src/Rules/RuleErrors/RuleError467.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -22,10 +22,8 @@ final class RuleError467 implements RuleError, LineRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -45,17 +43,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 184f6043fdf..cca3dcfa5aa 100644 --- a/src/Rules/RuleErrors/RuleError469.php +++ b/src/Rules/RuleErrors/RuleError469.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -24,10 +24,8 @@ final class RuleError469 implements RuleError, FileRuleError, IdentifierRuleErro public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -52,17 +50,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 c483a990cbf..64fdec44050 100644 --- a/src/Rules/RuleErrors/RuleError471.php +++ b/src/Rules/RuleErrors/RuleError471.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError471 implements RuleError, LineRuleError, FileRuleError, Ide public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -60,17 +58,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 091b08a0fce..901fdc0c2bc 100644 --- a/src/Rules/RuleErrors/RuleError473.php +++ b/src/Rules/RuleErrors/RuleError473.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -22,10 +22,8 @@ final class RuleError473 implements RuleError, TipRuleError, IdentifierRuleError public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -45,17 +43,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 7a7965c10e0..f976f782927 100644 --- a/src/Rules/RuleErrors/RuleError475.php +++ b/src/Rules/RuleErrors/RuleError475.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -25,10 +25,8 @@ final class RuleError475 implements RuleError, LineRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -53,17 +51,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 081110f294b..eff6088e3bf 100644 --- a/src/Rules/RuleErrors/RuleError477.php +++ b/src/Rules/RuleErrors/RuleError477.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -27,10 +27,8 @@ final class RuleError477 implements RuleError, FileRuleError, TipRuleError, Iden public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -60,17 +58,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 80254bb60b0..bbd59dd4691 100644 --- a/src/Rules/RuleErrors/RuleError479.php +++ b/src/Rules/RuleErrors/RuleError479.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -30,10 +30,8 @@ final class RuleError479 implements RuleError, LineRuleError, FileRuleError, Tip public string $identifier; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -68,17 +66,12 @@ public function getIdentifier(): string return $this->identifier; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 7e77c85a231..179cdb6987e 100644 --- a/src/Rules/RuleErrors/RuleError481.php +++ b/src/Rules/RuleErrors/RuleError481.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; use PHPStan\Rules\FileDependenciesRuleError; use PHPStan\Rules\FixableNodeRuleError; use PHPStan\Rules\MetadataRuleError; +use PHPStan\Rules\NodeFix; use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; @@ -20,10 +20,8 @@ final class RuleError481 implements RuleError, MetadataRuleError, NonIgnorableRu /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -41,17 +39,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 1f8b3eaabf7..ad42d4d805d 100644 --- a/src/Rules/RuleErrors/RuleError483.php +++ b/src/Rules/RuleErrors/RuleError483.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -23,10 +23,8 @@ final class RuleError483 implements RuleError, LineRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -49,17 +47,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 4b0bf3aca21..3586f66eb51 100644 --- a/src/Rules/RuleErrors/RuleError485.php +++ b/src/Rules/RuleErrors/RuleError485.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -25,10 +25,8 @@ final class RuleError485 implements RuleError, FileRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -56,17 +54,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 69c4b0b6eee..2ad5c0198d2 100644 --- a/src/Rules/RuleErrors/RuleError487.php +++ b/src/Rules/RuleErrors/RuleError487.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -28,10 +28,8 @@ final class RuleError487 implements RuleError, LineRuleError, FileRuleError, Met /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -64,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 f401d9805bf..b22072f4537 100644 --- a/src/Rules/RuleErrors/RuleError489.php +++ b/src/Rules/RuleErrors/RuleError489.php @@ -2,10 +2,10 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -23,10 +23,8 @@ final class RuleError489 implements RuleError, TipRuleError, MetadataRuleError, /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -49,17 +47,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 f4f4323efca..216cb8b8fe0 100644 --- a/src/Rules/RuleErrors/RuleError491.php +++ b/src/Rules/RuleErrors/RuleError491.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError491 implements RuleError, LineRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -57,17 +55,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 4773c9255be..18318b6c962 100644 --- a/src/Rules/RuleErrors/RuleError493.php +++ b/src/Rules/RuleErrors/RuleError493.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -28,10 +28,8 @@ final class RuleError493 implements RuleError, FileRuleError, TipRuleError, Meta /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -64,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 6564db8c8a1..05d106c0c3f 100644 --- a/src/Rules/RuleErrors/RuleError495.php +++ b/src/Rules/RuleErrors/RuleError495.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -31,10 +31,8 @@ final class RuleError495 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -72,17 +70,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 1df55ed5009..8dc28faec52 100644 --- a/src/Rules/RuleErrors/RuleError497.php +++ b/src/Rules/RuleErrors/RuleError497.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -23,10 +23,8 @@ final class RuleError497 implements RuleError, IdentifierRuleError, MetadataRule /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -49,17 +47,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 7b451cea678..d3c897b4b65 100644 --- a/src/Rules/RuleErrors/RuleError499.php +++ b/src/Rules/RuleErrors/RuleError499.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError499 implements RuleError, LineRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -57,17 +55,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 6b68f5fc4f2..23f471ee959 100644 --- a/src/Rules/RuleErrors/RuleError501.php +++ b/src/Rules/RuleErrors/RuleError501.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -28,10 +28,8 @@ final class RuleError501 implements RuleError, FileRuleError, IdentifierRuleErro /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -64,17 +62,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e8bfb21a2cf..b232978cb2a 100644 --- a/src/Rules/RuleErrors/RuleError503.php +++ b/src/Rules/RuleErrors/RuleError503.php @@ -2,13 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -31,10 +31,8 @@ final class RuleError503 implements RuleError, LineRuleError, FileRuleError, Ide /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -72,17 +70,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 901a70777d2..4ecd31c1a3a 100644 --- a/src/Rules/RuleErrors/RuleError505.php +++ b/src/Rules/RuleErrors/RuleError505.php @@ -2,11 +2,11 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -26,10 +26,8 @@ final class RuleError505 implements RuleError, TipRuleError, IdentifierRuleError /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -57,17 +55,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 c57afd4784a..05adef43413 100644 --- a/src/Rules/RuleErrors/RuleError507.php +++ b/src/Rules/RuleErrors/RuleError507.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -29,10 +29,8 @@ final class RuleError507 implements RuleError, LineRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -65,17 +63,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 e396b433b80..c77523f8cd9 100644 --- a/src/Rules/RuleErrors/RuleError509.php +++ b/src/Rules/RuleErrors/RuleError509.php @@ -2,12 +2,12 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -31,10 +31,8 @@ final class RuleError509 implements RuleError, FileRuleError, TipRuleError, Iden /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -72,17 +70,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 20a4a3164d2..14bd0fc5286 100644 --- a/src/Rules/RuleErrors/RuleError511.php +++ b/src/Rules/RuleErrors/RuleError511.php @@ -2,13 +2,13 @@ namespace PHPStan\Rules\RuleErrors; -use PhpParser\Node; 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; @@ -34,10 +34,8 @@ final class RuleError511 implements RuleError, LineRuleError, FileRuleError, Tip /** @var mixed[] */ public array $metadata; - public Node $originalNode; - - /** @var callable(Node): Node */ - public $newNodeCallable; + /** @var non-empty-list */ + public array $nodeFixes; /** @var list */ public array $fileDependencies; @@ -80,17 +78,12 @@ public function getMetadata(): array return $this->metadata; } - public function getOriginalNode(): Node - { - return $this->originalNode; - } - /** - * @return callable(Node): 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 99f8770e99c..f853db70f66 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -2,13 +2,16 @@ namespace PHPStan\Testing; +use Nette\Utils\FileSystem; use PhpParser\Node; use PHPStan\Analyser\Analyser; use PHPStan\Analyser\AnalyserResultFinalizer; use PHPStan\Analyser\Error; use PHPStan\Analyser\ExpressionResultFactory; 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; @@ -29,13 +32,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; /** @@ -45,6 +57,8 @@ abstract class RuleTestCase extends PHPStanTestCase { + private const FIX_ROUNDS_LIMIT = 10; + private ?Analyser $analyser = null; /** @@ -232,23 +246,90 @@ 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 { - [$errors] = $this->gatherAnalyserErrorsWithDelayedErrors([$file]); - $diffs = []; - foreach ($errors as $error) { - if ($error->getFixedErrorDiff() === null) { - continue; - } - $diffs[] = $error->getFixedErrorDiff(); - } + $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(). + * + * 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 + { + $fileHelper = $this->getFileHelper(); + $fixedFile = $fileHelper->normalizePath($fixedFile); + // a trait is analysed only when its file is analysed too + $analysedFiles = array_values(array_unique([$fileHelper->normalizePath($file), $fixedFile])); + $contentsByFile = [$fixedFile => FileReader::read($fixedFile)]; + // original path => path analysed in the current round + $roundPaths = array_combine($analysedFiles, $analysedFiles); $patcher = self::getContainer()->getByType(Patcher::class); - $newFileContents = $patcher->applyDiffs($file, $diffs); // @phpstan-ignore missingType.checkedException, missingType.checkedException + $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; + } + + $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); + } + } + } finally { + FileSystem::delete($tmpDir); + } $fixedFileContents = FileReader::read($expectedFile); - $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($newFileContents)); + $this->assertSame($this->normalizeLineEndings($fixedFileContents), $this->normalizeLineEndings($contentsByFile[$fixedFile])); } private function normalizeLineEndings(string $string): string @@ -303,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 7df8c83398d..913691b1481 100644 --- a/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php +++ b/tests/PHPStan/Analyser/CollectedDataRuleReuseTest.php @@ -11,10 +11,13 @@ 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; 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 +280,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->assertNotSame([], $errors[0]->getFixedErrorDiffs()); + + $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(); @@ -315,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)); + } + +} 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]); + } + } diff --git a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php index bf31b347be7..06ddbba2981 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('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); + $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%'); 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); + } + } + +} diff --git a/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php b/tests/PHPStan/Fixable/FixCollectedFuncCallRule.php new file mode 100644 index 00000000000..dafbbf7db2d --- /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..d6aa4784a50 --- /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('currentPhpVersionRichParser')); + } + + 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/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/FixIssetRuleTest.php b/tests/PHPStan/Fixable/FixIssetRuleTest.php index e6c360c35d2..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,4 +27,38 @@ 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'); + } + + 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/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/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/MultiFixRule.php b/tests/PHPStan/Fixable/MultiFixRule.php new file mode 100644 index 00000000000..febb3439d09 --- /dev/null +++ b/tests/PHPStan/Fixable/MultiFixRule.php @@ -0,0 +1,99 @@ + + */ +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) { + return []; + } + + $name = $node->name->toLowerString(); + $args = $node->getArgs(); + if (($name !== 'renameall' && $name !== 'renameallornothing') || !isset($args[0]) || !$args[0]->value instanceof String_) { + return []; + } + + $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 { + $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/RemoveNodeRule.php b/tests/PHPStan/Fixable/RemoveNodeRule.php new file mode 100644 index 00000000000..faf46907325 --- /dev/null +++ b/tests/PHPStan/Fixable/RemoveNodeRule.php @@ -0,0 +1,71 @@ + + */ +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\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; + } 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..47e99f51274 --- /dev/null +++ b/tests/PHPStan/Fixable/RemoveNodeRuleTest.php @@ -0,0 +1,59 @@ + + */ +class RemoveNodeRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new RemoveNodeRule(); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/remove-node.php'], [ + ['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], + ]); + } + + 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 = []; + foreach ($this->gatherAnalyserErrors([__DIR__ . '/data/remove-node.php']) as $error) { + $fixable[$error->getMessage()] = $error->getFixedErrorDiffs() !== []; + } + + $this->assertSame([ + 'Removing items.' => true, + 'Removing Stmt_Expression.' => true, + 'Removing Arg.' => true, + 'Removing Expr_FuncCall.' => false, + 'Removing Stmt_ClassMethod.' => true, + ], $fixable); + } + +} 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 @@ +