diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 830d8e23d3e..9ad51d433fc 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -29,6 +29,10 @@ jobs: name: 'PHPStan' run: vendor/bin/phpstan analyse --ansi + - + name: 'Avoid duplicate short class names' + run: php scripts/unique-rector-short-class-name.php + - name: 'Help and Version' run: diff --git a/config/set/php85.php b/config/set/php85.php index 3277f13944b..1117c693375 100644 --- a/config/set/php85.php +++ b/config/set/php85.php @@ -11,7 +11,7 @@ use Rector\Php85\Rector\Class_\SleepToSerializeRector; use Rector\Php85\Rector\Class_\WakeupToUnserializeRector; use Rector\Php85\Rector\ClassMethod\NullDebugInfoReturnRector; -use Rector\Php85\Rector\Const_\DeprecatedAnnotationToDeprecatedAttributeRector; +use Rector\Php85\Rector\Const_\ConstAndTraitDeprecatedAttributeRector; use Rector\Php85\Rector\FuncCall\ArrayKeyExistsNullToEmptyStringRector; use Rector\Php85\Rector\FuncCall\ChrArgModuloRector; use Rector\Php85\Rector\FuncCall\OrdSingleByteRector; @@ -35,7 +35,7 @@ ArrayFirstLastRector::class, RemoveFinfoBufferContextArgRector::class, NullDebugInfoReturnRector::class, - DeprecatedAnnotationToDeprecatedAttributeRector::class, + ConstAndTraitDeprecatedAttributeRector::class, ColonAfterSwitchCaseRector::class, ArrayKeyExistsNullToEmptyStringRector::class, ChrArgModuloRector::class, diff --git a/rules-tests/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector/DeprecatedAnnotationToDeprecatedAttributeRectorTest.php b/rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/ConstAndTraitDeprecatedAttributeRectorTest.php similarity index 74% rename from rules-tests/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector/DeprecatedAnnotationToDeprecatedAttributeRectorTest.php rename to rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/ConstAndTraitDeprecatedAttributeRectorTest.php index 122b522c627..2b8d76deaf3 100644 --- a/rules-tests/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector/DeprecatedAnnotationToDeprecatedAttributeRectorTest.php +++ b/rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/ConstAndTraitDeprecatedAttributeRectorTest.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Rector\Tests\Php85\Rector\Const_\DeprecatedAnnotationToDeprecatedAttributeRector; +namespace Rector\Tests\Php85\Rector\Const_\ConstAndTraitDeprecatedAttributeRector; use Iterator; use PHPUnit\Framework\Attributes\DataProvider; use Rector\Testing\PHPUnit\AbstractRectorTestCase; -final class DeprecatedAnnotationToDeprecatedAttributeRectorTest extends AbstractRectorTestCase +final class ConstAndTraitDeprecatedAttributeRectorTest extends AbstractRectorTestCase { #[DataProvider('provideData')] public function test(string $filePath): void diff --git a/rules-tests/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector/Fixture/basic.php.inc b/rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/Fixture/basic.php.inc similarity index 63% rename from rules-tests/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector/Fixture/basic.php.inc rename to rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/Fixture/basic.php.inc index 7556a2caed6..a8c27ca64ef 100644 --- a/rules-tests/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector/Fixture/basic.php.inc +++ b/rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/Fixture/basic.php.inc @@ -1,6 +1,6 @@ +----- + diff --git a/rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/Fixture/skip_on_class_const.php.inc b/rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/Fixture/skip_on_class_const.php.inc new file mode 100644 index 00000000000..162b9de3c62 --- /dev/null +++ b/rules-tests/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector/Fixture/skip_on_class_const.php.inc @@ -0,0 +1,16 @@ +rule(DeprecatedAnnotationToDeprecatedAttributeRector::class); + $rectorConfig->rule(ConstAndTraitDeprecatedAttributeRector::class); $rectorConfig->phpVersion(PhpVersion::PHP_85); }; diff --git a/rules/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector.php b/rules/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector.php similarity index 70% rename from rules/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector.php rename to rules/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector.php index 153aced3225..079de99d966 100644 --- a/rules/Php85/Rector/Const_/DeprecatedAnnotationToDeprecatedAttributeRector.php +++ b/rules/Php85/Rector/Const_/ConstAndTraitDeprecatedAttributeRector.php @@ -6,17 +6,21 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Const_; +use PhpParser\Node\Stmt\Trait_; use Rector\PhpAttribute\DeprecatedAnnotationToDeprecatedAttributeConverter; use Rector\Rector\AbstractRector; -use Rector\ValueObject\PhpVersionFeature; +use Rector\ValueObject\PhpVersion; use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Tests\Php85\Rector\Const_\DeprecatedAnnotationToDeprecatedAttributeRector\DeprecatedAnnotationToDeprecatedAttributeRectorTest + * @see https://wiki.php.net/rfc/attributes-on-constants + * @see https://wiki.php.net/rfc/deprecated_traits + * + * @see \Rector\Tests\Php85\Rector\Const_\ConstAndTraitDeprecatedAttributeRector\ConstAndTraitDeprecatedAttributeRectorTest */ -final class DeprecatedAnnotationToDeprecatedAttributeRector extends AbstractRector implements MinPhpVersionInterface +final class ConstAndTraitDeprecatedAttributeRector extends AbstractRector implements MinPhpVersionInterface { public function __construct( private readonly DeprecatedAnnotationToDeprecatedAttributeConverter $deprecatedAnnotationToDeprecatedAttributeConverter, @@ -25,7 +29,7 @@ public function __construct( public function getRuleDefinition(): RuleDefinition { - return new RuleDefinition('Change @deprecated annotation to Deprecated attribute', [ + return new RuleDefinition('Change @deprecated annotation to #[Deprecated] attribute for constants', [ new CodeSample( <<<'CODE_SAMPLE' /** @@ -44,11 +48,11 @@ public function getRuleDefinition(): RuleDefinition public function getNodeTypes(): array { - return [Const_::class]; + return [Const_::class, Trait_::class]; } /** - * @param Const_ $node + * @param Const_|Trait_ $node */ public function refactor(Node $node): ?Node { @@ -57,6 +61,6 @@ public function refactor(Node $node): ?Node public function provideMinPhpVersion(): int { - return PhpVersionFeature::DEPRECATED_ATTRIBUTE_ON_CONSTANT; + return PhpVersion::PHP_85; } } diff --git a/scripts/unique-rector-short-class-name.php b/scripts/unique-rector-short-class-name.php new file mode 100644 index 00000000000..ee0001601e5 --- /dev/null +++ b/scripts/unique-rector-short-class-name.php @@ -0,0 +1,69 @@ +find([ + __DIR__ . '/../rules', + __DIR__ . '/../vendor/rector/rector-doctrine', + __DIR__ . '/../vendor/rector/rector-phpunit', + __DIR__ . '/../vendor/rector/rector-symfony', + __DIR__ . '/../vendor/rector/rector-downgrade-php', +]); + +/** + * @param string[] $classNames + * @return string[] + */ +function getShortClassNames(array $classNames): array +{ + $shortClassNames = []; + foreach ($classNames as $className) { + $shortClassNames[] = substr($className, strrpos($className, '\\') + 1); + } + + return $shortClassNames; +} + +/** + * @param string[] $shortClassNames + * @return string[] + */ +function filterDuplicatedValues(array $shortClassNames): array +{ + $classNamesToCounts = array_count_values($shortClassNames); + $duplicatedShortClassNames = []; + + foreach ($classNamesToCounts as $className => $count) { + if ($count === 1) { + // unique, skip + continue; + } + + $duplicatedShortClassNames[] = $className; + } + + return $duplicatedShortClassNames; +} + +$shortClassNames = getShortClassNames($rectorClassNames); +$duplicatedShortClassNames = filterDuplicatedValues($shortClassNames); + +if ($duplicatedShortClassNames === []) { + echo "All Rector class names are unique!\n"; + exit(ExitCode::SUCCESS); +} + +echo "The following Rector class names are duplicated:\n"; +foreach ($duplicatedShortClassNames as $duplicatedShortClassName) { + echo sprintf("- %s\n", $duplicatedShortClassName); +} + +exit(ExitCode::FAILURE); diff --git a/src/PhpAttribute/DeprecatedAnnotationToDeprecatedAttributeConverter.php b/src/PhpAttribute/DeprecatedAnnotationToDeprecatedAttributeConverter.php index 3cdfb86e86e..154fce0da30 100644 --- a/src/PhpAttribute/DeprecatedAnnotationToDeprecatedAttributeConverter.php +++ b/src/PhpAttribute/DeprecatedAnnotationToDeprecatedAttributeConverter.php @@ -16,6 +16,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Const_; use PhpParser\Node\Stmt\Function_; +use PhpParser\Node\Stmt\Trait_; use PHPStan\PhpDocParser\Ast\PhpDoc\DeprecatedTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; @@ -47,7 +48,7 @@ public function __construct( ) { } - public function convert(ClassConst|Function_|ClassMethod|Const_ $node): ?Node + public function convert(ClassConst|Function_|ClassMethod|Const_|Trait_ $node): ?Node { $hasChanged = false; $phpDocInfo = $this->phpDocInfoFactory->createFromNode($node); diff --git a/src/ValueObject/PhpVersionFeature.php b/src/ValueObject/PhpVersionFeature.php index 39b1e7f647c..cbda1f5cba6 100644 --- a/src/ValueObject/PhpVersionFeature.php +++ b/src/ValueObject/PhpVersionFeature.php @@ -793,12 +793,6 @@ final class PhpVersionFeature */ public const DEPRECATED_NULL_DEBUG_INFO_RETURN = PhpVersion::PHP_85; - /** - * @see https://wiki.php.net/rfc/attributes-on-constants - * @var int - */ - public const DEPRECATED_ATTRIBUTE_ON_CONSTANT = PhpVersion::PHP_85; - /** * @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_semicolon_after_case_in_switch_statement * @var int