rector/vendor/rector/rector-nette-to-symfony/src/NodeAnalyzer/ClassMethodRenderAnalyzer.php
Tomas Votruba c99e19b804 Updated Rector to commit 4f619aae72
4f619aae72 NodeRepository usage cleanup (#287)
2021-06-25 06:35:08 +00:00

142 lines
5.8 KiB
PHP

<?php
declare (strict_types=1);
namespace Rector\NetteToSymfony\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Nette\NodeAnalyzer\ReturnAnalyzer;
use Rector\Nette\NodeAnalyzer\ThisTemplatePropertyFetchAnalyzer;
use Rector\NetteToSymfony\ValueObject\ClassMethodRender;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeNestingScope\ScopeNestingComparator;
use Rector\NodeNestingScope\ValueObject\ControlStructure;
use RectorPrefix20210625\Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class ClassMethodRenderAnalyzer
{
/**
* @var Expr[]
*/
private $templateVariables = [];
/**
* @var Node[]
*/
private $nodesToRemove = [];
/**
* @var array<string, Assign[]>
*/
private $conditionalAssigns = [];
/**
* @var Expr[]
*/
private $templateFileExprs = [];
/**
* @var Return_|null
*/
private $lastReturn;
/**
* @var \Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser
*/
private $simpleCallableNodeTraverser;
/**
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var \Rector\NodeNestingScope\ScopeNestingComparator
*/
private $scopeNestingComparator;
/**
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
*/
private $betterNodeFinder;
/**
* @var \Rector\Nette\NodeAnalyzer\ThisTemplatePropertyFetchAnalyzer
*/
private $thisTemplatePropertyFetchAnalyzer;
/**
* @var \Rector\Nette\NodeAnalyzer\ReturnAnalyzer
*/
private $returnAnalyzer;
public function __construct(\RectorPrefix20210625\Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser $simpleCallableNodeTraverser, \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver, \Rector\NodeNestingScope\ScopeNestingComparator $scopeNestingComparator, \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\Nette\NodeAnalyzer\ThisTemplatePropertyFetchAnalyzer $thisTemplatePropertyFetchAnalyzer, \Rector\Nette\NodeAnalyzer\ReturnAnalyzer $returnAnalyzer)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
$this->scopeNestingComparator = $scopeNestingComparator;
$this->betterNodeFinder = $betterNodeFinder;
$this->thisTemplatePropertyFetchAnalyzer = $thisTemplatePropertyFetchAnalyzer;
$this->returnAnalyzer = $returnAnalyzer;
}
public function collectFromClassMethod(\PhpParser\Node\Stmt\ClassMethod $classMethod) : \Rector\NetteToSymfony\ValueObject\ClassMethodRender
{
$this->templateFileExprs = [];
$this->templateVariables = [];
$this->nodesToRemove = [];
$this->conditionalAssigns = [];
$this->lastReturn = $this->returnAnalyzer->findLastClassMethodReturn($classMethod);
$this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $classMethod->stmts, function (\PhpParser\Node $node) : void {
if ($node instanceof \PhpParser\Node\Expr\MethodCall) {
$this->collectTemplateFileExpr($node);
}
if ($node instanceof \PhpParser\Node\Expr\Assign) {
$this->collectVariableFromAssign($node);
}
});
return new \Rector\NetteToSymfony\ValueObject\ClassMethodRender($this->templateFileExprs, $this->templateVariables, $this->nodesToRemove, $this->conditionalAssigns);
}
private function collectTemplateFileExpr(\PhpParser\Node\Expr\MethodCall $methodCall) : void
{
if (!$this->nodeNameResolver->isNames($methodCall->name, ['render', 'setFile'])) {
return;
}
$this->nodesToRemove[] = $methodCall;
if (!isset($methodCall->args[0])) {
return;
}
$this->templateFileExprs[] = $methodCall->args[0]->value;
}
private function collectVariableFromAssign(\PhpParser\Node\Expr\Assign $assign) : void
{
// $this->template = x
if ($assign->var instanceof \PhpParser\Node\Expr\PropertyFetch) {
$propertyFetch = $assign->var;
if (!$this->thisTemplatePropertyFetchAnalyzer->isTemplatePropertyFetch($propertyFetch->var)) {
return;
}
$variableName = $this->nodeNameResolver->getName($propertyFetch);
$foundParent = $this->betterNodeFinder->findParentTypes($propertyFetch->var, \Rector\NodeNestingScope\ValueObject\ControlStructure::CONDITIONAL_NODE_SCOPE_TYPES + [\PhpParser\Node\FunctionLike::class]);
if ($foundParent && $this->scopeNestingComparator->isInBothIfElseBranch($foundParent, $propertyFetch)) {
$this->conditionalAssigns[$variableName][] = $assign;
return;
}
if ($foundParent instanceof \PhpParser\Node\Stmt\If_) {
return;
}
if ($foundParent instanceof \PhpParser\Node\Stmt\Else_) {
return;
}
// there is a return before this assign, to do not remove it and keep ti
if (!$this->returnAnalyzer->isBeforeLastReturn($assign, $this->lastReturn)) {
return;
}
$this->templateVariables[$variableName] = $assign->expr;
$this->nodesToRemove[] = $assign;
return;
}
// $x = $this->template
if (!$this->thisTemplatePropertyFetchAnalyzer->isTemplatePropertyFetch($assign->expr)) {
return;
}
$this->nodesToRemove[] = $assign;
}
}