Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/TypeDeclaration/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ services:

Rector\TypeDeclaration\:
resource: '../src/'
exclude: '../src/{Rector/**/*Rector.php}'
exclude: '../src/{Rector/**/*Rector.php,Exception}'
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ interface PropertyTypeInfererInterface
* @return string[]
*/
public function inferProperty(Property $property): array;

/**
* Higher priority goes first.
*/
public function getPriority(): int;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);

namespace Rector\TypeDeclaration\Exception;

use Exception;
use Rector\TypeDeclaration\Contract\PropertyTypeInfererInterface;

final class ConflictingPriorityException extends Exception
{
public function __construct(
PropertyTypeInfererInterface $firstPropertyTypeInfererInterface,
PropertyTypeInfererInterface $secondPropertyTypeInfererInterface
) {
$message = sprintf(
'There are 2 property type inferers with %d priority:%s- %s%s- %s.%sChange value in "getPriority()" method in one of them to different value',
$firstPropertyTypeInfererInterface->getPriority(),
PHP_EOL,
get_class($firstPropertyTypeInfererInterface),
PHP_EOL,
get_class($secondPropertyTypeInfererInterface),
PHP_EOL
);

parent::__construct($message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Type\ArrayType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
Expand Down Expand Up @@ -36,6 +37,11 @@ public function inferProperty(Node\Stmt\Property $property): array
return $this->staticTypeToStringResolver->resolveObjectType($assignedExprStaticType);
}

public function getPriority(): int
{
return 500;
}

/**
* @return Type[]
*/
Expand All @@ -61,6 +67,10 @@ private function collectAllPropertyAsignExprStaticTypes(ClassLike $classLike, st
return null;
}

if ($exprStaticType instanceof ErrorType) {
return null;
}

if ($node->var instanceof ArrayDimFetch) {
$exprStaticType = new ArrayType(new MixedType(), $exprStaticType);
}
Expand All @@ -70,7 +80,7 @@ private function collectAllPropertyAsignExprStaticTypes(ClassLike $classLike, st
return null;
});

return $assignedExprStaticTypes;
return $this->filterOutDuplicatedTypes($assignedExprStaticTypes);
}

/**
Expand Down Expand Up @@ -98,4 +108,23 @@ private function matchPropertyAssignExpr(Assign $assign, string $propertyName):

return null;
}

/**
* @param Type[] $types
* @return Type[]
*/
private function filterOutDuplicatedTypes(array $types): array
{
if (count($types) === 1) {
return $types;
}

$uniqueTypes = [];
foreach ($types as $type) {
$valueObjectHash = md5(serialize($type));
$uniqueTypes[$valueObjectHash] = $type;
}

return $uniqueTypes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ public function inferProperty(Node\Stmt\Property $property): array
return [];
}

public function getPriority(): int
{
return 800;
}

private function getResolveParamStaticTypeAsString(ClassMethod $classMethod, string $propertyName): ?string
{
$paramStaticType = $this->resolveParamStaticType($classMethod, $propertyName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ public function inferProperty(Property $property): array

return $this->staticTypeToStringResolver->resolveObjectType($nodeStaticType);
}

public function getPriority(): int
{
return 700;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ public function inferProperty(Property $property): array
return $types;
}

public function getPriority(): int
{
return 1000;
}

private function isNullable(string $value): bool
{
return (bool) Strings::match($value, '#nullable=true#');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ public function inferProperty(Property $property): array
return [];
}

public function getPriority(): int
{
return 900;
}

private function resolveTargetEntity(GenericTagValueNode $genericTagValueNode): ?string
{
$match = Strings::match($genericTagValueNode->value, '#targetEntity=\"(?<targetEntity>.*?)\"#');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ public function inferProperty(Property $property): array

return [];
}

public function getPriority(): int
{
return 600;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ public function inferProperty(Property $property): array
return $stringTypes;
}

public function getPriority(): int
{
return 750;
}

private function resolveAssignedNodeToProperty(ClassMethod $classMethod, string $propertyName): ?Expr
{
$assignedNode = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\Contract\PropertyTypeInfererInterface;
use Rector\TypeDeclaration\Exception\ConflictingPriorityException;

final class PropertyTypeDeclarationRector extends AbstractRector
{
Expand All @@ -29,7 +30,8 @@ final class PropertyTypeDeclarationRector extends AbstractRector
public function __construct(DocBlockManipulator $docBlockManipulator, array $propertyTypeInferers = [])
{
$this->docBlockManipulator = $docBlockManipulator;
$this->propertyTypeInferers = $propertyTypeInferers;

$this->sortAndSetPropertyTypeInferers($propertyTypeInferers);
}

public function getDefinition(): RectorDefinition
Expand Down Expand Up @@ -80,4 +82,27 @@ private function setNodeVarTypes(Node $node, array $varTypes): Node

return $node;
}

/**
* @param PropertyTypeInfererInterface[] $propertyTypeInferers
*/
private function sortAndSetPropertyTypeInferers(array $propertyTypeInferers): void
{
foreach ($propertyTypeInferers as $propertyTypeInferer) {
$this->ensurePriorityIsUnique($propertyTypeInferer);
$this->propertyTypeInferers[$propertyTypeInferer->getPriority()] = $propertyTypeInferer;
}

krsort($this->propertyTypeInferers);
}

private function ensurePriorityIsUnique(PropertyTypeInfererInterface $propertyTypeInferer): void
{
if (! isset($this->propertyTypeInferers[$propertyTypeInferer->getPriority()])) {
return;
}

$alreadySetPropertyTypeInferer = $this->propertyTypeInferers[$propertyTypeInferer->getPriority()];
throw new ConflictingPriorityException($propertyTypeInferer, $alreadySetPropertyTypeInferer);
}
}
Loading