From 32fa86eebd2a3997bb718942ecae48d66a23f2ef Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 14 Feb 2026 13:24:51 +0700 Subject: [PATCH 1/2] Fix combine DowngradeThrowExprRector + DowngradeNullsafeToTernaryOperatorRector --- ...wngradeNullsafeToTernaryOperatorRector.php | 22 +++++++++++-- .../DowngradeThrowNullsafeTest.php | 28 +++++++++++++++++ .../Fixture/fixture.php.inc | 31 +++++++++++++++++++ .../config/configured_rule.php | 11 +++++++ 4 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 tests/Issues/DowngradeThrowNullsafe/DowngradeThrowNullsafeTest.php create mode 100644 tests/Issues/DowngradeThrowNullsafe/Fixture/fixture.php.inc create mode 100644 tests/Issues/DowngradeThrowNullsafe/config/configured_rule.php diff --git a/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php b/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php index 39362d51..8ea64373 100644 --- a/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php +++ b/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php @@ -12,6 +12,7 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\Ternary; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Stmt\Expression; use Rector\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -43,13 +44,19 @@ public function getRuleDefinition(): RuleDefinition */ public function getNodeTypes(): array { - return [MethodCall::class, PropertyFetch::class, NullsafeMethodCall::class, NullsafePropertyFetch::class]; + return [ + Expression::class, + MethodCall::class, + PropertyFetch::class, + NullsafeMethodCall::class, + NullsafePropertyFetch::class, + ]; } /** - * @param MethodCall|NullsafeMethodCall|NullsafePropertyFetch $node + * @param Expression|MethodCall|NullsafeMethodCall|NullsafePropertyFetch $node */ - public function refactor(Node $node): ?Ternary + public function refactor(Node $node): null|Ternary|Expression { static $currentFile = null; @@ -61,6 +68,15 @@ public function refactor(Node $node): ?Ternary $currentFile = $this->file->getFilePath(); } + if ($node instanceof Expression) { + if ($node->expr instanceof Assign && ($node->expr->expr instanceof NullsafeMethodCall || $node->expr->expr instanceof NullsafePropertyFetch)) { + $node->expr = new Assign($node->expr->var, $this->refactor($node->expr->expr)); + return $node; + } + + return null; + } + if ($node instanceof MethodCall || $node instanceof PropertyFetch) { if ($node->var instanceof NullsafeMethodCall || $node->var instanceof NullsafePropertyFetch) { $nullsafeVariable = $this->createNullsafeVariable(); diff --git a/tests/Issues/DowngradeThrowNullsafe/DowngradeThrowNullsafeTest.php b/tests/Issues/DowngradeThrowNullsafe/DowngradeThrowNullsafeTest.php new file mode 100644 index 00000000..e017bb60 --- /dev/null +++ b/tests/Issues/DowngradeThrowNullsafe/DowngradeThrowNullsafeTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/tests/Issues/DowngradeThrowNullsafe/Fixture/fixture.php.inc b/tests/Issues/DowngradeThrowNullsafe/Fixture/fixture.php.inc new file mode 100644 index 00000000..19d384f5 --- /dev/null +++ b/tests/Issues/DowngradeThrowNullsafe/Fixture/fixture.php.inc @@ -0,0 +1,31 @@ +transliterate($s) + ?? throw new Nette\InvalidStateException('Transliterator::transliterate() failed.'); + } +} + +?> +----- +transliterate($s) : null) === null) { + throw new Nette\InvalidStateException('Transliterator::transliterate() failed.'); + } + $s = ($nullsafeVariable2 = \Transliterator::create('Any-Latin; Latin-ASCII')) ? $nullsafeVariable2->transliterate($s) : null; + } +} + +?> diff --git a/tests/Issues/DowngradeThrowNullsafe/config/configured_rule.php b/tests/Issues/DowngradeThrowNullsafe/config/configured_rule.php new file mode 100644 index 00000000..e7bc9cc1 --- /dev/null +++ b/tests/Issues/DowngradeThrowNullsafe/config/configured_rule.php @@ -0,0 +1,11 @@ +rules([DowngradeThrowExprRector::class, DowngradeNullsafeToTernaryOperatorRector::class]); +}; From bbd497c3336195b1ac97d6cad6fbcc89e91a377c Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 14 Feb 2026 13:39:14 +0700 Subject: [PATCH 2/2] fix fixture test --- .../Fixture/multiple_call.php.inc | 4 ++-- .../DowngradeNullsafeToTernaryOperatorRector.php | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/rules-tests/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector/Fixture/multiple_call.php.inc b/rules-tests/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector/Fixture/multiple_call.php.inc index 52d9dac6..949babb7 100644 --- a/rules-tests/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector/Fixture/multiple_call.php.inc +++ b/rules-tests/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector/Fixture/multiple_call.php.inc @@ -21,8 +21,8 @@ class MultipleCall { public function run($object) { - $result = ($nullsafeVariable1 = ($nullsafeVariable3 = $object->multiple($args1)) ? $nullsafeVariable3->call($args2) : null) ? $nullsafeVariable1->otherCall($args3) : null; - $result = ($nullsafeVariable2 = ($nullsafeVariable4 = ($nullsafeVariable5 = $object->multiple($args1)) ? $nullsafeVariable5->call($args2) : null) ? $nullsafeVariable4->otherCall($args3) : null) ? $nullsafeVariable2->anotherCall($args4) : null; + $result = ($nullsafeVariable1 = ($nullsafeVariable2 = $object->multiple($args1)) ? $nullsafeVariable2->call($args2) : null) ? $nullsafeVariable1->otherCall($args3) : null; + $result = ($nullsafeVariable3 = ($nullsafeVariable4 = ($nullsafeVariable5 = $object->multiple($args1)) ? $nullsafeVariable5->call($args2) : null) ? $nullsafeVariable4->otherCall($args3) : null) ? $nullsafeVariable3->anotherCall($args4) : null; } } diff --git a/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php b/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php index 8ea64373..0588851d 100644 --- a/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php +++ b/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php @@ -70,8 +70,11 @@ public function refactor(Node $node): null|Ternary|Expression if ($node instanceof Expression) { if ($node->expr instanceof Assign && ($node->expr->expr instanceof NullsafeMethodCall || $node->expr->expr instanceof NullsafePropertyFetch)) { - $node->expr = new Assign($node->expr->var, $this->refactor($node->expr->expr)); - return $node; + $refactorAssignExpr = $this->refactor($node->expr->expr); + if ($refactorAssignExpr instanceof Ternary) { + $node->expr->expr = $refactorAssignExpr; + return $node; + } } return null;