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
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
use Rector\NetteToSymfony\Route\RouteInfoFactory;
use Rector\NodeContainer\ParsedNodesByType;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\PhpParser\Node\Manipulator\ClassMethodManipulator;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Rector\Util\RectorStrings;
use ReflectionMethod;

Expand Down Expand Up @@ -58,15 +58,15 @@ final class RouterListToControllerAnnotationsRector extends AbstractRector
private $routeInfoFactory;

/**
* @var ClassMethodManipulator
* @var ReturnTypeInferer
*/
private $classMethodManipulator;
private $returnTypeInferer;

public function __construct(
ParsedNodesByType $parsedNodesByType,
ClassMethodManipulator $classMethodManipulator,
DocBlockManipulator $docBlockManipulator,
RouteInfoFactory $routeInfoFactory,
ReturnTypeInferer $returnTypeInferer,
string $routeListClass = 'Nette\Application\Routers\RouteList',
string $routerClass = 'Nette\Application\IRouter',
string $routeAnnotationClass = 'Symfony\Component\Routing\Annotation\Route'
Expand All @@ -77,7 +77,7 @@ public function __construct(
$this->docBlockManipulator = $docBlockManipulator;
$this->routeAnnotationClass = $routeAnnotationClass;
$this->routeInfoFactory = $routeInfoFactory;
$this->classMethodManipulator = $classMethodManipulator;
$this->returnTypeInferer = $returnTypeInferer;
}

public function getDefinition(): RectorDefinition
Expand Down Expand Up @@ -153,12 +153,8 @@ public function refactor(Node $node): ?Node
return null;
}

$nodeReturnTypes = $this->classMethodManipulator->resolveReturnType($node);
if ($nodeReturnTypes === []) {
return null;
}

if (! in_array($this->routeListClass, $nodeReturnTypes, true)) {
$inferedReturnTypes = $this->returnTypeInferer->inferFunctionLike($node);
if (! in_array($this->routeListClass, $inferedReturnTypes, true)) {
return null;
}

Expand All @@ -176,13 +172,7 @@ public function refactor(Node $node): ?Node
continue;
}

$phpDocTagNode = new SymfonyRoutePhpDocTagNode(
$this->routeAnnotationClass,
$routeInfo->getPath(),
null,
$routeInfo->getHttpMethods()
);

$phpDocTagNode = $this->createSymfonyRoutePhpDocTagNode($routeInfo);
$this->docBlockManipulator->addTag($classMethod, $phpDocTagNode);
}

Expand Down Expand Up @@ -338,4 +328,14 @@ private function resolvePathFromClassAndMethodNodes(Class_ $classNode, ClassMeth

return $presenterPart . '/' . $actionPart;
}

