decouple ParamTypeInferer

This commit is contained in:
Tomas Votruba 2019-08-31 22:34:27 +02:00
parent f9c44ec25e
commit 328fb06ee2
7 changed files with 113 additions and 79 deletions

View File

@ -12,8 +12,8 @@ use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\Contract\TypeInferer\ParamTypeInfererInterface;
use Rector\TypeDeclaration\PhpDocParser\ParamPhpDocNodeFactory;
use Rector\TypeDeclaration\TypeInferer\ParamTypeInferer;
/**
* @sponsor Thanks https://spaceflow.io/ for sponsoring this rule - visit them on https://github.com/SpaceFlow-app
@ -26,27 +26,24 @@ final class AddArrayParamDocTypeRector extends AbstractRector
*/
private $docBlockManipulator;
/**
* @var ParamTypeInfererInterface[]
*/
private $paramTypeInferers = [];
/**
* @var ParamPhpDocNodeFactory
*/
private $paramPhpDocNodeFactory;
/**
* @param ParamTypeInfererInterface[] $paramTypeInferers
* @var ParamTypeInferer
*/
private $paramTypeInferer;
public function __construct(
DocBlockManipulator $docBlockManipulator,
array $paramTypeInferers,
ParamPhpDocNodeFactory $paramPhpDocNodeFactory
ParamPhpDocNodeFactory $paramPhpDocNodeFactory,
ParamTypeInferer $paramTypeInferer
) {
$this->docBlockManipulator = $docBlockManipulator;
$this->paramTypeInferers = $paramTypeInferers;
$this->paramPhpDocNodeFactory = $paramPhpDocNodeFactory;
$this->paramTypeInferer = $paramTypeInferer;
}
public function getDefinition(): RectorDefinition
@ -114,15 +111,7 @@ CODE_SAMPLE
return null;
}
$types = [];
foreach ($this->paramTypeInferers as $paramTypeInferer) {
$types = $paramTypeInferer->inferParam($param);
if ($types !== []) {
break;
}
}
// no types :/
$types = $this->paramTypeInferer->inferParam($param);
if ($types === []) {
return null;
}

View File

@ -8,7 +8,6 @@ use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\Contract\TypeInferer\ReturnTypeInfererInterface;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
/**
@ -27,9 +26,6 @@ final class AddArrayReturnDocTypeRector extends AbstractRector
*/
private $returnTypeInferer;
/**
* @param ReturnTypeInfererInterface[] $docBlockManipulator
*/
public function __construct(DocBlockManipulator $docBlockManipulator, ReturnTypeInferer $returnTypeInferer)
{
$this->docBlockManipulator = $docBlockManipulator;

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Stmt\Function_;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\Php\ReturnTypeInfo;
use Rector\Php\TypeAnalyzer;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\ReturnTypeResolver\ReturnTypeResolver;
@ -32,10 +33,19 @@ final class ReturnTypeDeclarationRector extends AbstractTypeDeclarationRector
*/
private $returnTypeInferer;
public function __construct(ReturnTypeResolver $returnTypeResolver, ReturnTypeInferer $returnTypeInferer)
{
/**
* @var TypeAnalyzer
*/
private $typeAnalyzer;
public function __construct(
ReturnTypeResolver $returnTypeResolver,
ReturnTypeInferer $returnTypeInferer,
TypeAnalyzer $typeAnalyzer
) {
$this->returnTypeResolver = $returnTypeResolver;
$this->returnTypeInferer = $returnTypeInferer;
$this->typeAnalyzer = $typeAnalyzer;
}
public function getDefinition(): RectorDefinition
@ -128,11 +138,12 @@ CODE_SAMPLE
}
}
} else {
$inferedTypes = $this->returnTypeInferer->inferFunctionLike($node);
dump($inferedTypes);
dump($returnTypeInfo->getTypeNode());
die;
if ($returnTypeInfo->getTypeNode() === null) {
$inferedTypes = $this->returnTypeInferer->inferFunctionLike($node);
if ($inferedTypes) {
$returnTypeInfo = new ReturnTypeInfo($inferedTypes, $this->typeAnalyzer, $inferedTypes);
}
}
$node->returnType = $returnTypeInfo->getTypeNode();
}

View File

