diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index 97337ef6f0f..4780bc4e881 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -6,6 +6,9 @@ // $container->get(Type::class) → instance of "Type" override(\Psr\Container\ContainerInterface::get(0), type(0)); +// $propertyPhpDocInfo->getByType(Type::class) → instance of "Type"|null - @todo how to make this nullable? +override(\Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo::getByType(0), type(0)); + // PhpStorm 2019.1 - add argument autocomplete // https://blog.jetbrains.com/phpstorm/2019/02/new-phpstorm-meta-php-features/ expectedArguments( diff --git a/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php b/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php index ea9ad06705a..5e7aee61c0e 100644 --- a/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php +++ b/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php @@ -5,6 +5,7 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; use Rector\Architecture\Tests\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector\RemoveRepositoryFromEntityAnnotationRectorTest; +use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Class_\EntityTagValueNode; use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; @@ -73,7 +74,7 @@ public function refactor(Node $node): ?Node $phpDocInfo = $this->docBlockManipulator->createPhpDocInfoFromNode($node); - $doctrineEntityTag = $phpDocInfo->getDoctrineEntity(); + $doctrineEntityTag = $phpDocInfo->getByType(EntityTagValueNode::class); if ($doctrineEntityTag === null) { return null; } diff --git a/packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfo.php b/packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfo.php index 487f9dec3d3..8efee2e4313 100644 --- a/packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfo.php +++ b/packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfo.php @@ -13,14 +13,6 @@ use Rector\BetterPhpDocParser\Attributes\Ast\PhpDoc\AttributeAwareVarTagValueNode; use Rector\BetterPhpDocParser\Attributes\Attribute\Attribute; use Rector\BetterPhpDocParser\Attributes\Contract\Ast\AttributeAwareNodeInterface; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Class_\EntityTagValueNode; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\IdTagValueNode; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\JoinColumnTagValueNode; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\ManyToManyTagValueNode; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\ManyToOneTagValueNode; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\OneToManyTagValueNode; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\OneToOneTagValueNode; -use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\TableTagValueNode; use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\DoctrineRelationTagValueNodeInterface; final class PhpDocInfo @@ -176,46 +168,6 @@ public function getVarTypes(): array return $this->getResolvedTypesAttribute($varTagValue); } - public function getDoctrineId(): ?IdTagValueNode - { - return $this->getByType(IdTagValueNode::class); - } - - public function getDoctrineTable(): ?TableTagValueNode - { - return $this->getByType(TableTagValueNode::class); - } - - public function getDoctrineManyToMany(): ?ManyToManyTagValueNode - { - return $this->getByType(ManyToManyTagValueNode::class); - } - - public function getDoctrineManyToOne(): ?ManyToOneTagValueNode - { - return $this->getByType(ManyToOneTagValueNode::class); - } - - public function getDoctrineOneToOne(): ?OneToOneTagValueNode - { - return $this->getByType(OneToOneTagValueNode::class); - } - - public function getDoctrineOneToMany(): ?OneToManyTagValueNode - { - return $this->getByType(OneToManyTagValueNode::class); - } - - public function getDoctrineEntity(): ?EntityTagValueNode - { - return $this->getByType(EntityTagValueNode::class); - } - - public function getDoctrineJoinColumnTagValueNode(): ?JoinColumnTagValueNode - { - return $this->getByType(JoinColumnTagValueNode::class); - } - /** * @return string[] */ @@ -257,10 +209,7 @@ public function getReturnTypes(): array public function getDoctrineRelationTagValueNode(): ?DoctrineRelationTagValueNodeInterface { - return $this->getDoctrineManyToMany() ?? - $this->getDoctrineOneToMany() ?? - $this->getDoctrineOneToOne() ?? - $this->getDoctrineManyToOne() ?? null; + return $this->getByType(DoctrineRelationTagValueNodeInterface::class); } public function removeTagValueNodeFromNode(PhpDocTagValueNode $phpDocTagValueNode): void diff --git a/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php b/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php index c363e3362fc..bced78c4f41 100644 --- a/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php +++ b/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php @@ -6,7 +6,9 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Property; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; +use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Class_\EntityTagValueNode; use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\ColumnTagValueNode; +use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\IdTagValueNode; use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\TableTagValueNode; use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\DoctrineRelationTagValueNodeInterface; use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator; @@ -30,7 +32,7 @@ public function isDoctrineEntityClass(Class_ $class): bool return false; } - return (bool) $classPhpDocInfo->getDoctrineEntity(); + return (bool) $classPhpDocInfo->getByType(EntityTagValueNode::class); } public function isDoctrineEntityClassWithIdProperty(Class_ $class): bool @@ -69,7 +71,7 @@ public function hasPropertyDoctrineIdTag(Property $property): bool return false; } - return (bool) $propertyPhpDocInfo->getDoctrineId(); + return (bool) $propertyPhpDocInfo->getByType(IdTagValueNode::class); } public function getDoctrineRelationTagValueNode(Property $property): ?DoctrineRelationTagValueNodeInterface @@ -89,7 +91,7 @@ public function getDoctrineTableTagValueNode(Class_ $class): ?TableTagValueNode return null; } - return $classPhpDocInfo->getDoctrineTable(); + return $classPhpDocInfo->getByType(TableTagValueNode::class); } public function isDoctrineProperty(Property $property): bool diff --git a/packages/Doctrine/src/Provider/EntityWithMissingUuidProvider.php b/packages/Doctrine/src/Provider/EntityWithMissingUuidProvider.php index fd9b678c57b..1561359bab2 100644 --- a/packages/Doctrine/src/Provider/EntityWithMissingUuidProvider.php +++ b/packages/Doctrine/src/Provider/EntityWithMissingUuidProvider.php @@ -8,6 +8,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver; use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\ColumnTagValueNode; +use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\IdTagValueNode; use Rector\NodeContainer\ParsedNodesByType; use Rector\PhpParser\Node\Manipulator\ClassManipulator; use Rector\PhpParser\Node\Resolver\NameResolver; @@ -111,12 +112,11 @@ private function isPropertyClassIdWithUuidType(Property $property): bool { $propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNode($property); - $idTagValueNode = $propertyPhpDocInfo->getDoctrineId(); + $idTagValueNode = $propertyPhpDocInfo->getByType(IdTagValueNode::class); if ($idTagValueNode === null) { return false; } - /** @var ColumnTagValueNode|null $columnTagValueNode */ $columnTagValueNode = $propertyPhpDocInfo->getByType(ColumnTagValueNode::class); if ($columnTagValueNode === null) { return false; diff --git a/packages/Doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php b/packages/Doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php index ef718e10ebb..0e7a9d1c483 100644 --- a/packages/Doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php +++ b/packages/Doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php @@ -14,6 +14,7 @@ use Rector\Doctrine\PhpDocParser\Ast\PhpDoc\PhpDocTagNodeFactory; use Rector\Doctrine\Provider\EntityWithMissingUuidProvider; use Rector\Doctrine\Uuid\JoinTableNameResolver; +use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\JoinColumnTagValueNode; use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\DoctrineRelationTagValueNodeInterface; use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\ToManyTagNodeInterface; use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\ToOneTagNodeInterface; @@ -148,8 +149,7 @@ private function updateDocComment(Property $property): void private function refactorToManyPropertyPhpDocInfo(PhpDocInfo $propertyPhpDocInfo, Property $property): void { - $doctrineJoinColumnTagValueNode = $propertyPhpDocInfo->getDoctrineJoinColumnTagValueNode(); - + $doctrineJoinColumnTagValueNode = $propertyPhpDocInfo->getByType(JoinColumnTagValueNode::class); if ($doctrineJoinColumnTagValueNode) { // replace @ORM\JoinColumn with @ORM\JoinTable $propertyPhpDocInfo->removeTagValueNodeFromNode($doctrineJoinColumnTagValueNode); @@ -161,7 +161,7 @@ private function refactorToManyPropertyPhpDocInfo(PhpDocInfo $propertyPhpDocInfo private function refactorToOnePropertyPhpDocInfo(PhpDocInfo $propertyPhpDocInfo): void { - $joinColumnTagValueNode = $propertyPhpDocInfo->getDoctrineJoinColumnTagValueNode(); + $joinColumnTagValueNode = $propertyPhpDocInfo->getByType(JoinColumnTagValueNode::class); if ($joinColumnTagValueNode) { $joinColumnTagValueNode->changeNullable(true); diff --git a/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php b/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php index 397c8756406..92a9aff2eb1 100644 --- a/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php +++ b/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php @@ -134,7 +134,6 @@ private function resolveTemplateName(ClassMethod $classMethod): string /** @var PhpDocInfo $classMethodPhpDocInfo */ $classMethodPhpDocInfo = $this->getPhpDocInfo($classMethod); - /** @var TemplateTagValueNode|null $templateTagValueNode */ $templateTagValueNode = $classMethodPhpDocInfo->getByType(TemplateTagValueNode::class); if ($templateTagValueNode === null) { throw new ShouldNotHappenException(__METHOD__); diff --git a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineColumnPropertyTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineColumnPropertyTypeInferer.php index 7041ec76f91..b827c3af35c 100644 --- a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineColumnPropertyTypeInferer.php +++ b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineColumnPropertyTypeInferer.php @@ -70,13 +70,17 @@ public function inferProperty(Property $property): array $phpDocInfo = $this->docBlockManipulator->createPhpDocInfoFromNode($property); - /** @var ColumnTagValueNode|null $doctrineColumnTagValueNode */ $doctrineColumnTagValueNode = $phpDocInfo->getByType(ColumnTagValueNode::class); if ($doctrineColumnTagValueNode === null) { return []; } - $scalarType = $this->doctrineTypeToScalarType[$doctrineColumnTagValueNode->getType()] ?? null; + $type = $doctrineColumnTagValueNode->getType(); + if ($type === null) { + return []; + } + + $scalarType = $this->doctrineTypeToScalarType[$type] ?? null; if ($scalarType === null) { return []; } diff --git a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php index 3f1a1db1ac4..6df1531fa07 100644 --- a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php +++ b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php @@ -44,7 +44,7 @@ public function inferProperty(Property $property): array if ($relationTagValueNode instanceof ToManyTagNodeInterface) { return $this->processToManyRelation($relationTagValueNode); } elseif ($relationTagValueNode instanceof ToOneTagNodeInterface) { - $joinColumnTagValueNode = $phpDocInfo->getDoctrineJoinColumnTagValueNode(); + $joinColumnTagValueNode = $phpDocInfo->getByType(JoinColumnTagValueNode::class); return $this->processToOneRelation($relationTagValueNode, $joinColumnTagValueNode); } diff --git a/utils/PHPStanExtensions/config/phpstan-extensions.neon b/utils/PHPStanExtensions/config/phpstan-extensions.neon index 4b30327deef..e26a4289cff 100644 --- a/utils/PHPStanExtensions/config/phpstan-extensions.neon +++ b/utils/PHPStanExtensions/config/phpstan-extensions.neon @@ -1,7 +1,7 @@ services: - Rector\PHPStanExtensions\Utils\PHPStanValueResolver - # $node->geAttribute($1) => Type|null by $1 + # $node->getAttribute($1) => Type|null by $1 - { class: Rector\PHPStanExtensions\Rector\Type\GetAttributeReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] } # $nameResolver->getName() => in some cases always string @@ -11,3 +11,6 @@ services: # $betterNodeFinder->findByInstance(..., $1) => $1[] - { class: Rector\PHPStanExtensions\Rector\Type\BetterNodeFinderReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] } + + # $phpDocInfo->getByType($1) => Type|null by $1 + - { class: Rector\PHPStanExtensions\Rector\Type\PhpDocInfoGetByTypeReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] } diff --git a/utils/PHPStanExtensions/src/Rector/Type/PhpDocInfoGetByTypeReturnTypeExtension.php b/utils/PHPStanExtensions/src/Rector/Type/PhpDocInfoGetByTypeReturnTypeExtension.php new file mode 100644 index 00000000000..13fc887cd93 --- /dev/null +++ b/utils/PHPStanExtensions/src/Rector/Type/PhpDocInfoGetByTypeReturnTypeExtension.php @@ -0,0 +1,51 @@ +getName() === 'getByType'; + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type { + $returnType = $this->resolveArgumentValue($methodCall->args[0]->value); + + return new UnionType([new ObjectType($returnType), new NullType()]); + } + + private function resolveArgumentValue(Expr $expr): ?string + { + if ($expr instanceof ClassConstFetch) { + if ((string) $expr->name !== 'class') { + return null; + } + + return $expr->class->toString(); + } + + return null; + } +}