Skip to content

Commit

Permalink
[TypeDeclaration] Fix returned yield nodes in nested function [closes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Dec 4, 2019
1 parent 4fa3e84 commit 469090e
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;

use PhpParser\Node;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\Class_;
Expand Down Expand Up @@ -75,8 +74,8 @@ private function collectReturns(FunctionLike $functionLike): array
$this->callableNodeTraverser->traverseNodesWithCallable((array) $functionLike->getStmts(), function (
Node $node
) use (&$returns): ?int {
if ($node instanceof Function_ || $node instanceof Closure || $node instanceof ArrowFunction) {
// skip Return_ nodes in nested functions
// skip Return_ nodes in nested functions
if ($node instanceof FunctionLike) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,31 @@
namespace Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;

use Iterator;
use PhpParser\Node;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\NodeTraverser;
use PHPStan\Type\ArrayType;
use PHPStan\Type\IterableType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use Rector\Php\PhpVersionProvider;
use Rector\PhpParser\Node\BetterNodeFinder;
use Rector\TypeDeclaration\Contract\TypeInferer\ReturnTypeInfererInterface;
use Rector\TypeDeclaration\TypeInferer\AbstractTypeInferer;

final class YieldNodesReturnTypeInferer extends AbstractTypeInferer implements ReturnTypeInfererInterface
{
/**
* @var BetterNodeFinder
*/
private $betterNodeFinder;

/**
* @var PhpVersionProvider
*/
private $phpVersionProvider;

public function __construct(BetterNodeFinder $betterNodeFinder, PhpVersionProvider $phpVersionProvider)
public function __construct(PhpVersionProvider $phpVersionProvider)
{
$this->betterNodeFinder = $betterNodeFinder;
$this->phpVersionProvider = $phpVersionProvider;
}

Expand All @@ -43,8 +38,7 @@ public function __construct(BetterNodeFinder $betterNodeFinder, PhpVersionProvid
*/
public function inferFunctionLike(FunctionLike $functionLike): Type
{
/** @var Yield_[] $yieldNodes */
$yieldNodes = $this->betterNodeFinder->findInstanceOf((array) $functionLike->stmts, Yield_::class);
$yieldNodes = $this->findCurrentScopeYieldNodes($functionLike);

$types = [];
if (count($yieldNodes) > 0) {
Expand Down Expand Up @@ -72,4 +66,31 @@ public function getPriority(): int
{
return 1200;
}

/**
* @return Yield_[]
*/
private function findCurrentScopeYieldNodes(FunctionLike $functionLike): array
{
$yieldNodes = [];

$this->callableNodeTraverser->traverseNodesWithCallable((array) $functionLike->getStmts(), function (
Node $node
) use (
&$yieldNodes
): ?int {
// skip nested scope
if ($node instanceof FunctionLike) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}

if (! $node instanceof Yield_) {
return null;
}

$yieldNodes[] = $node;
return null;
});
return $yieldNodes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeDeclarationRector\Fixture;

class SkipAnonymousFunctionNestedType
{
private function collectionCallback(): callable
{
return function (int $offset, int $itemCountPerPage): iterable {
$stmt = $this->connection->executeQuery('SELECT * FROM *');

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield EventsEntity::forCollection();
}
};
}

private function again(): callable
{
return function (int $offset, int $itemCountPerPage): iterable {
return 25;
};
}
}

0 comments on commit 469090e

Please sign in to comment.