From c203b601c98f4a93236c82179a2e9a5a519b48ae Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 21 Apr 2023 22:23:38 +0700 Subject: [PATCH] [Php80] Handle crash leaveNode() returned invalid value of type integer on TokenGetAllToObjectRector (#3644) Co-authored-by: GitHub Action --- .../Fixture/not_array_first2.php.inc | 43 ++++++++++ .../NodeManipulator/TokenManipulator.php | 79 +++++++++++++------ 2 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 rules-tests/Php80/Rector/FuncCall/TokenGetAllToObjectRector/Fixture/not_array_first2.php.inc diff --git a/rules-tests/Php80/Rector/FuncCall/TokenGetAllToObjectRector/Fixture/not_array_first2.php.inc b/rules-tests/Php80/Rector/FuncCall/TokenGetAllToObjectRector/Fixture/not_array_first2.php.inc new file mode 100644 index 00000000000..ad226339448 --- /dev/null +++ b/rules-tests/Php80/Rector/FuncCall/TokenGetAllToObjectRector/Fixture/not_array_first2.php.inc @@ -0,0 +1,43 @@ +tokens = []; + foreach ($tokens as $token) { + if (!is_array($token) || ($token[0] !== T_WHITESPACE && $token[0] !== T_INLINE_HTML)) { + $this->tokens = $token; + } + } + } +} + +?> +----- +tokens = []; + foreach ($tokens as $token) { + if (!$token->is(T_WHITESPACE) && !$token->is(T_INLINE_HTML)) { + $this->tokens = $token->text; + } + } + } +} + +?> diff --git a/rules/Php80/NodeManipulator/TokenManipulator.php b/rules/Php80/NodeManipulator/TokenManipulator.php index d5a9c3cfe56..07d764af402 100644 --- a/rules/Php80/NodeManipulator/TokenManipulator.php +++ b/rules/Php80/NodeManipulator/TokenManipulator.php @@ -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; @@ -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; @@ -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); }); } @@ -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); @@ -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); @@ -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; @@ -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; } }