From 487f162d53fe42f6d76557ca6cd49d93ceb911e8 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 5 Feb 2024 08:59:23 +0100 Subject: [PATCH] [experimental] Add withTypeCoverageLevel() method to streamline Rector integration to new projects (#5553) * [experimental] Add withTypeCoverageLevel() method to streamline Rector integration to new projects * add withDeadCodeLevel() method --- rector.php | 2 + src/Configuration/Levels/DeadCodeLevel.php | 123 ++++++++++++++++++ .../Levels/LevelRulesResolver.php | 35 +++++ .../Levels/TypeCoverageLevel.php | 94 +++++++++++++ src/Configuration/RectorConfigBuilder.php | 37 ++++++ src/Console/Command/ListRulesCommand.php | 2 + 6 files changed, 293 insertions(+) create mode 100644 src/Configuration/Levels/DeadCodeLevel.php create mode 100644 src/Configuration/Levels/LevelRulesResolver.php create mode 100644 src/Configuration/Levels/TypeCoverageLevel.php diff --git a/rector.php b/rector.php index 500e01b389b..c3706069121 100644 --- a/rector.php +++ b/rector.php @@ -22,6 +22,8 @@ earlyReturn: true, naming: true ) + // @experimental since 0.19.7 for more smooth Rector integration to new project + ->withTypeCoverageLevel(10) ->withPhpSets() ->withRules([DeclareStrictTypesRector::class]) ->withPaths([ diff --git a/src/Configuration/Levels/DeadCodeLevel.php b/src/Configuration/Levels/DeadCodeLevel.php new file mode 100644 index 00000000000..691f6e497f9 --- /dev/null +++ b/src/Configuration/Levels/DeadCodeLevel.php @@ -0,0 +1,123 @@ +> + */ + public const RULE_LIST = [ + // easy picks + RemoveUnusedForeachKeyRector::class, + RemoveDuplicatedArrayKeyRector::class, + RecastingRemovalRector::class, + RemoveAndTrueRector::class, + SimplifyMirrorAssignRector::class, + RemoveDeadContinueRector::class, + RemoveUnusedNonEmptyArrayBeforeForeachRector::class, + RemoveNullPropertyInitializationRector::class, + RemoveUselessReturnExprInConstructRector::class, + + RemoveTypedPropertyDeadInstanceOfRector::class, + TernaryToBooleanOrFalseToBooleanAndRector::class, + RemoveDoubleAssignRector::class, + RemoveConcatAutocastRector::class, + SimplifyIfElseWithSameContentRector::class, + SimplifyUselessVariableRector::class, + RemoveDeadZeroAndOneOperationRector::class, + + // docblock + RemoveUselessParamTagRector::class, + RemoveUselessReturnTagRector::class, + RemoveNonExistingVarAnnotationRector::class, + RemoveUselessVarTagRector::class, + RemovePhpVersionIdCheckRector::class, + + RemoveAlwaysTrueIfConditionRector::class, + RemoveUnusedPrivateClassConstantRector::class, + RemoveUnusedPrivatePropertyRector::class, + + RemoveDuplicatedCaseInSwitchRector::class, + RemoveDeadInstanceOfRector::class, + + RemoveDeadTryCatchRector::class, + RemoveDeadIfForeachForRector::class, + RemoveDeadStmtRector::class, + UnwrapFutureCompatibleIfPhpVersionRector::class, + RemoveParentCallWithoutParentRector::class, + RemoveDeadConditionAboveReturnRector::class, + RemoveDeadLoopRector::class, + + // removing methods could be risky if there is some magic loading them + RemoveUnusedPromotedPropertyRector::class, + RemoveUnusedPrivateMethodParameterRector::class, + RemoveUnusedPrivateMethodRector::class, + RemoveUnreachableStatementRector::class, + RemoveUnusedVariableAssignRector::class, + + // this could break framework magic autowiring in some cases + RemoveUnusedConstructorParamRector::class, + RemoveEmptyClassMethodRector::class, + RemoveDeadReturnRector::class, + ]; +} diff --git a/src/Configuration/Levels/LevelRulesResolver.php b/src/Configuration/Levels/LevelRulesResolver.php new file mode 100644 index 00000000000..4831ed7cc1d --- /dev/null +++ b/src/Configuration/Levels/LevelRulesResolver.php @@ -0,0 +1,35 @@ +> $availableRules + * @return array> + */ + public static function resolve(int $level, array $availableRules, string $methodName): array + { + $rulesCount = count($availableRules); + + Assert::range( + $level, + 0, + $rulesCount - 1, + 'Level %s is not available "' . $methodName . '" method. Pick one between %2$s (lowest) and %3$s (highest).' + ); + + $levelRules = []; + + for ($i = 0; $i <= $level; ++$i) { + $levelRules[] = $availableRules[$i]; + } + + return $levelRules; + } +} diff --git a/src/Configuration/Levels/TypeCoverageLevel.php b/src/Configuration/Levels/TypeCoverageLevel.php new file mode 100644 index 00000000000..244bce42569 --- /dev/null +++ b/src/Configuration/Levels/TypeCoverageLevel.php @@ -0,0 +1,94 @@ + + */ + public const RULE_LIST = [ + // php 7.0 + AddVoidReturnTypeWhereNoReturnRector::class, + // php 7.4 + AddArrowFunctionReturnTypeRector::class, + ReturnTypeFromStrictNewArrayRector::class, + ReturnTypeFromStrictConstantReturnRector::class, + NumericReturnTypeFromStrictScalarReturnsRector::class, + ReturnTypeFromStrictScalarReturnExprRector::class, + ReturnTypeFromStrictBoolReturnExprRector::class, + ReturnTypeFromStrictTernaryRector::class, + EmptyOnNullableObjectToInstanceOfRector::class, + + // php 7.4 + TypedPropertyFromStrictConstructorRector::class, + ReturnTypeFromReturnDirectArrayRector::class, + AddParamTypeSplFixedArrayRector::class, + AddReturnTypeDeclarationFromYieldsRector::class, + AddParamTypeBasedOnPHPUnitDataProviderRector::class, + + // php 7.4 + TypedPropertyFromStrictSetUpRector::class, + ReturnTypeFromReturnNewRector::class, + BoolReturnTypeFromStrictScalarReturnsRector::class, + ReturnTypeFromStrictNativeCallRector::class, + ReturnTypeFromStrictTypedCallRector::class, + + // param + AddMethodCallBasedStrictParamTypeRector::class, + ParamTypeByParentCallTypeRector::class, + ReturnUnionTypeRector::class, + + // more risky rules + ReturnTypeFromStrictParamRector::class, + AddParamTypeFromPropertyTypeRector::class, + MergeDateTimePropertyTypeDeclarationRector::class, + PropertyTypeFromStrictSetterGetterRector::class, + StrictArrayParamDimFetchRector::class, + StrictStringParamConcatRector::class, + ]; +} diff --git a/src/Configuration/RectorConfigBuilder.php b/src/Configuration/RectorConfigBuilder.php index 2b51278b796..ee507f708e7 100644 --- a/src/Configuration/RectorConfigBuilder.php +++ b/src/Configuration/RectorConfigBuilder.php @@ -6,6 +6,9 @@ use Rector\Caching\Contract\ValueObject\Storage\CacheStorageInterface; use Rector\Config\RectorConfig; +use Rector\Configuration\Levels\DeadCodeLevel; +use Rector\Configuration\Levels\LevelRulesResolver; +use Rector\Configuration\Levels\TypeCoverageLevel; use Rector\Contract\Rector\ConfigurableRectorInterface; use Rector\Contract\Rector\RectorInterface; use Rector\Doctrine\Set\DoctrineSetList; @@ -582,4 +585,38 @@ public function withSymfonyContainerPhp(string $symfonyContainerPhpFile): self $this->symfonyContainerPhpFile = $symfonyContainerPhpFile; return $this; } + + /** + * @experimental since 0.19.7 Raise your dead-code coverage from the safest rules + * to more affecting ones, one level at a time + */ + public function withDeadCodeLevel(int $level): self + { + $levelRules = LevelRulesResolver::resolve( + $level, + DeadCodeLevel::RULE_LIST, + 'RectorConfig::withDeadCodeLevel()' + ); + + $this->rules = array_merge($this->rules, $levelRules); + + return $this; + } + + /** + * @experimental since 0.19.7 Raise your type coverage from the safest type rules + * to more affecting ones, one level at a time + */ + public function withTypeCoverageLevel(int $level): self + { + $levelRules = LevelRulesResolver::resolve( + $level, + TypeCoverageLevel::RULE_LIST, + 'RectorConfig::withTypeCoverageLevel()' + ); + + $this->rules = array_merge($this->rules, $levelRules); + + return $this; + } } diff --git a/src/Console/Command/ListRulesCommand.php b/src/Console/Command/ListRulesCommand.php index c5ea9cde3e6..7192c18aad5 100644 --- a/src/Console/Command/ListRulesCommand.php +++ b/src/Console/Command/ListRulesCommand.php @@ -34,6 +34,8 @@ protected function configure(): void $this->setName('list-rules'); $this->setDescription('Show loaded Rectors'); + $this->setAliases(['show-rules']); + $this->addOption( Option::OUTPUT_FORMAT, null,