make use of Types of doc types (#4444)

This commit is contained in:
Tomas Votruba 2020-10-18 21:49:54 +02:00 committed by GitHub
parent 26ab509d7a
commit f96372e1c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 96 additions and 45 deletions

View File

@ -337,9 +337,9 @@ final class PhpDocInfo
return $paramTypesByName;
}
public function changeVarType(Type $newType): void
public function changeVarType(Type $type): void
{
$this->phpDocTypeChanger->changeVarType($this, $newType);
$this->phpDocTypeChanger->changeVarType($this, $type);
}
public function changeReturnType(Type $newType): void

View File

@ -7,6 +7,7 @@ namespace Rector\NodeTypeResolver\PHPStan;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\ArrayType;
use PHPStan\Type\ConstantType;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
@ -40,6 +41,10 @@ final class TypeHasher
return $type->getFullyQualifiedName();
}
if ($type instanceof GenericObjectType) {
return $this->phpStanStaticTypeMapper->mapToDocString($type);
}
if ($type instanceof TypeWithClassName) {
return $type->getClassName();
}

View File

@ -4,31 +4,28 @@ declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\PhpDoc;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareArrayTypeNode;
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareFullyQualifiedIdentifierTypeNode;
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareIdentifierTypeNode;
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareUnionTypeNode;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
final class CollectionTypeFactory
{
public function createFromIdentifierType(IdentifierTypeNode $identifierTypeNode): AttributeAwareUnionTypeNode
public function createType(FullyQualifiedObjectType $fullyQualifiedObjectType): UnionType
{
$genericTypeNode = $this->createGenericTypeNode($identifierTypeNode);
$genericType = $this->createGenericObjectType($fullyQualifiedObjectType);
$arrayType = new ArrayType(new MixedType(), $fullyQualifiedObjectType);
return new AttributeAwareUnionTypeNode([
$genericTypeNode,
new AttributeAwareArrayTypeNode($identifierTypeNode),
]);
return new UnionType([$genericType, $arrayType]);
}
private function createGenericTypeNode(IdentifierTypeNode $identifierTypeNode): GenericTypeNode
private function createGenericObjectType(FullyQualifiedObjectType $fullyQualifiedObjectType): Type
{
$genericTypesNodes = [new AttributeAwareIdentifierTypeNode('int'), $identifierTypeNode];
$genericTypes = [new IntegerType(), $fullyQualifiedObjectType];
return new GenericTypeNode(new AttributeAwareFullyQualifiedIdentifierTypeNode(
'Doctrine\Common\Collections\Collection'
), $genericTypesNodes);
return new GenericObjectType('Doctrine\Common\Collections\Collection', $genericTypes);
}
}

View File

