diff --git a/packages/attribute-aware-php-doc/src/Ast/PhpDoc/AttributeAwareDataProviderTagValueNode.php b/packages/attribute-aware-php-doc/src/Ast/PhpDoc/DataProviderTagValueNode.php similarity index 88% rename from packages/attribute-aware-php-doc/src/Ast/PhpDoc/AttributeAwareDataProviderTagValueNode.php rename to packages/attribute-aware-php-doc/src/Ast/PhpDoc/DataProviderTagValueNode.php index b16b1cdf661..a8d452f8ebb 100644 --- a/packages/attribute-aware-php-doc/src/Ast/PhpDoc/AttributeAwareDataProviderTagValueNode.php +++ b/packages/attribute-aware-php-doc/src/Ast/PhpDoc/DataProviderTagValueNode.php @@ -8,7 +8,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode; use Rector\BetterPhpDocParser\Attributes\Attribute\AttributeTrait; use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface; -final class AttributeAwareDataProviderTagValueNode implements PhpDocTagValueNode, AttributeAwareNodeInterface +final class DataProviderTagValueNode implements PhpDocTagValueNode, AttributeAwareNodeInterface { use AttributeTrait; diff --git a/packages/attribute-aware-php-doc/src/Ast/PhpDoc/RequiredTagValueNode.php b/packages/attribute-aware-php-doc/src/Ast/PhpDoc/RequiredTagValueNode.php new file mode 100644 index 00000000000..8f224cbfac2 --- /dev/null +++ b/packages/attribute-aware-php-doc/src/Ast/PhpDoc/RequiredTagValueNode.php @@ -0,0 +1,38 @@ +privatesCaller->callPrivateMethod( $this->phpDocParser, @@ -65,6 +65,6 @@ final class PHPUnitDataProviderDocNodeFactory $tokenIterator ); - return new AttributeAwareDataProviderTagValueNode($method); + return new DataProviderTagValueNode($method); } } diff --git a/packages/better-php-doc-parser/src/PhpDocParser/BetterPhpDocParser.php b/packages/better-php-doc-parser/src/PhpDocParser/BetterPhpDocParser.php index 875ca9f877c..5423b2af784 100644 --- a/packages/better-php-doc-parser/src/PhpDocParser/BetterPhpDocParser.php +++ b/packages/better-php-doc-parser/src/PhpDocParser/BetterPhpDocParser.php @@ -15,6 +15,7 @@ use PHPStan\PhpDocParser\Parser\PhpDocParser; use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocNode; +use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\RequiredTagValueNode; use Rector\BetterPhpDocParser\Attributes\Ast\AttributeAwareNodeFactory; use Rector\BetterPhpDocParser\Attributes\Attribute\Attribute; use Rector\BetterPhpDocParser\Contract\GenericPhpDocNodeFactoryInterface; @@ -26,6 +27,7 @@ use Rector\BetterPhpDocParser\Printer\MultilineSpaceFormatPreserver; use Rector\BetterPhpDocParser\ValueObject\StartAndEnd; use Rector\Core\Configuration\CurrentNodeProvider; use Rector\Core\Exception\ShouldNotHappenException; +use Rector\PhpAttribute\ValueObject\TagName; use Symplify\PackageBuilder\Reflection\PrivatesAccessor; use Symplify\PackageBuilder\Reflection\PrivatesCaller; @@ -186,13 +188,16 @@ final class BetterPhpDocParser extends PhpDocParser throw new ShouldNotHappenException(); } - if (strtolower($tag) === '@param') { + $lowercasedTag = strtolower($tag); + if ($lowercasedTag === '@param') { // to prevent circular reference of this service $this->paramPhpDocNodeFactory->setPhpDocParser($this); $tagValueNode = $this->paramPhpDocNodeFactory->createFromTokens($tokenIterator); - } elseif (strtolower($tag) === '@dataprovider') { + } elseif ($lowercasedTag === '@dataprovider') { $this->phpUnitDataProviderDocNodeFactory->setPhpDocParser($this); $tagValueNode = $this->phpUnitDataProviderDocNodeFactory->createFromTokens($tokenIterator); + } elseif ($lowercasedTag === '@' . TagName::REQUIRED) { + $tagValueNode = new RequiredTagValueNode(); } else { // class-annotation $phpDocNodeFactory = $this->matchTagToPhpDocNodeFactory($tag); diff --git a/packages/php-attribute/config/config.php b/packages/php-attribute/config/config.php index fa7c2325c11..cd5e28bbee5 100644 --- a/packages/php-attribute/config/config.php +++ b/packages/php-attribute/config/config.php @@ -13,5 +13,5 @@ return static function (ContainerConfigurator $containerConfigurator): void { ->autoconfigure(); $services->load('Rector\PhpAttribute\\', __DIR__ . '/../src') - ->exclude([__DIR__ . '/../src/Contract']); + ->exclude([__DIR__ . '/../src/Contract', __DIR__ . '/../src/ValueObject']); }; diff --git a/packages/php-attribute/src/AnnotationToAttributeConverter.php b/packages/php-attribute/src/AnnotationToAttributeConverter.php index e2a69d5764f..4c8f050c3fb 100644 --- a/packages/php-attribute/src/AnnotationToAttributeConverter.php +++ b/packages/php-attribute/src/AnnotationToAttributeConverter.php @@ -6,10 +6,8 @@ namespace Rector\PhpAttribute; use PhpParser\Node; use PhpParser\Node\Attribute; -use PhpParser\Node\AttributeGroup; use PhpParser\Node\Expr\ArrowFunction; use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; @@ -44,15 +42,7 @@ final class AnnotationToAttributeConverter return null; } - // special cases without tag value node $hasNewAttrGroups = false; - if ($phpDocInfo->hasByName('required')) { - $phpDocInfo->removeByName('required'); - $node->attrGroups[] = new AttributeGroup([ - new Attribute(new FullyQualified('Symfony\Contracts\Service\Attribute\Required')), - ]); - $hasNewAttrGroups = true; - } // 0. has 0 nodes, nothing to change /** @var PhpAttributableTagNodeInterface[] $phpAttributableTagNodes */ diff --git a/packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php b/packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php index cba5e7dc6bb..867df95f34e 100644 --- a/packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php +++ b/packages/php-attribute/src/Printer/PhpAttributteGroupFactory.php @@ -11,7 +11,6 @@ use PhpParser\Node\AttributeGroup; use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PhpParser\Node\Name\FullyQualified; -use Rector\BetterPhpDocParser\Contract\PhpDocNode\SilentKeyNodeInterface; use Rector\PhpAttribute\Contract\ManyPhpAttributableTagNodeInterface; use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface; @@ -43,13 +42,7 @@ final class PhpAttributteGroupFactory public function printItemsToAttributeArgs(PhpAttributableTagNodeInterface $phpAttributableTagNode): array { $items = $phpAttributableTagNode->getAttributableItems(); - - $silentKey = null; - if ($phpAttributableTagNode instanceof SilentKeyNodeInterface) { - $silentKey = $phpAttributableTagNode->getSilentKey(); - } - - return $this->createArgsFromItems($items, $silentKey); + return $this->createArgsFromItems($items); } /** diff --git a/packages/php-attribute/src/ValueObject/TagName.php b/packages/php-attribute/src/ValueObject/TagName.php new file mode 100644 index 00000000000..b2ba2f044b3 --- /dev/null +++ b/packages/php-attribute/src/ValueObject/TagName.php @@ -0,0 +1,15 @@ +hasByName('required'); + return $phpDocInfo->hasByName(TagName::REQUIRED); } } diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/symfony_route.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/symfony_route.php.inc index 617c5023cd6..15f5d5c6bc4 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/symfony_route.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/Fixture/symfony_route.php.inc @@ -24,7 +24,7 @@ use Symfony\Component\Routing\Annotation\Route; class SymfonyRoute { - #[\Symfony\Component\Routing\Annotation\Route('/path', name: 'action')] + #[\Symfony\Component\Routing\Annotation\Route(path: '/path', name: 'action')] public function action() { } diff --git a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/FixtureAutoImported/imported_symfony_route.php.inc b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/FixtureAutoImported/imported_symfony_route.php.inc index 0661cf43384..8b95a8c6010 100644 --- a/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/FixtureAutoImported/imported_symfony_route.php.inc +++ b/rules/php80/tests/Rector/Class_/AnnotationToAttributeRector/FixtureAutoImported/imported_symfony_route.php.inc @@ -24,7 +24,7 @@ use Symfony\Component\Routing\Annotation\Route; class SymfonyRoute { - #[Route('/path', name: 'action')] + #[Route(path: '/path', name: 'action')] public function action() { } diff --git a/rules/phpunit/src/Rector/Class_/RemoveDataProviderTestPrefixRector.php b/rules/phpunit/src/Rector/Class_/RemoveDataProviderTestPrefixRector.php index b4e9f5d176d..eadd68d6f09 100644 --- a/rules/phpunit/src/Rector/Class_/RemoveDataProviderTestPrefixRector.php +++ b/rules/phpunit/src/Rector/Class_/RemoveDataProviderTestPrefixRector.php @@ -8,7 +8,7 @@ use Nette\Utils\Strings; use PhpParser\Node; use PhpParser\Node\Identifier; use PhpParser\Node\Stmt\Class_; -use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareDataProviderTagValueNode; +use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\DataProviderTagValueNode; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\Core\Rector\AbstractPHPUnitRector; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -107,8 +107,8 @@ CODE_SAMPLE continue; } - /** @var AttributeAwareDataProviderTagValueNode[] $dataProviderTagValueNodes */ - $dataProviderTagValueNodes = $phpDocInfo->findAllByType(AttributeAwareDataProviderTagValueNode::class); + /** @var DataProviderTagValueNode[] $dataProviderTagValueNodes */ + $dataProviderTagValueNodes = $phpDocInfo->findAllByType(DataProviderTagValueNode::class); if ($dataProviderTagValueNodes === []) { continue; } diff --git a/rules/privatization/src/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector.php b/rules/privatization/src/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector.php index a46a438b452..d49e8ea7904 100644 --- a/rules/privatization/src/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector.php +++ b/rules/privatization/src/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector.php @@ -12,6 +12,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\Caching\Contract\Rector\ZeroCacheRectorInterface; use Rector\Core\Rector\AbstractRector; use Rector\NodeTypeResolver\Node\AttributeKey; +use Rector\PhpAttribute\ValueObject\TagName; use Rector\Privatization\NodeAnalyzer\ClassMethodExternalCallNodeAnalyzer; use Rector\VendorLocker\NodeVendorLocker\ClassMethodVisibilityVendorLockResolver; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -161,7 +162,7 @@ CODE_SAMPLE return false; } - return $phpDocInfo->hasByNames(['api', 'required']); + return $phpDocInfo->hasByNames(['api', TagName::REQUIRED]); } private function isControllerAction(Class_ $class, ClassMethod $classMethod): bool diff --git a/rules/privatization/src/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector.php b/rules/privatization/src/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector.php index 8c7b98d28c4..68ff1cd0b70 100644 --- a/rules/privatization/src/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector.php +++ b/rules/privatization/src/Rector/Property/PrivatizeLocalPropertyToPrivatePropertyRector.php @@ -11,6 +11,7 @@ use PhpParser\Node\Stmt\Property; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\Core\Rector\AbstractRector; use Rector\NodeTypeResolver\Node\AttributeKey; +use Rector\PhpAttribute\ValueObject\TagName; use Rector\VendorLocker\NodeVendorLocker\PropertyVisibilityVendorLockResolver; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -26,7 +27,7 @@ final class PrivatizeLocalPropertyToPrivatePropertyRector extends AbstractRector private const ANNOTATIONS_REQUIRING_PUBLIC = [ 'api', // Symfony DI - 'required', + TagName::REQUIRED, // other DI 'inject', ]; diff --git a/rules/solid/src/NodeFactory/InjectMethodFactory.php b/rules/solid/src/NodeFactory/InjectMethodFactory.php index 4469e0834b8..dd15c619329 100644 --- a/rules/solid/src/NodeFactory/InjectMethodFactory.php +++ b/rules/solid/src/NodeFactory/InjectMethodFactory.php @@ -14,6 +14,7 @@ use Rector\Core\PhpParser\Builder\ParamBuilder; use Rector\Core\PhpParser\Node\NodeFactory; use Rector\Naming\Naming\PropertyNaming; use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory; +use Rector\PhpAttribute\ValueObject\TagName; use Rector\SOLID\Rector\Class_\MultiParentingToAbstractDependencyRector; final class InjectMethodFactory @@ -86,7 +87,7 @@ final class InjectMethodFactory if ($framework === MultiParentingToAbstractDependencyRector::FRAMEWORK_SYMFONY) { $phpDocInfo = $this->phpDocInfoFactory->createEmpty($classMethod); - $phpDocInfo->addBareTag('required'); + $phpDocInfo->addBareTag(TagName::REQUIRED); } return $classMethod; diff --git a/rules/symfony/src/Rector/ClassMethod/AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector.php b/rules/symfony/src/Rector/ClassMethod/AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector.php index f41f8fb570e..1e6796b22e8 100644 --- a/rules/symfony/src/Rector/ClassMethod/AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector.php +++ b/rules/symfony/src/Rector/ClassMethod/AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector.php @@ -9,6 +9,7 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Rector\AbstractRector; use Rector\NodeTypeResolver\Node\AttributeKey; +use Rector\PhpAttribute\ValueObject\TagName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -17,11 +18,6 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; */ final class AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector extends AbstractRector { - /** - * @var string - */ - private const REQUIRED_TAG = 'required'; - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -65,7 +61,7 @@ CODE_SAMPLE */ public function refactor(Node $node): ?Node { - if (! $this->hasTagByName($node, self::REQUIRED_TAG)) { + if (! $this->hasTagByName($node, TagName::REQUIRED)) { return null; } diff --git a/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php b/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php index 82860219c7f..6314e647615 100644 --- a/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php +++ b/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php @@ -13,7 +13,7 @@ use PhpParser\Node\Stmt\Return_; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; -use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareDataProviderTagValueNode; +use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\DataProviderTagValueNode; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -78,8 +78,8 @@ final class PHPUnitDataProviderParamTypeInferer implements ParamTypeInfererInter return null; } - /** @var AttributeAwareDataProviderTagValueNode|null $attributeAwareDataProviderTagValueNode */ - $attributeAwareDataProviderTagValueNode = $phpDocInfo->getByType(AttributeAwareDataProviderTagValueNode::class); + /** @var DataProviderTagValueNode|null $attributeAwareDataProviderTagValueNode */ + $attributeAwareDataProviderTagValueNode = $phpDocInfo->getByType(DataProviderTagValueNode::class); if ($attributeAwareDataProviderTagValueNode === null) { return null; }