private function createSymfonyRoutePhpDocTagNode(RouteInfo $routeInfo): SymfonyRoutePhpDocTagNode
{
return new SymfonyRoutePhpDocTagNode(
$this->routeAnnotationClass,
$routeInfo->getPath(),
null,
$routeInfo->getHttpMethods()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer\ReturnTypeDeclarationReturnTypeInferer;

/**
* @sponsor Thanks https://spaceflow.io/ for sponsoring this rule - visit them on https://github.com/SpaceFlow-app
Expand Down Expand Up @@ -89,16 +90,22 @@ public function refactor(Node $node): ?Node
return null;
}

$inferedTypes = $this->returnTypeInferer->inferFunctionLike($node);
$inferedTypes = $this->returnTypeInferer->inferFunctionLikeWithExcludedInferers(
$node,
[ReturnTypeDeclarationReturnTypeInferer::class]
);
if ($inferedTypes === ['void']) {
return null;
}

if ($inferedTypes !== []) {
$docType = implode('|', $inferedTypes);
$this->docBlockManipulator->addReturnTag($node, $docType);
if ($inferedTypes === []) {
return null;
}

$docType = implode('|', $inferedTypes);

$this->docBlockManipulator->addReturnTag($node, $docType);

return $node;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer\ReturnTypeDeclarationReturnTypeInferer;

final class ReturnTypeDeclarationRector extends AbstractTypeDeclarationRector
{
Expand Down Expand Up @@ -94,7 +95,11 @@ public function refactor(Node $node): ?Node
$hasNewType = $node->returnType->getAttribute(self::HAS_NEW_INHERITED_TYPE, false);
}

$inferedTypes = $this->returnTypeInferer->inferFunctionLike($node);
$inferedTypes = $this->returnTypeInferer->inferFunctionLikeWithExcludedInferers(
$node,
[ReturnTypeDeclarationReturnTypeInferer::class]
);

if ($inferedTypes === []) {
return null;
}
Expand Down
46 changes: 46 additions & 0 deletions packages/TypeDeclaration/src/TypeDeclarationToStringConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php declare(strict_types=1);

namespace Rector\TypeDeclaration;

use PhpParser\Node\FunctionLike;
use PhpParser\Node\NullableType;
use Rector\PhpParser\Node\Resolver\NameResolver;

final class TypeDeclarationToStringConverter
{
/**
* @var NameResolver
*/
private $nameResolver;

public function __construct(NameResolver $nameResolver)
{
$this->nameResolver = $nameResolver;
}

/**
* @return string[]
*/
public function resolveFunctionLikeReturnTypeToString(FunctionLike $functionLike): array
{
if ($functionLike->getReturnType() === null) {
return [];
}

$returnType = $functionLike->getReturnType();

$types = [];

$type = $returnType instanceof NullableType ? $returnType->type : $returnType;
$result = $this->nameResolver->getName($type);
if ($result !== null) {
$types[] = $result;
}

if ($returnType instanceof NullableType) {
$types[] = 'null';
}

return $types;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@

namespace Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;

use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Return_;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
use Rector\TypeDeclaration\TypeDeclarationToStringConverter;
use Rector\TypeDeclaration\TypeInferer\AbstractTypeInferer;

final class GetterTypeDeclarationPropertyTypeInferer extends AbstractTypeInferer implements PropertyTypeInfererInterface
{
/**
* @var TypeDeclarationToStringConverter
*/
private $typeDeclarationToStringConverter;

public function __construct(TypeDeclarationToStringConverter $typeDeclarationToStringConverter)
{
$this->typeDeclarationToStringConverter = $typeDeclarationToStringConverter;
}

/**
* @return string[]
*/
Expand All @@ -33,7 +40,7 @@ public function inferProperty(Property $property): array
continue;
}

$returnTypes = $this->resolveReturnTypeToString($classMethod);
$returnTypes = $this->typeDeclarationToStringConverter->resolveFunctionLikeReturnTypeToString($classMethod);
// let PhpDoc solve that later for more precise type
if ($returnTypes === ['array']) {
return [];
Expand Down Expand Up @@ -74,31 +81,4 @@ private function hasClassMethodOnlyStatementReturnOfPropertyFetch(

return $this->nameResolver->isName($return->expr, $propertyName);
}

/**
* @param Function_|ClassMethod|Closure $functionLike
* @return string[]
*/
private function resolveReturnTypeToString(FunctionLike $functionLike): array
{
if ($functionLike->getReturnType() === null) {
return [];
}

$returnType = $functionLike->getReturnType();

$types = [];

$type = $returnType instanceof NullableType ? $returnType->type : $returnType;
$result = $this->nameResolver->getName($type);
if ($result !== null) {
$types[] = $result;
}

if ($returnType instanceof NullableType) {
$types[] = 'null';
}

return $types;
}
}
26 changes: 24 additions & 2 deletions packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,30 @@ public function __construct(array $returnTypeInferers)
*/
public function inferFunctionLike(FunctionLike $functionLike): array
{
foreach ($this->returnTypeInferers as $returnTypeInferers) {
$types = $returnTypeInferers->inferFunctionLike($functionLike);
foreach ($this->returnTypeInferers as $returnTypeInferer) {
$types = $returnTypeInferer->inferFunctionLike($functionLike);
if ($types !== []) {
return $types;
}
}

return [];
}

/**
* @param string[] $excludedInferers
* @return string[]
*/
public function inferFunctionLikeWithExcludedInferers(FunctionLike $functionLike, array $excludedInferers): array
{
foreach ($this->returnTypeInferers as $returnTypeInferer) {
foreach ($excludedInferers as $excludedInferer) {
if (is_a($returnTypeInferer, $excludedInferer, true)) {
continue 2;
}
}

$types = $returnTypeInferer->inferFunctionLike($functionLike);
if ($types !== []) {
return $types;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types=1);

namespace Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;

use PhpParser\Node\FunctionLike;
use Rector\TypeDeclaration\Contract\TypeInferer\ReturnTypeInfererInterface;
use Rector\TypeDeclaration\TypeDeclarationToStringConverter;
use Rector\TypeDeclaration\TypeInferer\AbstractTypeInferer;

final class ReturnTypeDeclarationReturnTypeInferer extends AbstractTypeInferer implements ReturnTypeInfererInterface
{
/**
* @var TypeDeclarationToStringConverter
*/
private $typeDeclarationToStringConverter;

public function __construct(TypeDeclarationToStringConverter $typeDeclarationToStringConverter)
{
$this->typeDeclarationToStringConverter = $typeDeclarationToStringConverter;
}

/**
* @return string[]
*/
public function inferFunctionLike(FunctionLike $functionLike): array
{
if ($functionLike->getReturnType() === null) {
return [];
}

// resolve later with more precise type, e.g. Type[]
if ($this->nameResolver->isNames($functionLike->getReturnType(), ['array', 'iterable'])) {
return [];
}

return $this->typeDeclarationToStringConverter->resolveFunctionLikeReturnTypeToString($functionLike);
}

public function getPriority(): int
{
return 2000;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function test(): void
__DIR__ . '/Fixture/simple_array.php.inc',
__DIR__ . '/Fixture/add_without_return_type_declaration.php.inc',
__DIR__ . '/Fixture/fix_incorrect_array.php.inc',
// skip
// skip
__DIR__ . '/Fixture/skip_constructor.php.inc',
__DIR__ . '/Fixture/skip_array_after_array_type.php.inc',
__DIR__ . '/Fixture/skip_shorten_class_name.php.inc',
Expand Down
Loading