diff --git a/config/set/downgrade-php84.php b/config/set/downgrade-php84.php index 2a920783..af56a7d2 100644 --- a/config/set/downgrade-php84.php +++ b/config/set/downgrade-php84.php @@ -6,6 +6,7 @@ use Rector\DowngradePhp84\Rector\Expression\DowngradeArrayAllRector; use Rector\DowngradePhp84\Rector\Expression\DowngradeArrayAnyRector; use Rector\DowngradePhp84\Rector\Expression\DowngradeArrayFindKeyRector; +use Rector\DowngradePhp84\Rector\ClassMethod\DowngradeDeprecatedAttributeRector; use Rector\DowngradePhp84\Rector\Expression\DowngradeArrayFindRector; use Rector\DowngradePhp84\Rector\FuncCall\DowngradeExitNamedArgumentRector; use Rector\DowngradePhp84\Rector\FuncCall\DowngradeRoundingModeEnumRector; @@ -22,5 +23,6 @@ DowngradeArrayAnyRector::class, DowngradeArrayFindRector::class, DowngradeArrayFindKeyRector::class, + DowngradeDeprecatedAttributeRector::class, ]); }; diff --git a/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/DowngradeDeprecatedAttributeRectorTest.php b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/DowngradeDeprecatedAttributeRectorTest.php new file mode 100644 index 00000000..33dd9e41 --- /dev/null +++ b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/DowngradeDeprecatedAttributeRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/class_const.php.inc b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/class_const.php.inc new file mode 100644 index 00000000..0d85a388 --- /dev/null +++ b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/class_const.php.inc @@ -0,0 +1,25 @@ + +----- + diff --git a/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/heredoc_message.php.inc b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/heredoc_message.php.inc new file mode 100644 index 00000000..31a00069 --- /dev/null +++ b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/heredoc_message.php.inc @@ -0,0 +1,32 @@ + +----- + diff --git a/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/method_message_and_since.php.inc b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/method_message_and_since.php.inc new file mode 100644 index 00000000..573df8ea --- /dev/null +++ b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/method_message_and_since.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/no_args.php.inc b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/no_args.php.inc new file mode 100644 index 00000000..9207fb66 --- /dev/null +++ b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/no_args.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/skip_other_attribute.php.inc b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/skip_other_attribute.php.inc new file mode 100644 index 00000000..3f9d2743 --- /dev/null +++ b/rules-tests/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector/Fixture/skip_other_attribute.php.inc @@ -0,0 +1,11 @@ +rule(DowngradeDeprecatedAttributeRector::class); +}; diff --git a/rules/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector.php b/rules/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector.php new file mode 100644 index 00000000..be3ab9c4 --- /dev/null +++ b/rules/DowngradePhp84/Rector/ClassMethod/DowngradeDeprecatedAttributeRector.php @@ -0,0 +1,145 @@ +> + */ + public function getNodeTypes(): array + { + return [ClassMethod::class, Function_::class, ClassConst::class, EnumCase::class]; + } + + /** + * @param ClassMethod|Function_|ClassConst|EnumCase $node + */ + public function refactor(Node $node): ?Node + { + if ($node->attrGroups === []) { + return null; + } + + $hasChanged = false; + + foreach ($node->attrGroups as $attrGroupKey => $attrGroup) { + foreach ($attrGroup->attrs as $attrKey => $attribute) { + if (! $this->isName($attribute->name, 'Deprecated')) { + continue; + } + + $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); + $phpDocInfo->addPhpDocTagNode( + new PhpDocTagNode('@deprecated', new GenericTagValueNode($this->createTagValue($attribute))) + ); + + unset($attrGroup->attrs[$attrKey]); + $hasChanged = true; + } + + if ($attrGroup->attrs === []) { + unset($node->attrGroups[$attrGroupKey]); + } + } + + if (! $hasChanged) { + return null; + } + + $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); + + return $node; + } + + private function createTagValue(Attribute $attribute): string + { + $message = null; + $since = null; + + foreach ($attribute->args as $position => $arg) { + $value = $this->valueResolver->getValue($arg->value); + if (! is_string($value)) { + continue; + } + + $name = $arg instanceof Arg && $arg->name instanceof Identifier + ? $arg->name->toString() + : ($position === 0 ? 'message' : 'since'); + + if ($name === 'since') { + $since = $value; + } elseif ($name === 'message') { + $message = $value; + } + } + + $parts = array_filter([$since, $message], static fn (?string $part): bool => $part !== null && $part !== ''); + + return implode(' ', array_map(static fn (string $part): string => (string) preg_replace( + '#\s+#', + ' ', + trim($part) + ), $parts)); + } +}