[PHP 7.4] Add id tag support + remove default array on collection

This commit is contained in:
TomasVotruba 2020-03-24 22:26:12 +01:00
parent 1d11fa00b5
commit 35ef3a0217
8 changed files with 145 additions and 6 deletions

View File

@ -36,6 +36,16 @@ abstract class AbstractTagValueNode implements AttributeAwareNodeInterface, PhpD
*/
protected $orderedVisibleItems;
/**
* @var bool
*/
protected $hasOpeningBracket = false;
/**
* @var bool
*/
protected $hasClosingBracket = false;
/**
* @param mixed[] $item
*/
@ -145,5 +155,8 @@ abstract class AbstractTagValueNode implements AttributeAwareNodeInterface, PhpD
$this->hasNewlineAfterOpening = (bool) Strings::match($originalContent, '#^(\(\s+|\n)#m');
$this->hasNewlineBeforeClosing = (bool) Strings::match($originalContent, '#(\s+\)|\n(\s+)?)$#m');
$this->hasOpeningBracket = (bool) Strings::match($originalContent, '#^\(#');
$this->hasClosingBracket = (bool) Strings::match($originalContent, '#\)$#');
}
}

View File

@ -8,9 +8,24 @@ use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode;
final class IdTagValueNode extends AbstractDoctrineTagValueNode
{
public function __construct(?string $annotationContent = null)
{
$this->resolveOriginalContentSpacingAndOrder($annotationContent);
}
public function __toString(): string
{
return '';
$content = '';
if ($this->hasOpeningBracket) {
$content .= '(';
}
if ($this->hasClosingBracket) {
$content .= ')';
}
return $content;
}
public function getShortName(): string

View File

@ -20,6 +20,8 @@ final class IdPhpDocNodeFactory extends AbstractPhpDocNodeFactory
public function createFromNodeAndTokens(Node $node, TokenIterator $tokenIterator): ?PhpDocTagValueNode
{
return new IdTagValueNode();
$annotationContent = $this->resolveContentFromTokenIterator($tokenIterator);
return new IdTagValueNode($annotationContent);
}
}

View File

@ -39,8 +39,8 @@ final class IntersectionTypeMapper implements TypeMapperInterface
{
$intersectionTypesNodes = [];
foreach ($type->getTypes() as $unionedType) {
$intersectionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType);
foreach ($type->getTypes() as $intersectionedType) {
$intersectionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($intersectionedType);
}
$intersectionTypesNodes = array_unique($intersectionTypesNodes);

View File

@ -121,6 +121,7 @@ PHP
}
$this->removeVarPhpTagValueNodeIfNotComment($node, $varType);
$this->removeDefaultValueForDoctrineCollection($node, $varType);
$node->type = $propertyTypeNode;
@ -181,4 +182,14 @@ PHP
{
return $varTagValueNode->type instanceof ArrayTypeNode;
}
private function removeDefaultValueForDoctrineCollection(Property $property, Type $varType): void
{
if (! $this->doctrineTypeAnalyzer->isDoctrineCollectionWithIterableUnionType($varType)) {
return;
}
$onlyProperty = $property->props[0];
$onlyProperty->default = null;
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Pehapkari\Training\Entity\TrainingTerm;
/**
* @ORM\Entity
*/
class DoctrineCollectionWithDefaultArray
{
/**
* @ORM\OneToMany(targetEntity="Pehapkari\Training\Entity\TrainingTerm", mappedBy="training")
* @var TrainingTerm[]|Collection
*/
private $trainingTerms = [];
}
?>
-----
<?php
namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Pehapkari\Training\Entity\TrainingTerm;
/**
* @ORM\Entity
*/
class DoctrineCollectionWithDefaultArray
{
/**
* @ORM\OneToMany(targetEntity="Pehapkari\Training\Entity\TrainingTerm", mappedBy="training")
* @var TrainingTerm[]|Collection
*/
private \Doctrine\Common\Collections\Collection $trainingTerms;
}
?>

View File

@ -0,0 +1,38 @@
<?php
namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class DoctrineId
{
/**
* @ORM\Id()
* @var int
*/
private $id;
}
?>
-----
<?php
namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class DoctrineId
{
/**
* @ORM\Id()
*/
private int $id;
}
?>

View File

@ -10,6 +10,7 @@ use PHPStan\Type\NullType;
use PHPStan\Type\Type;
use PHPStan\Type\VoidType;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\PHPStanStaticTypeMapper\DoctrineTypeAnalyzer;
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer\DefaultValuePropertyTypeInferer;
@ -30,17 +31,24 @@ final class PropertyTypeInferer extends AbstractPriorityAwareTypeInferer
*/
private $typeFactory;
/**
* @var DoctrineTypeAnalyzer
*/
private $doctrineTypeAnalyzer;
/**
* @param PropertyTypeInfererInterface[] $propertyTypeInferers
*/
public function __construct(
array $propertyTypeInferers,
DefaultValuePropertyTypeInferer $defaultValuePropertyTypeInferer,
TypeFactory $typeFactory
TypeFactory $typeFactory,
DoctrineTypeAnalyzer $doctrineTypeAnalyzer
) {
$this->propertyTypeInferers = $this->sortTypeInferersByPriority($propertyTypeInferers);
$this->defaultValuePropertyTypeInferer = $defaultValuePropertyTypeInferer;
$this->typeFactory = $typeFactory;
$this->doctrineTypeAnalyzer = $doctrineTypeAnalyzer;
}
public function inferProperty(Property $property): Type
@ -53,7 +61,7 @@ final class PropertyTypeInferer extends AbstractPriorityAwareTypeInferer
// default value type must be added to each resolved type
$defaultValueType = $this->defaultValuePropertyTypeInferer->inferProperty($property);
if (! $defaultValueType instanceof MixedType) {
if ($this->shouldUnionWithDefaultValue($defaultValueType, $type)) {
return $this->unionWithDefaultValueType($type, $defaultValueType);
}
@ -73,4 +81,13 @@ final class PropertyTypeInferer extends AbstractPriorityAwareTypeInferer
$types = [$type, $defaultValueType];
return $this->typeFactory->createMixedPassedOrUnionType($types);
}
private function shouldUnionWithDefaultValue(Type $defaultValueType, Type $type): bool
{
if ($defaultValueType instanceof MixedType) {
return false;
}
return ! $this->doctrineTypeAnalyzer->isDoctrineCollectionWithIterableUnionType($type);
}
}