diff --git a/config/set/type-declaration-docblocks.php b/config/set/type-declaration-docblocks.php index 26d2bb82f80..31c410d68c9 100644 --- a/config/set/type-declaration-docblocks.php +++ b/config/set/type-declaration-docblocks.php @@ -2,47 +2,12 @@ declare(strict_types=1); +use Rector\Config\Level\TypeDeclarationDocblocksLevel; use Rector\Config\RectorConfig; -use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnArrayDocblockBasedOnArrayMapRector; -use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnDocblockForScalarArrayFromAssignsRector; -use Rector\TypeDeclarationDocblocks\Rector\Class_\AddReturnDocblockDataProviderRector; -use Rector\TypeDeclarationDocblocks\Rector\Class_\ClassMethodArrayDocblockParamFromLocalCallsRector; -use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarArrayFromGetterReturnRector; -use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarArrayFromPropertyDefaultsRector; -use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarFromParamDocblockInConstructorRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockFromDataProviderRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockFromDimFetchAccessRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForArrayDimAssignedObjectRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForJsonArrayRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockGetterReturnArrayFromPropertyDocblockVarRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockReturnArrayFromDirectArrayInstanceRector; /** * @experimental * 2025-09, experimental hidden set for type declaration in docblocks */ return static function (RectorConfig $rectorConfig): void { - $rectorConfig->rules([ - // property var - DocblockVarFromParamDocblockInConstructorRector::class, - DocblockVarArrayFromPropertyDefaultsRector::class, - DocblockVarArrayFromGetterReturnRector::class, - - // param - AddParamArrayDocblockFromDimFetchAccessRector::class, - ClassMethodArrayDocblockParamFromLocalCallsRector::class, - - // return - DocblockGetterReturnArrayFromPropertyDocblockVarRector::class, - AddReturnDocblockForCommonObjectDenominatorRector::class, - AddReturnArrayDocblockBasedOnArrayMapRector::class, - AddReturnDocblockForScalarArrayFromAssignsRector::class, - DocblockReturnArrayFromDirectArrayInstanceRector::class, - AddReturnDocblockForArrayDimAssignedObjectRector::class, - AddReturnDocblockForJsonArrayRector::class, - - // tests - AddParamArrayDocblockFromDataProviderRector::class, - AddReturnDocblockDataProviderRector::class, - ]); + $rectorConfig->rules(TypeDeclarationDocblocksLevel::RULES); }; diff --git a/src/Config/Level/TypeDeclarationDocblocksLevel.php b/src/Config/Level/TypeDeclarationDocblocksLevel.php new file mode 100644 index 00000000000..f9cb4f550f1 --- /dev/null +++ b/src/Config/Level/TypeDeclarationDocblocksLevel.php @@ -0,0 +1,57 @@ +> + */ + public const RULES = [ + // start with rules based on native code + // property var + DocblockVarArrayFromPropertyDefaultsRector::class, + + // tests + AddParamArrayDocblockFromDataProviderRector::class, + AddReturnDocblockDataProviderRector::class, + + // param + AddParamArrayDocblockFromDimFetchAccessRector::class, + ClassMethodArrayDocblockParamFromLocalCallsRector::class, + + // return + AddReturnDocblockForCommonObjectDenominatorRector::class, + AddReturnArrayDocblockBasedOnArrayMapRector::class, + AddReturnDocblockForScalarArrayFromAssignsRector::class, + DocblockReturnArrayFromDirectArrayInstanceRector::class, + AddReturnDocblockForArrayDimAssignedObjectRector::class, + AddReturnDocblockForJsonArrayRector::class, + + // move to rules based on existing docblocks, as more risky + // property var + DocblockVarFromParamDocblockInConstructorRector::class, + DocblockVarArrayFromGetterReturnRector::class, + + // return + DocblockGetterReturnArrayFromPropertyDocblockVarRector::class, + ]; +} diff --git a/src/Configuration/RectorConfigBuilder.php b/src/Configuration/RectorConfigBuilder.php index ae16e45f9bb..13e5e3b2512 100644 --- a/src/Configuration/RectorConfigBuilder.php +++ b/src/Configuration/RectorConfigBuilder.php @@ -11,6 +11,7 @@ use Rector\Config\Level\CodeQualityLevel; use Rector\Config\Level\CodingStyleLevel; use Rector\Config\Level\DeadCodeLevel; +use Rector\Config\Level\TypeDeclarationDocblocksLevel; use Rector\Config\Level\TypeDeclarationLevel; use Rector\Config\RectorConfig; use Rector\Config\RegisteredService; @@ -141,6 +142,8 @@ final class RectorConfigBuilder */ private ?bool $isTypeCoverageLevelUsed = null; + private ?bool $isTypeCoverageDocblockLevelUsed = null; + private ?bool $isDeadCodeLevelUsed = null; private ?bool $isCodeQualityLevelUsed = null; @@ -224,6 +227,17 @@ public function __invoke(RectorConfig $rectorConfig): void )); } + if (in_array( + SetList::TYPE_DECLARATION_DOCBLOCKS, + $uniqueSets, + true + ) && $this->isTypeCoverageDocblockLevelUsed === true) { + throw new InvalidConfigurationException(sprintf( + 'Your config already enables type declarations set.%sRemove "->withTypeCoverageDocblockLevel()" as it only duplicates it, or remove type declaration set.', + PHP_EOL + )); + } + if (in_array(SetList::DEAD_CODE, $uniqueSets, true) && $this->isDeadCodeLevelUsed === true) { throw new InvalidConfigurationException(sprintf( 'Your config already enables dead code set.%sRemove "->withDeadCodeLevel()" as it only duplicates it, or remove dead code set.', @@ -742,6 +756,7 @@ public function withPreparedSets( bool $codeQuality = false, bool $codingStyle = false, bool $typeDeclarations = false, + bool $typeDeclarationDocblocks = false, bool $privatization = false, bool $naming = false, bool $instanceOf = false, @@ -761,6 +776,7 @@ public function withPreparedSets( SetList::CODE_QUALITY => $codeQuality, SetList::CODING_STYLE => $codingStyle, SetList::TYPE_DECLARATION => $typeDeclarations, + SetList::TYPE_DECLARATION_DOCBLOCKS => $typeDeclarationDocblocks, SetList::PRIVATIZATION => $privatization, SetList::NAMING => $naming, SetList::INSTANCEOF => $instanceOf, @@ -1019,6 +1035,35 @@ public function withTypeCoverageLevel(int $level): self return $this; } + /** + * Raise your type coverage docblock from the safest type rules + * to more affecting ones, one level at a time + */ + public function withTypeCoverageDocblockLevel(int $level): self + { + Assert::natural($level); + + $this->isTypeCoverageDocblockLevelUsed = true; + + $levelRules = LevelRulesResolver::resolve($level, TypeDeclarationDocblocksLevel::RULES, __METHOD__); + + // too high + $levelRulesCount = count($levelRules); + if ($levelRulesCount + self::MAX_LEVEL_GAP < $level) { + $this->levelOverflows[] = new LevelOverflow( + __METHOD__, + $level, + $levelRulesCount, + 'TypeDeclarationDocblocksLevel', + 'TYPE_DECLARATION_DOCBLOCKS' + ); + } + + $this->rules = array_merge($this->rules, $levelRules); + + return $this; + } + /** * Raise your dead-code coverage from the safest rules * to more affecting ones, one level at a time