@ -9,8 +9,7 @@ use PhpParser\Node\Stmt\Property;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
use Rector\TypeDeclaration\Exception\ConflictingPriorityException;
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
use Rector\TypeDeclaration\ValueObject\IdentifierValueObject;
/**
@ -24,18 +23,14 @@ final class PropertyTypeDeclarationRector extends AbstractRector
private $docBlockManipulator;
/**
* @var PropertyTypeInfererInterface[]
* @var PropertyTypeInferer
*/
private $propertyTypeInferers = [];
private $propertyTypeInferer;
/**
* @param PropertyTypeInfererInterface[] $propertyTypeInferers
*/
public function __construct(DocBlockManipulator $docBlockManipulator, array $propertyTypeInferers = [])
public function __construct(DocBlockManipulator $docBlockManipulator, PropertyTypeInferer $propertyTypeInferer)
{
$this->docBlockManipulator = $docBlockManipulator;
$this->sortAndSetPropertyTypeInferers($propertyTypeInferers);
$this->propertyTypeInferer = $propertyTypeInferer;
}
public function getDefinition(): RectorDefinition
@ -64,12 +59,10 @@ final class PropertyTypeDeclarationRector extends AbstractRector
return null;
}
foreach ($this->propertyTypeInferers as $propertyTypeInferer) {
$types = $propertyTypeInferer->inferProperty($node);
if ($types) {
$this->setNodeVarTypes($node, $types);
return $node;
}
$types = $this->propertyTypeInferer->inferProperty($node);
if ($types) {
$this->setNodeVarTypes($node, $types);
return $node;
}
return null;
@ -84,28 +77,4 @@ final class PropertyTypeDeclarationRector extends AbstractRector
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);
}
}

View File

@ -0,0 +1,37 @@
<?php declare(strict_types=1);
namespace Rector\TypeDeclaration\TypeInferer;
use PhpParser\Node\Param;
use Rector\TypeDeclaration\Contract\TypeInferer\ParamTypeInfererInterface;
final class ParamTypeInferer
{
/**
* @var ParamTypeInfererInterface[]
*/
private $paramTypeInferers = [];
/**
* @param ParamTypeInfererInterface[] $paramTypeInferers
*/
public function __construct(array $paramTypeInferers)
{
$this->paramTypeInferers = $paramTypeInferers;
}
/**
* @return string[]
*/
public function inferParam(Param $param): array
{
foreach ($this->paramTypeInferers as $paramTypeInferers) {
$types = $paramTypeInferers->inferParam($param);
if ($types !== []) {
return $types;
}
}
return [];
}
}

View File

@ -4,6 +4,8 @@ namespace Rector\TypeDeclaration\TypeInferer;
use PhpParser\Node\Stmt\Property;
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
use Rector\TypeDeclaration\Exception\ConflictingPriorityException;
use Rector\TypeDeclaration\ValueObject\IdentifierValueObject;
final class PropertyTypeInferer
{
@ -17,16 +19,16 @@ final class PropertyTypeInferer
*/
public function __construct(array $propertyTypeInferers)
{
$this->propertyTypeInferers = $propertyTypeInferers;
$this->sortAndSetPropertyTypeInferers($propertyTypeInferers);
}
/**
* @property string[]
* @return string[]|IdentifierValueObject[]
*/
public function inferProperty(Property $property): array
{
foreach ($this->propertyTypeInferers as $propertyTypeInferers) {
$types = $propertyTypeInferers->inferFunctionLike($property);
$types = $propertyTypeInferers->inferProperty($property);
if ($types !== []) {
return $types;
}
@ -34,4 +36,28 @@ final class PropertyTypeInferer
return [];
}
/**
* @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);
}
}

View File

@ -5,16 +5,19 @@ namespace Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Trait_;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\TypeDeclaration\Contract\TypeInferer\ReturnTypeInfererInterface;
use Rector\TypeDeclaration\TypeInferer\AbstractTypeInferer;
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
use Rector\TypeDeclaration\ValueObject\IdentifierValueObject;
/**
* Infer return type from $this->variable and get type $this->variable from @var annotation
@ -33,7 +36,7 @@ final class ReturnedPropertyReturnTypeInferer extends AbstractTypeInferer implem
/**
* @param ClassMethod|Closure|Function_ $functionLike
* @return string[]
* @return string[]|IdentifierValueObject[]
*/
public function inferFunctionLike(FunctionLike $functionLike): array
{
@ -56,7 +59,7 @@ final class ReturnedPropertyReturnTypeInferer extends AbstractTypeInferer implem
private function matchSingleStmtReturnPropertyFetch(ClassMethod $classMethod): ?PropertyFetch
{
if (count($classMethod->stmts) !== 1) {
if (count((array) $classMethod->stmts) !== 1) {
return null;
}
@ -84,18 +87,21 @@ final class ReturnedPropertyReturnTypeInferer extends AbstractTypeInferer implem
private function getPropertyByPropertyFetch(PropertyFetch $propertyFetch): ?Property
{
/** @var Class_|Trait_|Interface_|null $class */
$class = $propertyFetch->getAttribute(AttributeKey::CLASS_NODE);
if ($class instanceof ClassLike) {
if ($class === null) {
return null;
}
/** @var string $propertyName */
$propertyName = $this->nameResolver->getName($propertyFetch->name);
foreach ($class->stmts as $stmt) {
if (!$stmt instanceof Property) {
if (! $stmt instanceof Property) {
continue;
}
if (!$this->nameResolver->isName($stmt, $propertyName)) {
if (! $this->nameResolver->isName($stmt, $propertyName)) {
continue;
}