Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Php80] Handle crash leaveNode() returned invalid value of type integer on TokenGetAllToObjectRector #3644

Merged
merged 13 commits into from
Apr 21, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Rector\Tests\Php80\Rector\FuncCall\TokenGetAllToObjectRector\Fixture;

final class NotArrayFirst2
{
public function run()
{
$code = '<?php echo 1;';

$tokens = token_get_all($code);
$this->tokens = [];
foreach ($tokens as $token) {
if (!is_array($token) || ($token[0] !== T_WHITESPACE && $token[0] !== T_INLINE_HTML)) {
$this->tokens = $token;
}
}
}
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\FuncCall\TokenGetAllToObjectRector\Fixture;

final class NotArrayFirst2
{
public function run()
{
$code = '<?php echo 1;';

$tokens = \PhpToken::tokenize($code);
$this->tokens = [];
foreach ($tokens as $token) {
if (!$token->is(T_WHITESPACE) && !$token->is(T_INLINE_HTML)) {
$this->tokens = $token->text;
}
}
}
}

?>
79 changes: 54 additions & 25 deletions rules/Php80/NodeManipulator/TokenManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
Expand Down Expand Up @@ -135,11 +137,12 @@ public function refactorTokenIsKind(array $nodes, Variable $singleTokenVariable)
{
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($nodes, function (Node $node) use (
$singleTokenVariable
): ?MethodCall {
if (! $node instanceof Identical) {
): null|MethodCall|BooleanNot {
if (! $this->isIdenticalOrNotIdentical($node)) {
return null;
}

/** @var Identical|NotIdentical $node */
$arrayDimFetchAndConstFetch = $this->matchArrayDimFetchAndConstFetch($node);
if (! $arrayDimFetchAndConstFetch instanceof ArrayDimFetchAndConstFetch) {
return null;
Expand All @@ -156,19 +159,21 @@ public function refactorTokenIsKind(array $nodes, Variable $singleTokenVariable)
return null;
}

$constName = $this->nodeNameResolver->getName($constFetch);
if ($constName === null) {
return null;
}

$constName = (string) $this->nodeNameResolver->getName($constFetch);
if (! StringUtils::isMatch($constName, '#^T_#')) {
return null;
}

return $this->createIsTConstTypeMethodCall(
$isTConstTypeMethodCall = $this->createIsTConstTypeMethodCall(
$arrayDimFetch,
$arrayDimFetchAndConstFetch->getConstFetch()
);

if ($node instanceof Identical) {
return $isTConstTypeMethodCall;
}

return new BooleanNot($isTConstTypeMethodCall);
});
}

Expand Down Expand Up @@ -212,11 +217,27 @@ public function removeIsArray(array $nodes, Variable $singleTokenVariable): void
return $node;
}

if (! $parentNode instanceof BooleanNot) {
$this->nodesToRemoveCollector->addNodeToRemove($nodeToRemove);
return $node;
}

$parentOfParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
if ($parentOfParentNode instanceof BinaryOp) {
$this->nodesToRemoveCollector->addNodeToRemove($parentNode);
return $node;
}

$this->nodesToRemoveCollector->addNodeToRemove($nodeToRemove);
return $node;
});
}

private function isIdenticalOrNotIdentical(Node $node): bool
{
return $node instanceof Identical || $node instanceof NotIdentical;
}

private function replaceTernary(Ternary $ternary): void
{
$currentStmt = $this->betterNodeFinder->resolveCurrentStatement($ternary);
Expand Down Expand Up @@ -298,7 +319,7 @@ private function isArrayDimFetchWithDimIntegerValue(ArrayDimFetch $arrayDimFetch
return $this->valueResolver->isValue($arrayDimFetch->dim, $value);
}

private function matchArrayDimFetchAndConstFetch(Identical $identical): ?ArrayDimFetchAndConstFetch
private function matchArrayDimFetchAndConstFetch(Identical|NotIdentical $identical): ?ArrayDimFetchAndConstFetch
{
if ($identical->left instanceof ArrayDimFetch && $identical->right instanceof ConstFetch) {
return new ArrayDimFetchAndConstFetch($identical->left, $identical->right);
Expand Down Expand Up @@ -329,12 +350,14 @@ private function shouldSkipNodeRemovalForPartOfIf(FuncCall $funcCall): bool
return true;
}

if ($parentNode instanceof BooleanNot) {
$parentParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
if ($parentParentNode instanceof If_) {
$parentParentNode->cond = $parentNode;
return true;
}
if (! $parentNode instanceof BooleanNot) {
return false;
}

$parentParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
if ($parentParentNode instanceof If_) {
$parentParentNode->cond = $parentNode;
return true;
}

return false;
Expand All @@ -343,18 +366,24 @@ private function shouldSkipNodeRemovalForPartOfIf(FuncCall $funcCall): bool
private function matchParentNodeInCaseOfIdenticalTrue(FuncCall $funcCall): Identical | FuncCall
{
$parentNode = $funcCall->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof Identical) {
$isRightValueTrue = $this->valueResolver->isValue($parentNode->right, true);
if ($parentNode->left === $funcCall && $isRightValueTrue) {
return $parentNode;
}
if (! $parentNode instanceof Identical) {
return $funcCall;
}

$isLeftValueTrue = $this->valueResolver->isValue($parentNode->left, true);
if ($parentNode->right === $funcCall && $isLeftValueTrue) {
return $parentNode;
}
$isRightValueTrue = $this->valueResolver->isValue($parentNode->right, true);
if ($parentNode->left === $funcCall && $isRightValueTrue) {
return $parentNode;
}

$isLeftValueTrue = $this->valueResolver->isValue($parentNode->left, true);
if ($parentNode->right !== $funcCall) {
return $funcCall;
}

if (! $isLeftValueTrue) {
return $funcCall;
}

return $funcCall;
return $parentNode;
}
}