rector/rules/Defluent/ValueObject/AbstractRootExpr.php
2021-07-05 23:06:30 +00:00

80 lines
2.9 KiB
PHP

<?php
declare (strict_types=1);
namespace Rector\Defluent\ValueObject;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Defluent\Contract\ValueObject\FirstCallFactoryAwareInterface;
use Rector\Defluent\Contract\ValueObject\RootExprAwareInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
abstract class AbstractRootExpr implements \Rector\Defluent\Contract\ValueObject\RootExprAwareInterface, \Rector\Defluent\Contract\ValueObject\FirstCallFactoryAwareInterface
{
/**
* @var bool
*/
protected $isFirstCallFactory = \false;
/**
* @var \PhpParser\Node\Expr
*/
protected $rootExpr;
/**
* @var \PhpParser\Node\Expr
*/
protected $assignExpr;
public function createFirstAssign() : \PhpParser\Node\Expr\Assign
{
if ($this->isFirstCallFactory && $this->getFirstAssign() !== null) {
return $this->createFactoryAssign();
}
return $this->createAssign($this->assignExpr, $this->rootExpr);
}
/**
* @param \PhpParser\Node\Expr $assignVar
* @param \PhpParser\Node\Expr $assignExpr
*/
protected function createAssign($assignVar, $assignExpr) : \PhpParser\Node\Expr\Assign
{
if ($assignVar === $assignExpr) {
throw new \Rector\Core\Exception\ShouldNotHappenException();
}
return new \PhpParser\Node\Expr\Assign($assignVar, $assignExpr);
}
protected function getFirstAssign() : ?\PhpParser\Node\Expr\Assign
{
$currentStmt = $this->assignExpr->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::CURRENT_STATEMENT);
if (!$currentStmt instanceof \PhpParser\Node\Stmt\Expression) {
return null;
}
$currentExpr = $currentStmt->expr;
if ($currentExpr instanceof \PhpParser\Node\Expr\Assign) {
return $currentExpr;
}
return null;
}
private function createFactoryAssign() : \PhpParser\Node\Expr\Assign
{
/** @var Assign $firstAssign */
$firstAssign = $this->getFirstAssign();
$currentMethodCall = $firstAssign->expr;
if (!$currentMethodCall instanceof \PhpParser\Node\Expr\MethodCall) {
throw new \Rector\Core\Exception\ShouldNotHappenException();
}
$currentMethodCall = $this->resolveLastMethodCall($currentMethodCall);
// ensure var and expr are different
$assignVar = $firstAssign->var;
$assignExpr = $currentMethodCall;
return $this->createAssign($assignVar, $assignExpr);
}
private function resolveLastMethodCall(\PhpParser\Node\Expr\MethodCall $currentMethodCall) : \PhpParser\Node\Expr\MethodCall
{
while ($currentMethodCall->var instanceof \PhpParser\Node\Expr\MethodCall) {
$currentMethodCall = $currentMethodCall->var;
}
return $currentMethodCall;
}
}