From e27beeb55c8b1b6dac6b9f85b547eb46c211c538 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 23 Oct 2025 14:43:30 +0200 Subject: [PATCH 1/4] move internal /bin files to /scripts, to separate from public /bin API --- .github/workflows/build_scoped_rector.yaml | 4 ++-- .github/workflows/code_analysis.yaml | 6 +++--- build/build-rector-scoped.sh | 2 +- full_build.sh | 2 +- {bin => scripts}/add-phpstan-self-replace.php | 2 +- {bin => scripts}/check-before-after-same-fixtures.php | 0 {bin => scripts}/list-unused-rules.php | 0 {bin => scripts}/no-php-file-in-fixtures.php | 0 {bin => scripts}/test-fixture-stats.php | 0 {bin => scripts}/validate-phpstan-version.php | 0 10 files changed, 8 insertions(+), 8 deletions(-) rename {bin => scripts}/add-phpstan-self-replace.php (97%) rename {bin => scripts}/check-before-after-same-fixtures.php (100%) rename {bin => scripts}/list-unused-rules.php (100%) rename {bin => scripts}/no-php-file-in-fixtures.php (100%) rename {bin => scripts}/test-fixture-stats.php (100%) rename {bin => scripts}/validate-phpstan-version.php (100%) diff --git a/.github/workflows/build_scoped_rector.yaml b/.github/workflows/build_scoped_rector.yaml index 21f334b0b94..3b8cf64c641 100644 --- a/.github/workflows/build_scoped_rector.yaml +++ b/.github/workflows/build_scoped_rector.yaml @@ -58,7 +58,7 @@ jobs: # 1. copy files to $NESTED_DIRECTORY directory Exclude the scoped/nested directories to prevent rsync from copying in a loop - run: rsync --exclude rector-build -av * rector-build --quiet - - run: rm -rf rector-build/rules-tests rector-build/templates rector-build/tests rector-build/bin/generate-changelog.php rector-build/bin/validate-phpstan-version.php rector-build/vendor/tracy/tracy/examples rector-build/vendor/symfony/console/Tester rector-build/vendor/symfony/console/Event rector-build/vendor/symfony/console/EventListener rector-build/vendor/tracy/tracy/examples rector-build/vendor/tracy/tracy/src/Bridges rector-build/vendor/tracy/tracy/src/Tracy/Bar rector-build/vendor/tracy/tracy/src/Tracy/Session rector-build/vendor/symfony/service-contracts/Test + - run: rm -rf rector-build/rules-tests rector-build/templates rector-build/tests rector-build/scripts/validate-phpstan-version.php rector-build/vendor/tracy/tracy/examples rector-build/vendor/symfony/console/Tester rector-build/vendor/symfony/console/Event rector-build/vendor/symfony/console/EventListener rector-build/vendor/tracy/tracy/examples rector-build/vendor/tracy/tracy/src/Bridges rector-build/vendor/tracy/tracy/src/Tracy/Bar rector-build/vendor/tracy/tracy/src/Tracy/Session rector-build/vendor/symfony/service-contracts/Test # 2. downgrade rector - run: php -d memory_limit=-1 bin/rector process rector-build/bin rector-build/config rector-build/src rector-build/rules rector-build/vendor --config build/config/config-downgrade.php --ansi --no-diffs @@ -95,7 +95,7 @@ jobs: - run: cp -a rector-prefixed-downgraded/. remote-repository - - run: rm -rf remote-repository/bin/add-phpstan-self-replace.php remote-repository/bin/test-fixture-stats.php remote-repository/bin/check-before-after-same-fixtures.php remote-repository/bin/no-php-file-in-fixtures.php + - run: rm -rf remote-repository/scripts/add-phpstan-self-replace.php remote-repository/scripts/test-fixture-stats.php remote-repository/scripts/check-before-after-same-fixtures.php remote-repository/scripts/no-php-file-in-fixtures.php # 7. setup git - diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 6889069be1c..70dcf2d4a58 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -46,7 +46,7 @@ jobs: - name: 'Compatible PHPStan versions' - run: php bin/validate-phpstan-version.php + run: php scripts/validate-phpstan-version.php - name: 'Finalize classes' @@ -54,11 +54,11 @@ jobs: - name: 'Check before/after test fixture on no-changes' - run: php bin/check-before-after-same-fixtures.php + run: php scripts/check-before-after-same-fixtures.php - name: 'Check no "*.php" files in rules Fixture directory' - run: php bin/no-php-file-in-fixtures.php + run: php scripts/no-php-file-in-fixtures.php - name: 'Detect composer dependency issues' diff --git a/build/build-rector-scoped.sh b/build/build-rector-scoped.sh index 86c11ae01b8..198919e9f8b 100644 --- a/build/build-rector-scoped.sh +++ b/build/build-rector-scoped.sh @@ -30,7 +30,7 @@ note "Starts" note "Downloading php-scoper.phar" wget https://github.com/humbug/php-scoper/releases/download/0.18.17/php-scoper.phar -N --no-verbose -php "$BUILD_DIRECTORY/bin/add-phpstan-self-replace.php" +php "$BUILD_DIRECTORY/scripts/add-phpstan-self-replace.php" note "Remove PHPStan to avoid duplicating it" diff --git a/full_build.sh b/full_build.sh index d39b31b4e18..21697762173 100644 --- a/full_build.sh +++ b/full_build.sh @@ -31,7 +31,7 @@ bin/rector process src/functions/node_helper.php -c build/config/config-downgrad rsync --exclude rector-build -av * rector-build --quiet -rm -rf rector-build/rules-tests rector-build/templates rector-build/tests rector-build/bin/validate-phpstan-version.php rector-build/vendor/tracy/tracy/examples rector-build/vendor/symfony/console/Tester rector-build/vendor/symfony/console/Event rector-build/vendor/symfony/console/EventListener rector-build/vendor/tracy/tracy/examples rector-build/vendor/tracy/tracy/src/Bridges rector-build/vendor/tracy/tracy/src/Tracy/Bar rector-build/vendor/tracy/tracy/src/Tracy/Session rector-build/vendor/symfony/service-contracts/Test +rm -rf rector-build/rules-tests rector-build/templates rector-build/tests rector-build/scripts/validate-phpstan-version.php rector-build/vendor/tracy/tracy/examples rector-build/vendor/symfony/console/Tester rector-build/vendor/symfony/console/Event rector-build/vendor/symfony/console/EventListener rector-build/vendor/tracy/tracy/examples rector-build/vendor/tracy/tracy/src/Bridges rector-build/vendor/tracy/tracy/src/Tracy/Bar rector-build/vendor/tracy/tracy/src/Tracy/Session rector-build/vendor/symfony/service-contracts/Test php -d memory_limit=-1 bin/rector process rector-build/bin rector-build/config rector-build/src rector-build/rules rector-build/vendor --config build/config/config-downgrade.php --ansi --no-diffs diff --git a/bin/add-phpstan-self-replace.php b/scripts/add-phpstan-self-replace.php similarity index 97% rename from bin/add-phpstan-self-replace.php rename to scripts/add-phpstan-self-replace.php index b6770821156..4390609dbc9 100644 --- a/bin/add-phpstan-self-replace.php +++ b/scripts/add-phpstan-self-replace.php @@ -12,7 +12,7 @@ $composerJsonFileContents = FileSystem::read(__DIR__ . '/../composer.json'); -$installedPackageResolver = new InstalledPackageResolver(__DIR__ . '/..'); +$installedPackageResolver = new InstalledPackageResolver(__DIR__ . '/rector-src'); $phpstanVersion = $installedPackageResolver->resolvePackageVersion('phpstan/phpstan'); $composerJson = Json::decode($composerJsonFileContents, forceArrays: true); diff --git a/bin/check-before-after-same-fixtures.php b/scripts/check-before-after-same-fixtures.php similarity index 100% rename from bin/check-before-after-same-fixtures.php rename to scripts/check-before-after-same-fixtures.php diff --git a/bin/list-unused-rules.php b/scripts/list-unused-rules.php similarity index 100% rename from bin/list-unused-rules.php rename to scripts/list-unused-rules.php diff --git a/bin/no-php-file-in-fixtures.php b/scripts/no-php-file-in-fixtures.php similarity index 100% rename from bin/no-php-file-in-fixtures.php rename to scripts/no-php-file-in-fixtures.php diff --git a/bin/test-fixture-stats.php b/scripts/test-fixture-stats.php similarity index 100% rename from bin/test-fixture-stats.php rename to scripts/test-fixture-stats.php diff --git a/bin/validate-phpstan-version.php b/scripts/validate-phpstan-version.php similarity index 100% rename from bin/validate-phpstan-version.php rename to scripts/validate-phpstan-version.php From a14d118c28cc7c6f89cacee19d97573983706406 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 23 Oct 2025 14:49:15 +0200 Subject: [PATCH 2/4] decouple script helpers --- composer.json | 3 +- ecs.php | 1 + phpstan.neon | 1 + .../avoid-short-node-names-in-fixtures.php | 14 +++++ scripts/check-before-after-same-fixtures.php | 21 +------- scripts/list-unused-rules.php | 51 ++----------------- scripts/src/Finder/FixtureFinder.php | 29 +++++++++++ scripts/src/Finder/RectorClassFinder.php | 26 ++++++++++ scripts/src/Finder/RectorSetFilesFinder.php | 37 ++++++++++++++ 9 files changed, 114 insertions(+), 69 deletions(-) create mode 100644 scripts/avoid-short-node-names-in-fixtures.php create mode 100644 scripts/src/Finder/FixtureFinder.php create mode 100644 scripts/src/Finder/RectorClassFinder.php create mode 100644 scripts/src/Finder/RectorSetFilesFinder.php diff --git a/composer.json b/composer.json index 6c7df99f587..98a18e95af9 100644 --- a/composer.json +++ b/composer.json @@ -86,7 +86,8 @@ "E2e\\Parallel\\Reflection\\Resolver\\": [ "e2e/parallel-reflection-resolver/src/", "e2e/no-parallel-reflection-resolver/src" - ] + ], + "Rector\\Scripts\\": "scripts/src" }, "classmap": [ "stubs", diff --git a/ecs.php b/ecs.php index 8861451b1b2..afaf70fdb2e 100644 --- a/ecs.php +++ b/ecs.php @@ -17,6 +17,7 @@ __DIR__ . '/tests', __DIR__ . '/utils', __DIR__ . '/config', + __DIR__ . '/scripts', __DIR__ . '/build/build-preload.php', ]) ->withSkip([ diff --git a/phpstan.neon b/phpstan.neon index dee738738c1..87f6920e76b 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -26,6 +26,7 @@ parameters: - tests - rules-tests - utils + - scripts - e2e/e2eTestRunnerWithCache.php - e2e/e2eTestRunner.php diff --git a/scripts/avoid-short-node-names-in-fixtures.php b/scripts/avoid-short-node-names-in-fixtures.php new file mode 100644 index 00000000000..b70fe8ea1b3 --- /dev/null +++ b/scripts/avoid-short-node-names-in-fixtures.php @@ -0,0 +1,14 @@ +getContents(), '/\b(?:class|interface)\s+([A-Z][A-Za-z0-9_]*)/'); + dump($shortClassNameMatch); +} diff --git a/scripts/check-before-after-same-fixtures.php b/scripts/check-before-after-same-fixtures.php index 7eb7bb257d9..63ed8c02def 100644 --- a/scripts/check-before-after-same-fixtures.php +++ b/scripts/check-before-after-same-fixtures.php @@ -10,9 +10,7 @@ use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; -use Webmozart\Assert\Assert; final readonly class SameBeforeAfterFixtureDetector { @@ -29,7 +27,7 @@ public function __construct() */ public function run(array $testDirectories): int { - $fixtureFiles = $this->findFixtureFiles($testDirectories); + $fixtureFiles = \Rector\Scripts\Finder\FixtureFinder::find($testDirectories); $invalidFixturePaths = []; foreach ($fixtureFiles as $fixtureFile) { @@ -53,23 +51,6 @@ public function run(array $testDirectories): int return Command::FAILURE; } - /** - * @param string[] $directories - * @return SplFileInfo[] - */ - private function findFixtureFiles(array $directories): array - { - Assert::allDirectory($directories); - - $finder = (new Finder()) - ->files() - ->in($directories) - ->name('*.php.inc') - ->sortByName(); - - return iterator_to_array($finder->getIterator()); - } - private function hasFileSameBeforeAndAfterPart(SplFileInfo $fixtureFile): bool { $parts = Strings::split($fixtureFile->getContents(), '#^\s*-----\s*$#m'); diff --git a/scripts/list-unused-rules.php b/scripts/list-unused-rules.php index d9c908bb8d8..b99c3c0afe0 100644 --- a/scripts/list-unused-rules.php +++ b/scripts/list-unused-rules.php @@ -4,6 +4,8 @@ use Nette\Loaders\RobotLoader; use Rector\Bridge\SetRectorsResolver; +use Rector\Scripts\Finder\RectorClassFinder; +use Rector\Scripts\Finder\RectorSetFilesFinder; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Style\SymfonyStyle; @@ -27,7 +29,7 @@ $symfonyStyle = new SymfonyStyle(new ArrayInput([]), new ConsoleOutput()); $symfonyStyle->writeln(sprintf('Found Rector %d rules', count($rectorClasses))); -$rectorSeFinder = new RectorSetFinder(); +$rectorSeFinder = new RectorSetFilesFinder(); $rectorSetFiles = $rectorSeFinder->find([ __DIR__ . '/../config/set', @@ -53,53 +55,6 @@ $symfonyStyle->newLine(); $symfonyStyle->listing($unusedRectorRules); -final class RectorClassFinder -{ - /** - * @param string[] $dirs - * @return string[] - */ - public function find(array $dirs): array - { - $robotLoader = new RobotLoader(); - $robotLoader->acceptFiles = ['*Rector.php']; - $robotLoader->addDirectory(...$dirs); - - $robotLoader->setTempDirectory(sys_get_temp_dir() . '/rector-rules'); - $robotLoader->refresh(); - - return array_keys($robotLoader->getIndexedClasses()); - } -} - -final class RectorSetFinder -{ - /** - * @param string[] $configDirs - * @return string[] - */ - public function find(array $configDirs): array - { - Assert::allString($configDirs); - Assert::allDirectory($configDirs); - - // find set files - $finder = (new Finder())->in($configDirs) - ->files() - ->name('*.php'); - - /** @var SplFileInfo[] $setFileInfos */ - $setFileInfos = iterator_to_array($finder->getIterator()); - - $setFiles = []; - foreach ($setFileInfos as $setFileInfo) { - $setFiles[] = $setFileInfo->getRealPath(); - } - - return $setFiles; - } -} - final class UsedRectorClassResolver { /** diff --git a/scripts/src/Finder/FixtureFinder.php b/scripts/src/Finder/FixtureFinder.php new file mode 100644 index 00000000000..e21a611408e --- /dev/null +++ b/scripts/src/Finder/FixtureFinder.php @@ -0,0 +1,29 @@ +files() + ->in($directories) + ->name('*.php.inc') + ->sortByName(); + + return iterator_to_array($finder->getIterator()); + } +} diff --git a/scripts/src/Finder/RectorClassFinder.php b/scripts/src/Finder/RectorClassFinder.php new file mode 100644 index 00000000000..6fdf1c3f9a0 --- /dev/null +++ b/scripts/src/Finder/RectorClassFinder.php @@ -0,0 +1,26 @@ +acceptFiles = ['*Rector.php']; + $robotLoader->addDirectory(...$dirs); + + $robotLoader->setTempDirectory(sys_get_temp_dir() . '/rector-rules'); + $robotLoader->refresh(); + + return array_keys($robotLoader->getIndexedClasses()); + } +} diff --git a/scripts/src/Finder/RectorSetFilesFinder.php b/scripts/src/Finder/RectorSetFilesFinder.php new file mode 100644 index 00000000000..de972608545 --- /dev/null +++ b/scripts/src/Finder/RectorSetFilesFinder.php @@ -0,0 +1,37 @@ +in($configDirs) + ->files() + ->name('*.php'); + + /** @var SplFileInfo[] $setFileInfos */ + $setFileInfos = iterator_to_array($finder->getIterator()); + + $setFiles = []; + foreach ($setFileInfos as $setFileInfo) { + $setFiles[] = $setFileInfo->getRealPath(); + } + + return $setFiles; + } +} From 111f057e5f8c40c20afcd143a43a6d21c9d878d9 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 23 Oct 2025 15:18:11 +0200 Subject: [PATCH 3/4] [ci] add short class fixture names check to avoid node class names --- .github/workflows/code_analysis.yaml | 4 ++ composer-dependency-analyser.php | 3 - ...nc => flip_instance_nullable_type.php.inc} | 4 +- ...do_.php.inc => continue_inside_do.php.inc} | 4 +- ...hp.inc => continue_inside_foreach.php.inc} | 4 +- .../{while_.php.inc => inside_while.php.inc} | 4 +- .../Fixture/{do_.php.inc => empty_do.php.inc} | 4 +- ...foreach_.php.inc => empty_foreach.php.inc} | 4 +- .../{while_.php.inc => empty_while.php.inc} | 4 +- ...cal.php.inc => split_or_identical.php.inc} | 4 +- .../Fixture/exit.php.inc | 36 ------------ .../{elseif.php.inc => if_return.php.inc} | 4 +- ...hrow.php.inc => split_after_throw.php.inc} | 4 +- .../aliased_with_multi_properties.php.inc | 51 ---------------- .../Fixture/nullable_type.php.inc | 4 +- .../avoid-short-node-names-in-fixtures.php | 58 ++++++++++++++++++- scripts/list-unused-rules.php | 4 -- 17 files changed, 81 insertions(+), 119 deletions(-) rename rules-tests/CodeQuality/Rector/Identical/FlipTypeControlToUseExclusiveTypeRector/Fixture/{nullable_type.php.inc => flip_instance_nullable_type.php.inc} (92%) rename rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/{do_.php.inc => continue_inside_do.php.inc} (87%) rename rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/{foreach_.php.inc => continue_inside_foreach.php.inc} (87%) rename rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/{while_.php.inc => inside_while.php.inc} (89%) rename rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/{do_.php.inc => empty_do.php.inc} (88%) rename rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/{foreach_.php.inc => empty_foreach.php.inc} (86%) rename rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/{while_.php.inc => empty_while.php.inc} (86%) rename rules-tests/EarlyReturn/Rector/If_/ChangeOrIfContinueToMultiContinueRector/Fixture/{identical.php.inc => split_or_identical.php.inc} (93%) delete mode 100644 rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/exit.php.inc rename rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/{elseif.php.inc => if_return.php.inc} (94%) rename rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/{throw.php.inc => split_after_throw.php.inc} (90%) delete mode 100644 rules-tests/Php80/Rector/Class_/AnnotationToAttributeRector/Fixture/aliased_with_multi_properties.php.inc diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 70dcf2d4a58..a21dc7aa5a8 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -56,6 +56,10 @@ jobs: name: 'Check before/after test fixture on no-changes' run: php scripts/check-before-after-same-fixtures.php + - + name: 'Check fixture classes are different to nodes' + run: php scripts/avoid-short-node-names-in-fixtures.php + - name: 'Check no "*.php" files in rules Fixture directory' run: php scripts/no-php-file-in-fixtures.php diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php index 3221035e148..ab40195069f 100644 --- a/composer-dependency-analyser.php +++ b/composer-dependency-analyser.php @@ -17,9 +17,6 @@ // ensure use version ^3.2.0 ->ignoreErrorsOnPackage('composer/pcre', [ErrorType::UNUSED_DEPENDENCY]) - // use din /bin, but only local script - ->ignoreErrorsOnPackage('nette/robot-loader', [ErrorType::DEV_DEPENDENCY_IN_PROD]) - ->ignoreErrorsOnPaths([ __DIR__ . '/stubs', __DIR__ . '/tests', diff --git a/rules-tests/CodeQuality/Rector/Identical/FlipTypeControlToUseExclusiveTypeRector/Fixture/nullable_type.php.inc b/rules-tests/CodeQuality/Rector/Identical/FlipTypeControlToUseExclusiveTypeRector/Fixture/flip_instance_nullable_type.php.inc similarity index 92% rename from rules-tests/CodeQuality/Rector/Identical/FlipTypeControlToUseExclusiveTypeRector/Fixture/nullable_type.php.inc rename to rules-tests/CodeQuality/Rector/Identical/FlipTypeControlToUseExclusiveTypeRector/Fixture/flip_instance_nullable_type.php.inc index b76d13eb434..6aabdcdea9f 100644 --- a/rules-tests/CodeQuality/Rector/Identical/FlipTypeControlToUseExclusiveTypeRector/Fixture/nullable_type.php.inc +++ b/rules-tests/CodeQuality/Rector/Identical/FlipTypeControlToUseExclusiveTypeRector/Fixture/flip_instance_nullable_type.php.inc @@ -4,7 +4,7 @@ namespace Rector\Tests\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiv use stdClass; -class NullableType +final class FlipInstanceNullableType { public function run() { @@ -32,7 +32,7 @@ namespace Rector\Tests\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiv use stdClass; -class NullableType +final class FlipInstanceNullableType { public function run() { diff --git a/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/do_.php.inc b/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/continue_inside_do.php.inc similarity index 87% rename from rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/do_.php.inc rename to rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/continue_inside_do.php.inc index 16dc3602ebc..a0bf3cc8bc9 100644 --- a/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/do_.php.inc +++ b/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/continue_inside_do.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadContinueRector\Fixture; -class Do_ +final class ContinueInsideDo { public function run() { @@ -19,7 +19,7 @@ class Do_ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadContinueRector\Fixture; -class Do_ +final class ContinueInsideDo { public function run() { diff --git a/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/foreach_.php.inc b/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/continue_inside_foreach.php.inc similarity index 87% rename from rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/foreach_.php.inc rename to rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/continue_inside_foreach.php.inc index ff0a556cab6..df4791318d3 100644 --- a/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/foreach_.php.inc +++ b/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/continue_inside_foreach.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadContinueRector\Fixture; -class Foreach_ +final class ContinueInsideForeach { public function run($values) { @@ -19,7 +19,7 @@ class Foreach_ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadContinueRector\Fixture; -class Foreach_ +final class ContinueInsideForeach { public function run($values) { diff --git a/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/while_.php.inc b/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/inside_while.php.inc similarity index 89% rename from rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/while_.php.inc rename to rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/inside_while.php.inc index bf4a41324c5..255e34c7f0a 100644 --- a/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/while_.php.inc +++ b/rules-tests/DeadCode/Rector/For_/RemoveDeadContinueRector/Fixture/inside_while.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadContinueRector\Fixture; -class While_ +final class InsideWhile { public function run() { @@ -19,7 +19,7 @@ class While_ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadContinueRector\Fixture; -class While_ +final class InsideWhile { public function run() { diff --git a/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/do_.php.inc b/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_do.php.inc similarity index 88% rename from rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/do_.php.inc rename to rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_do.php.inc index e5a48e2ad47..83b9234e8b7 100644 --- a/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/do_.php.inc +++ b/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_do.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadLoopRector\Fixture; -class Do_ +final class EmptyDo { public function run() { @@ -18,7 +18,7 @@ class Do_ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadLoopRector\Fixture; -class Do_ +final class EmptyDo { public function run() { diff --git a/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/foreach_.php.inc b/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_foreach.php.inc similarity index 86% rename from rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/foreach_.php.inc rename to rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_foreach.php.inc index 31c1bed9c0e..7074f6c608c 100644 --- a/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/foreach_.php.inc +++ b/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_foreach.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadLoopRector\Fixture; -class Foreach_ +final class EmptyForeach { public function run($values) { @@ -17,7 +17,7 @@ class Foreach_ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadLoopRector\Fixture; -class Foreach_ +final class EmptyForeach { public function run($values) { diff --git a/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/while_.php.inc b/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_while.php.inc similarity index 86% rename from rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/while_.php.inc rename to rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_while.php.inc index e5eef8c6e2a..4874ca4b38d 100644 --- a/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/while_.php.inc +++ b/rules-tests/DeadCode/Rector/For_/RemoveDeadLoopRector/Fixture/empty_while.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadLoopRector\Fixture; -class While_ +final class EmptyWhile { public function run() { @@ -17,7 +17,7 @@ class While_ namespace Rector\Tests\DeadCode\Rector\For_\RemoveDeadLoopRector\Fixture; -class While_ +final class EmptyWhile { public function run() { diff --git a/rules-tests/EarlyReturn/Rector/If_/ChangeOrIfContinueToMultiContinueRector/Fixture/identical.php.inc b/rules-tests/EarlyReturn/Rector/If_/ChangeOrIfContinueToMultiContinueRector/Fixture/split_or_identical.php.inc similarity index 93% rename from rules-tests/EarlyReturn/Rector/If_/ChangeOrIfContinueToMultiContinueRector/Fixture/identical.php.inc rename to rules-tests/EarlyReturn/Rector/If_/ChangeOrIfContinueToMultiContinueRector/Fixture/split_or_identical.php.inc index fe66eca91d4..30f4e9d0a47 100644 --- a/rules-tests/EarlyReturn/Rector/If_/ChangeOrIfContinueToMultiContinueRector/Fixture/identical.php.inc +++ b/rules-tests/EarlyReturn/Rector/If_/ChangeOrIfContinueToMultiContinueRector/Fixture/split_or_identical.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector\Fixture; -class Identical +final class SplitOrIdentical { public function canDrive(Car $newCar) { @@ -22,7 +22,7 @@ class Identical namespace Rector\Tests\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector\Fixture; -class Identical +final class SplitOrIdentical { public function canDrive(Car $newCar) { diff --git a/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/exit.php.inc b/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/exit.php.inc deleted file mode 100644 index 5f06372e965..00000000000 --- a/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/exit.php.inc +++ /dev/null @@ -1,36 +0,0 @@ - ------ - diff --git a/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/elseif.php.inc b/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/if_return.php.inc similarity index 94% rename from rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/elseif.php.inc rename to rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/if_return.php.inc index c6a15298a74..80b8941cf13 100644 --- a/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/elseif.php.inc +++ b/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/if_return.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\EarlyReturn\Rector\If_\RemoveAlwaysElseRector\Fixture; -class ElseIf_ +final class IfReturn { public function run() { @@ -24,7 +24,7 @@ class ElseIf_ namespace Rector\Tests\EarlyReturn\Rector\If_\RemoveAlwaysElseRector\Fixture; -class ElseIf_ +final class IfReturn { public function run() { diff --git a/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/throw.php.inc b/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/split_after_throw.php.inc similarity index 90% rename from rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/throw.php.inc rename to rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/split_after_throw.php.inc index a2d1a102023..474a636fb57 100644 --- a/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/throw.php.inc +++ b/rules-tests/EarlyReturn/Rector/If_/RemoveAlwaysElseRector/Fixture/split_after_throw.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\EarlyReturn\Rector\If_\RemoveAlwaysElseRector\Fixture; -class Throw_ +final class SplitAfterThrow { public function run() { @@ -21,7 +21,7 @@ class Throw_ namespace Rector\Tests\EarlyReturn\Rector\If_\RemoveAlwaysElseRector\Fixture; -class Throw_ +final class SplitAfterThrow { public function run() { diff --git a/rules-tests/Php80/Rector/Class_/AnnotationToAttributeRector/Fixture/aliased_with_multi_properties.php.inc b/rules-tests/Php80/Rector/Class_/AnnotationToAttributeRector/Fixture/aliased_with_multi_properties.php.inc deleted file mode 100644 index 1f31852345d..00000000000 --- a/rules-tests/Php80/Rector/Class_/AnnotationToAttributeRector/Fixture/aliased_with_multi_properties.php.inc +++ /dev/null @@ -1,51 +0,0 @@ - ------ - \ No newline at end of file diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/nullable_type.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/nullable_type.php.inc index b69fb8aeb42..85beeb7a898 100644 --- a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/nullable_type.php.inc +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/nullable_type.php.inc @@ -4,7 +4,7 @@ namespace Rector\Tests\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromo use DateTimeInterface; -class NullableType +final class MergeWithNullableType { private ?DateTimeInterface $time; @@ -22,7 +22,7 @@ namespace Rector\Tests\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromo use DateTimeInterface; -class NullableType +final class MergeWithNullableType { public function __construct(private ?DateTimeInterface $time = null) { diff --git a/scripts/avoid-short-node-names-in-fixtures.php b/scripts/avoid-short-node-names-in-fixtures.php index b70fe8ea1b3..78dbc511b63 100644 --- a/scripts/avoid-short-node-names-in-fixtures.php +++ b/scripts/avoid-short-node-names-in-fixtures.php @@ -4,11 +4,63 @@ declare(strict_types=1); +use Nette\Utils\Strings; +use Rector\Scripts\Finder\FixtureFinder; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Console\Style\SymfonyStyle; + require __DIR__ . '/../vendor/autoload.php'; -$fixtureFiles = \Rector\Scripts\Finder\FixtureFinder::find([__DIR__ . '/../tests', __DIR__ . '/../rules-tests']); +$fixtureFiles = FixtureFinder::find([__DIR__ . '/../tests', __DIR__ . '/../rules-tests']); + +// get short node names + +$nodeFileFinder = \Symfony\Component\Finder\Finder::create() + ->files() + ->name('*.php') + ->in(__DIR__ . '/../vendor/nikic/php-parser/lib/PhpParser/Node'); + +/** @var \Symfony\Component\Finder\SplFileInfo[] $nodeFileInfos */ +$nodeFileInfos = iterator_to_array($nodeFileFinder->getIterator()); + +$shortNodeClassNames = []; +foreach ($nodeFileInfos as $nodeFileInfo) { + $shortNodeClassNames[] = $nodeFileInfo->getBasename('.php'); +} + +$symfonyStyle = new SymfonyStyle(new ArrayInput([]), new ConsoleOutput()); + +$hasErrors = false; foreach ($fixtureFiles as $fixtureFileInfo) { - $shortClassNameMatch = \Nette\Utils\Strings::match($fixtureFileInfo->getContents(), '/\b(?:class|interface)\s+([A-Z][A-Za-z0-9_]*)/'); - dump($shortClassNameMatch); + $shortClassNameMatch = Strings::match( + $fixtureFileInfo->getContents(), + '/\b(?:class|interface)\s+(?[A-Z][A-Za-z0-9_]*)/' + ); + if ($shortClassNameMatch === null) { + continue; + } + + $fixtureClassName = $shortClassNameMatch['name']; + if (! in_array($fixtureClassName, $shortNodeClassNames, true)) { + continue; + } + + $symfonyStyle->writeln(sprintf( + 'Fixture class name "%s" conflicts with native short node name.%sChange it to different to avoid IDE incorrect autocomplete:%s%s%s', + $fixtureClassName, + PHP_EOL, + PHP_EOL, + $fixtureFileInfo->getRealPath(), + PHP_EOL + )); + + $hasErrors = true; } + +if ($hasErrors) { + exit(1); +} + +exit(0); diff --git a/scripts/list-unused-rules.php b/scripts/list-unused-rules.php index b99c3c0afe0..2bd803cfffd 100644 --- a/scripts/list-unused-rules.php +++ b/scripts/list-unused-rules.php @@ -2,16 +2,12 @@ declare(strict_types=1); -use Nette\Loaders\RobotLoader; use Rector\Bridge\SetRectorsResolver; use Rector\Scripts\Finder\RectorClassFinder; use Rector\Scripts\Finder\RectorSetFilesFinder; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\Finder\Finder; -use Symfony\Component\Finder\SplFileInfo; -use Webmozart\Assert\Assert; require __DIR__ . '/../vendor/autoload.php'; From 9ad84582e11b6fb2a6104283095966344ab787c1 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 23 Oct 2025 15:38:09 +0200 Subject: [PATCH 4/4] improve rector class finder return only non abstract non deprecated --- scripts/src/Finder/RectorClassFinder.php | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/scripts/src/Finder/RectorClassFinder.php b/scripts/src/Finder/RectorClassFinder.php index 6fdf1c3f9a0..e265784fecd 100644 --- a/scripts/src/Finder/RectorClassFinder.php +++ b/scripts/src/Finder/RectorClassFinder.php @@ -5,12 +5,13 @@ namespace Rector\Scripts\Finder; use Nette\Loaders\RobotLoader; +use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; final class RectorClassFinder { /** * @param string[] $dirs - * @return string[] + * @return class-string[] */ public function find(array $dirs): array { @@ -21,6 +22,25 @@ public function find(array $dirs): array $robotLoader->setTempDirectory(sys_get_temp_dir() . '/rector-rules'); $robotLoader->refresh(); - return array_keys($robotLoader->getIndexedClasses()); + /** @var array $rectorClasses */ + $rectorClasses = array_keys($robotLoader->getIndexedClasses()); + + $usableRectorClasses = []; + + // remove deprecated and abstract classes + foreach ($rectorClasses as $rectorClass) { + $rectorClassReflection = new \ReflectionClass($rectorClass); + if ($rectorClassReflection->isAbstract()) { + continue; + } + + if ($rectorClassReflection->implementsInterface(DeprecatedInterface::class)) { + continue; + } + + $usableRectorClasses[] = $rectorClass; + } + + return $usableRectorClasses; } }