diff --git a/composer.json b/composer.json index eff5c7e5925..2aa006c8aa0 100644 --- a/composer.json +++ b/composer.json @@ -86,7 +86,7 @@ "rules" ], "Rector\\Core\\": "src", - "Rector\\Compiler\\": "utils/compiler/src" + "Rector\\Utils\\": "utils" }, "files": [ "src/functions/node_helper.php", @@ -100,7 +100,7 @@ "rules-tests" ], "Rector\\Core\\Tests\\": "tests", - "Rector\\RuleDocGenerator\\": "utils/rule-doc-generator/src", + "Rector\\RuleDocGenerator\\": "utils/RuleDocGenerator/src", "E2e\\Parallel\\Reflection\\Resolver\\": [ "e2e/parallel-reflection-resolver/src/", "e2e/no-parallel-reflection-resolver/src" diff --git a/config/config.php b/config/config.php index 4874a8d586f..b0be23a6c09 100644 --- a/config/config.php +++ b/config/config.php @@ -36,6 +36,7 @@ use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider; use Rector\PSR4\Composer\PSR4NamespaceMatcher; use Rector\PSR4\Contract\PSR4AutoloadNamespaceMatcherInterface; +use Rector\Utils\Command\MissingInSetCommand; use Symfony\Component\Console\Application; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser; @@ -216,4 +217,6 @@ $services->set(DynamicSourceLocatorProvider::class) ->factory([service(PHPStanServicesFactory::class), 'createDynamicSourceLocatorProvider']); + + $services->set(MissingInSetCommand::class); }; diff --git a/packages/PhpAttribute/NodeAnalyzer/ExprParameterReflectionTypeCorrector.php b/packages/PhpAttribute/NodeAnalyzer/ExprParameterReflectionTypeCorrector.php index a1d58939418..b13b4d895da 100644 --- a/packages/PhpAttribute/NodeAnalyzer/ExprParameterReflectionTypeCorrector.php +++ b/packages/PhpAttribute/NodeAnalyzer/ExprParameterReflectionTypeCorrector.php @@ -47,11 +47,9 @@ public function correctItemsByAttributeClass(array|Array_ $items, string $attrib return $items; } - $constructorClassMethodReflection = $attributeClassReflection->getConstructor(); + $extendedMethodReflection = $attributeClassReflection->getConstructor(); - $parametersAcceptor = ParametersAcceptorSelector::selectSingle( - $constructorClassMethodReflection->getVariants() - ); + $parametersAcceptor = ParametersAcceptorSelector::selectSingle($extendedMethodReflection->getVariants()); foreach ($items as $name => $item) { foreach ($parametersAcceptor->getParameters() as $parameterReflection) { diff --git a/phpstan.neon b/phpstan.neon index 40dc011c6eb..964e8004af8 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -666,3 +666,5 @@ parameters: - message: '#New objects with "\$fullyQualifiedObjectType" name are overridden\. This can lead to unwanted bugs, please pick a different name to avoid it#' path: packages/NodeTypeResolver/PhpDocNodeVisitor/NameImportingPhpDocNodeVisitor.php + + - '#Class has a static method must so must contains "Static" in its name#' diff --git a/rector.php b/rector.php index 3af9ab5fc10..7665eb075be 100644 --- a/rector.php +++ b/rector.php @@ -7,11 +7,8 @@ use Rector\CodingStyle\Rector\MethodCall\PreferThisOrSelfMethodCallRector; use Rector\CodingStyle\ValueObject\ReturnArrayClassMethodToYield; use Rector\Config\RectorConfig; -use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchRector; use Rector\Nette\Set\NetteSetList; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; -use Rector\Php81\Rector\Class_\MyCLabsClassToEnumRector; -use Rector\Php81\Rector\Class_\SpatieEnumClassToEnumRector; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Privatization\Rector\Class_\FinalizeClassesWithoutChildrenRector; use Rector\Set\ValueObject\LevelSetList; @@ -43,8 +40,6 @@ new ReturnArrayClassMethodToYield('PHPUnit\Framework\TestCase', '*provide*'), ]); - // $rectorConfig->rule(RemoveJustPropertyFetchRector::class); - $rectorConfig->paths([ __DIR__ . '/bin', __DIR__ . '/src', @@ -68,29 +63,13 @@ __DIR__ . '/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php', ], - MyCLabsClassToEnumRector::class, - SpatieEnumClassToEnumRector::class, - - // test paths - '*/tests/**/Fixture/*', - '*/rules-tests/**/Fixture/*', - '*/packages-tests/**/Fixture/*', - '*/tests/**/Fixture*/*', - '*/rules-tests/**/Fixture*/*', - '*/packages-tests/**/Fixture*/*', - // source - '*/tests/**/Source/*', - '*/rules-tests/**/Source/*', - '*/packages-tests/**/Source/*', - '*/tests/**/Source*/*', - '*/rules-tests/**/Source*/*', - '*/packages-tests/**/Source*/*', - '*/tests/**/Expected/*', - '*/rules-tests/**/Expected/*', - '*/packages-tests/**/Expected/*', - '*/tests/**/Expected*/*', - '*/rules-tests/**/Expected*/*', - '*/packages-tests/**/Expected*/*', + // tests + '**/Fixture*', + '**/Fixture/*', + '**/Source*', + '**/Source/*', + '**/Expected/*', + '**/Expected*', __DIR__ . '/tests/PhpUnit/MultipleFilesChangedTrait/MultipleFilesChangedTraitTest.php', // to keep original API from PHPStan untouched diff --git a/rule-doc-generator.php b/rule-doc-generator.php index a10c31d68ea..f4828099d57 100644 --- a/rule-doc-generator.php +++ b/rule-doc-generator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use Rector\RuleDocGenerator\Category\RectorCategoryInferer; +use Rector\Utils\RuleDocGenerator\Category\RectorCategoryInferer; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $rectorConfig): void { diff --git a/scoper.php b/scoper.php index 168d5a08c4c..788dfe729c3 100644 --- a/scoper.php +++ b/scoper.php @@ -5,8 +5,8 @@ use Isolated\Symfony\Component\Finder\Finder; use Nette\Utils\DateTime; use Nette\Utils\Strings; -use Rector\Compiler\Unprefixer; use Rector\Core\Application\VersionResolver; +use Rector\Utils\Compiler\Unprefixer; require_once __DIR__ . '/vendor/autoload.php'; diff --git a/utils/Command/MissingInSetCommand.php b/utils/Command/MissingInSetCommand.php new file mode 100644 index 00000000000..34775d03152 --- /dev/null +++ b/utils/Command/MissingInSetCommand.php @@ -0,0 +1,100 @@ + + */ + private const SETS_TO_RULES_DIRECTORIES = [ + __DIR__ . '/../../config/set/code-quality.php' => __DIR__ . '/../../rules/CodeQuality/Rector', + __DIR__ . '/../../config/set/coding-style.php' => __DIR__ . '/../../rules/CodingStyle/Rector', + __DIR__ . '/../../config/set/dead-code.php' => __DIR__ . '/../../rules/DeadCode/Rector', + __DIR__ . '/../../config/set/early-return.php' => __DIR__ . '/../../rules/EarlyReturn/Rector', + ]; + + /** + * @see https://regex101.com/r/HuWjgn/1 + * @var string + */ + private const SHORT_CLASS_REGEX = '#(?\w+)::class#m'; + + public function __construct( + private readonly SymfonyStyle $symfonyStyle + ) { + parent::__construct(); + } + + protected function configure(): void + { + $this->setName('missing-in-set'); + $this->setDescription('[DEV] Show rules from specific category that are not part of the set'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + foreach (self::SETS_TO_RULES_DIRECTORIES as $setFile => $rulesDirectory) { + $shortClassesInSetFile = $this->resolveShortClassesFromSetFile($setFile); + $existingShortRectorClasses = $this->findShortRectorClasses($rulesDirectory); + + $shortRectorClassesNotInSetConfig = array_diff($existingShortRectorClasses, $shortClassesInSetFile); + + if ($shortRectorClassesNotInSetConfig === []) { + continue; + } + + $title = sprintf('In "%s" config we could not find', $setFile); + $this->symfonyStyle->title($title); + $this->symfonyStyle->listing($shortRectorClassesNotInSetConfig); + $this->symfonyStyle->newLine(2); + } + + return self::SUCCESS; + } + + /** + * @return string[] + */ + private function resolveShortClassesFromSetFile(string $setFile): array + { + $setFileContents = FileSystem::read($setFile); + $matches = Strings::matchAll($setFileContents, self::SHORT_CLASS_REGEX); + + $shortClasses = []; + foreach ($matches as $match) { + $shortClasses[] = $match['short_class_name']; + } + + return $shortClasses; + } + + /** + * @return string[] + */ + private function findShortRectorClasses(string $rulesDirectory): array + { + $robotLoader = new RobotLoader(); + $robotLoader->setTempDirectory(sys_get_temp_dir() . '/rector-missing-in-set'); + $robotLoader->addDirectory($rulesDirectory); + $robotLoader->rebuild(); + + $existingRectorClasses = array_keys($robotLoader->getIndexedClasses()); + $existingRectorShortClasses = []; + foreach ($existingRectorClasses as $existingRectorClass) { + $existingRectorShortClasses[] = (string) Strings::after($existingRectorClass, '\\', -1); + } + + return $existingRectorShortClasses; + } +} diff --git a/utils/compiler/src/Unprefixer.php b/utils/Compiler/Unprefixer.php similarity index 96% rename from utils/compiler/src/Unprefixer.php rename to utils/Compiler/Unprefixer.php index fc47166efef..827fcd25b8d 100644 --- a/utils/compiler/src/Unprefixer.php +++ b/utils/Compiler/Unprefixer.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Compiler; +namespace Rector\Utils\Compiler; use Nette\Utils\Strings; diff --git a/utils/rule-doc-generator/src/Category/RectorCategoryInferer.php b/utils/RuleDocGenerator/Category/RectorCategoryInferer.php similarity index 95% rename from utils/rule-doc-generator/src/Category/RectorCategoryInferer.php rename to utils/RuleDocGenerator/Category/RectorCategoryInferer.php index 2338877b04a..ae3634e4b0e 100644 --- a/utils/rule-doc-generator/src/Category/RectorCategoryInferer.php +++ b/utils/RuleDocGenerator/Category/RectorCategoryInferer.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\RuleDocGenerator\Category; +namespace Rector\Utils\RuleDocGenerator\Category; use Nette\Utils\Strings; use Rector\Core\Exception\ShouldNotHappenException; diff --git a/utils/compiler/config/config.php b/utils/compiler/config/config.php deleted file mode 100644 index 1fef3f6e115..00000000000 --- a/utils/compiler/config/config.php +++ /dev/null @@ -1,16 +0,0 @@ -services(); - - $services->defaults() - ->public() - ->autowire() - ->autoconfigure(); - - $services->load('Rector\Compiler\\', __DIR__ . '/../src'); -};