[Defluent] Handle casted return value on FluentChainMethodCallToNormalMethodCallRector (#643)

* [Defluent] Handle casted return value on FluentChainMethodCallToNormalMethodCallRector

* Fixed 🎉

* eol

* [ci-review] Rector Rectify

* clean up

* move to different ifixture test to avoid CI error

* try different class

* move back

* Fixed 🎉

* phpstan

* clean up

* final touch: handle multi casted

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Abdul Malik Ikhsan 2021-08-11 13:26:39 +07:00 committed by GitHub
parent e6b5c4ec7d
commit 3a76077bfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 5 deletions

View File

@ -0,0 +1,32 @@
<?php
namespace Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\DifferentReturnValues;
class CastedReturnValue
{
public function getCastedValue(DifferentReturnValues $differentReturnValues)
{
return (int) $differentReturnValues->someFunction()->otherFunction();
}
}
?>
-----
<?php
namespace Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\DifferentReturnValues;
class CastedReturnValue
{
public function getCastedValue(DifferentReturnValues $differentReturnValues)
{
$differentReturnValues->someFunction();
return (int) $differentReturnValues->otherFunction();
}
}
?>

View File

@ -0,0 +1,32 @@
<?php
namespace Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\DifferentReturnValues;
class MultiCastedReturnValue
{
public function getCastedValue(DifferentReturnValues $differentReturnValues)
{
return (int) (int) (int) $differentReturnValues->someFunction()->otherFunction();
}
}
?>
-----
<?php
namespace Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Tests\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\DifferentReturnValues;
class MultiCastedReturnValue
{
public function getCastedValue(DifferentReturnValues $differentReturnValues)
{
$differentReturnValues->someFunction();
return (int) $differentReturnValues->otherFunction();
}
}
?>

View File

@ -12,6 +12,7 @@ use Rector\Defluent\NodeFactory\NonFluentChainMethodCallFactory;
use Rector\Defluent\Skipper\FluentMethodCallSkipper;
use Rector\Defluent\ValueObject\AssignAndRootExpr;
use Rector\Defluent\ValueObject\AssignAndRootExprAndNodesToAdd;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class AssignAndRootExprAndNodesToAddMatcher
{
@ -44,10 +45,12 @@ final class AssignAndRootExprAndNodesToAddMatcher
return null;
}
$parentMethodCall = $methodCall->getAttribute(AttributeKey::PARENT_NODE);
$nodesToAdd = $this->nonFluentChainMethodCallFactory->createFromAssignObjectAndMethodCalls(
$assignAndRootExpr,
$chainMethodCalls,
$kind
$kind,
$parentMethodCall
);
return new AssignAndRootExprAndNodesToAdd($assignAndRootExpr, $nodesToAdd);

View File

@ -4,7 +4,9 @@ declare(strict_types=1);
namespace Rector\Defluent\NodeFactory;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
@ -57,12 +59,13 @@ final class NonFluentChainMethodCallFactory
/**
* @param MethodCall[] $chainMethodCalls
* @return Assign[]|MethodCall[]|Return_[]
* @return Assign[]|Cast[]|MethodCall[]|Return_[]
*/
public function createFromAssignObjectAndMethodCalls(
AssignAndRootExpr $assignAndRootExpr,
array $chainMethodCalls,
string $kind
string $kind,
?Node $node = null
): array {
$nodesToAdd = [];
@ -83,6 +86,12 @@ final class NonFluentChainMethodCallFactory
$nodesToAdd[] = $assignAndRootExpr->getReturnSilentVariable();
}
if ($node instanceof Cast) {
$lastNodeToAdd = $nodesToAdd[array_key_last($nodesToAdd)];
$cast = $node::class;
$nodesToAdd[array_key_last($nodesToAdd)] = new $cast($lastNodeToAdd);
}
return $nodesToAdd;
}

View File

@ -6,6 +6,7 @@ namespace Rector\Defluent\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Rector\AbstractRector;
@ -85,12 +86,41 @@ CODE_SAMPLE
return null;
}
$this->fluentNodeRemover->removeCurrentNode($node);
$this->addNodesAfterNode($assignAndRootExprAndNodesToAdd->getNodesToAdd(), $node);
$currentStatement = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
$nodesToAdd = $assignAndRootExprAndNodesToAdd->getNodesToAdd();
if ($currentStatement instanceof Return_) {
$lastNodeToAdd = end($nodesToAdd);
if (! $lastNodeToAdd) {
return null;
}
if (! $lastNodeToAdd instanceof Return_) {
$nodesToAdd[array_key_last($nodesToAdd)] = new Return_($lastNodeToAdd);
}
}
$this->removeCurrentNode($node);
$this->addNodesAfterNode($nodesToAdd, $node);
return null;
}
private function removeCurrentNode(MethodCall $methodCall): void
{
$parent = $methodCall->getAttribute(AttributeKey::PARENT_NODE);
while ($parent instanceof Cast) {
$parent = $parent->getAttribute(AttributeKey::PARENT_NODE);
if (! $parent instanceof Cast) {
$this->fluentNodeRemover->removeCurrentNode($parent);
return;
}
}
$this->fluentNodeRemover->removeCurrentNode($methodCall);
}
/**
* Is handled by:
* @see DefluentReturnMethodCallRector