@ -4,37 +4,52 @@ declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\PhpDoc;
use PhpParser\Node;
use PhpParser\Node\Stmt\Property;
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareIdentifierTypeNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\OneToManyTagValueNode;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
use Rector\StaticTypeMapper\PHPStan\NameScopeFactory;
final class CollectionTypeResolver
{
public function resolveFromType(TypeNode $typeNode): ?IdentifierTypeNode
/**
* @var NameScopeFactory
*/
private $nameScopeFactory;
public function __construct(NameScopeFactory $nameScopeFactory)
{
$this->nameScopeFactory = $nameScopeFactory;
}
public function resolveFromTypeNode(TypeNode $typeNode, Node $node): ?FullyQualifiedObjectType
{
if ($typeNode instanceof UnionTypeNode) {
foreach ($typeNode->types as $unionedTypeNode) {
if ($this->resolveFromType($unionedTypeNode) !== null) {
return $this->resolveFromType($unionedTypeNode);
$resolvedUnionedType = $this->resolveFromTypeNode($unionedTypeNode, $node);
if ($resolvedUnionedType !== null) {
return $resolvedUnionedType;
}
}
}
if ($typeNode instanceof ArrayTypeNode && $typeNode->type instanceof IdentifierTypeNode) {
return $typeNode->type;
$nameScope = $this->nameScopeFactory->createNameScopeFromNode($node);
$fullyQualifiedName = $nameScope->resolveStringName($typeNode->type->name);
return new FullyQualifiedObjectType($fullyQualifiedName);
}
return null;
}
public function resolveFromOneToManyProperty(Property $property): ?IdentifierTypeNode
public function resolveFromOneToManyProperty(Property $property): ?FullyQualifiedObjectType
{
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
if (! $phpDocInfo instanceof PhpDocInfo) {
@ -51,6 +66,6 @@ final class CollectionTypeResolver
throw new ShouldNotHappenException();
}
return new AttributeAwareIdentifierTypeNode($fullyQualifiedTargetEntity);
return new FullyQualifiedObjectType($fullyQualifiedTargetEntity);
}
}

View File

@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareVarTagValueNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\OneToManyTagValueNode;
use Rector\Core\PhpParser\Node\Manipulator\AssignManipulator;
@ -139,27 +138,25 @@ CODE_SAMPLE
$attributeAwareVarTagValueNode = $this->collectionVarTagValueNodeResolver->resolve($property);
if ($attributeAwareVarTagValueNode !== null) {
$collectionObjectType = $this->collectionTypeResolver->resolveFromType(
$attributeAwareVarTagValueNode->type
$collectionObjectType = $this->collectionTypeResolver->resolveFromTypeNode(
$attributeAwareVarTagValueNode->type,
$property
);
if ($collectionObjectType === null) {
return null;
}
$attributeAwareVarTagValueNode->type = $this->collectionTypeFactory->createFromIdentifierType(
$collectionObjectType
);
$newVarType = $this->collectionTypeFactory->createType($collectionObjectType);
$phpDocInfo->changeVarType($newVarType);
} else {
$collectionObjectType = $this->collectionTypeResolver->resolveFromOneToManyProperty($property);
if ($collectionObjectType === null) {
return null;
}
$attributeAwareUnionTypeNode = $this->collectionTypeFactory->createFromIdentifierType(
$collectionObjectType
);
$attributeAwareVarTagValueNode = new AttributeAwareVarTagValueNode($attributeAwareUnionTypeNode, '', '');
$phpDocInfo->addTagValueNode($attributeAwareVarTagValueNode);
$newVarType = $this->collectionTypeFactory->createType($collectionObjectType);
$phpDocInfo->changeVarType($newVarType);
}
return $property;

View File

@ -4,6 +4,7 @@ namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollec
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -24,6 +25,7 @@ namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollec
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -32,7 +34,7 @@ class NoVar
{
/**
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
* @var \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training[]|\Doctrine\Common\Collections\Collection<int, \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training>
*/
private $trainings = [];
}

View File

@ -4,6 +4,7 @@ namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollec
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -32,6 +33,7 @@ namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollec
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -40,12 +42,12 @@ class ParamWithoutArray
{
/**
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
* @var \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training[]|\Doctrine\Common\Collections\Collection<int, \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training>
*/
private $trainings = [];
/**
* @param \Doctrine\Common\Collections\Collection<int, Training>|Training[] $collection
* @param \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training[]|\Doctrine\Common\Collections\Collection<int, \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training> $collection
*/
public function setTrainings($collection): void
{

View File

@ -0,0 +1,19 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
*/
class SkipAlready
{
/**
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
* @var Collection<int, Training>|Training[]
*/
private $trainings = [];
}

View File

@ -4,6 +4,7 @@ namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollec
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -25,6 +26,7 @@ namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollec
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -33,7 +35,7 @@ class VarSomeClass
{
/**
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
* @var \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training[]|\Doctrine\Common\Collections\Collection<int, \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training>
*/
private $trainings = [];
}

View File

@ -2,8 +2,8 @@
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -23,8 +23,8 @@ class VarWithoutArray
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -33,7 +33,7 @@ class VarWithoutArray
{
/**
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
* @var \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training[]|\Doctrine\Common\Collections\Collection<int, \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training>
*/
private $trainings = [];
}

View File

@ -3,6 +3,7 @@
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -23,6 +24,7 @@ class VarWithoutCollection
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
use Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training;
/**
* @ORM\Entity
@ -31,7 +33,7 @@ class VarWithoutCollection
{
/**
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
* @var \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training[]|\Doctrine\Common\Collections\Collection<int, \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source\Training>
*/
private $trainings = [];
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Source;
final class Training
{
}