2021-03-03 09:49:57 +01:00
|
|
|
<?php
|
|
|
|
|
2021-05-09 20:15:43 +00:00
|
|
|
declare (strict_types=1);
|
2021-03-03 09:49:57 +01:00
|
|
|
namespace Rector\Php72\NodeFactory;
|
|
|
|
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Expr\Assign;
|
|
|
|
use PhpParser\Node\Expr\Closure;
|
|
|
|
use PhpParser\Node\Expr\ClosureUse;
|
|
|
|
use PhpParser\Node\Expr\Variable;
|
|
|
|
use PhpParser\Node\Identifier;
|
|
|
|
use PhpParser\Node\Name;
|
|
|
|
use PhpParser\Node\NullableType;
|
|
|
|
use PhpParser\Node\Param;
|
|
|
|
use PhpParser\Node\Stmt;
|
|
|
|
use PhpParser\Node\UnionType;
|
|
|
|
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
|
|
|
use Rector\NodeNameResolver\NodeNameResolver;
|
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
|
|
|
final class AnonymousFunctionFactory
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var NodeNameResolver
|
|
|
|
*/
|
|
|
|
private $nodeNameResolver;
|
|
|
|
/**
|
|
|
|
* @var BetterNodeFinder
|
|
|
|
*/
|
|
|
|
private $betterNodeFinder;
|
2021-05-10 22:23:08 +00:00
|
|
|
public function __construct(\Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver, \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder)
|
2021-03-03 09:49:57 +01:00
|
|
|
{
|
|
|
|
$this->nodeNameResolver = $nodeNameResolver;
|
|
|
|
$this->betterNodeFinder = $betterNodeFinder;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @param Param[] $params
|
|
|
|
* @param Stmt[] $stmts
|
2021-03-03 10:40:03 +01:00
|
|
|
* @param Identifier|Name|NullableType|UnionType|null $returnTypeNode
|
2021-03-03 09:49:57 +01:00
|
|
|
*/
|
2021-05-10 22:23:08 +00:00
|
|
|
public function create(array $params, array $stmts, ?\PhpParser\Node $returnTypeNode) : \PhpParser\Node\Expr\Closure
|
2021-03-03 09:49:57 +01:00
|
|
|
{
|
|
|
|
$useVariables = $this->createUseVariablesFromParams($stmts, $params);
|
2021-05-10 22:23:08 +00:00
|
|
|
$anonymousFunctionNode = new \PhpParser\Node\Expr\Closure();
|
2021-03-03 09:49:57 +01:00
|
|
|
$anonymousFunctionNode->params = $params;
|
|
|
|
foreach ($useVariables as $useVariable) {
|
2021-05-10 22:23:08 +00:00
|
|
|
$anonymousFunctionNode->uses[] = new \PhpParser\Node\Expr\ClosureUse($useVariable);
|
2021-03-03 09:49:57 +01:00
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
if ($returnTypeNode instanceof \PhpParser\Node) {
|
2021-03-03 10:40:03 +01:00
|
|
|
$anonymousFunctionNode->returnType = $returnTypeNode;
|
2021-03-03 09:49:57 +01:00
|
|
|
}
|
|
|
|
$anonymousFunctionNode->stmts = $stmts;
|
|
|
|
return $anonymousFunctionNode;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @param Node[] $nodes
|
|
|
|
* @param Param[] $paramNodes
|
|
|
|
* @return Variable[]
|
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
private function createUseVariablesFromParams(array $nodes, array $paramNodes) : array
|
2021-03-03 09:49:57 +01:00
|
|
|
{
|
|
|
|
$paramNames = [];
|
|
|
|
foreach ($paramNodes as $paramNode) {
|
|
|
|
$paramNames[] = $this->nodeNameResolver->getName($paramNode);
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
$variableNodes = $this->betterNodeFinder->findInstanceOf($nodes, \PhpParser\Node\Expr\Variable::class);
|
2021-03-03 09:49:57 +01:00
|
|
|
/** @var Variable[] $filteredVariables */
|
|
|
|
$filteredVariables = [];
|
|
|
|
$alreadyAssignedVariables = [];
|
|
|
|
foreach ($variableNodes as $variableNode) {
|
|
|
|
// "$this" is allowed
|
2021-05-09 20:15:43 +00:00
|
|
|
if ($this->nodeNameResolver->isName($variableNode, 'this')) {
|
2021-03-03 09:49:57 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$variableName = $this->nodeNameResolver->getName($variableNode);
|
|
|
|
if ($variableName === null) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
if (\in_array($variableName, $paramNames, \true)) {
|
2021-03-03 09:49:57 +01:00
|
|
|
continue;
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
$parentNode = $variableNode->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE);
|
|
|
|
if ($parentNode instanceof \PhpParser\Node\Expr\Assign) {
|
2021-03-03 09:49:57 +01:00
|
|
|
$alreadyAssignedVariables[] = $variableName;
|
|
|
|
}
|
|
|
|
if ($this->nodeNameResolver->isNames($variableNode, $alreadyAssignedVariables)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$filteredVariables[$variableName] = $variableNode;
|
|
|
|
}
|
|
|
|
return $filteredVariables;
|
|
|
|
}
|
|
|
|
}
|