From 0cd6f1fb242355d014349a6c6ad43e0d066bb1f3 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 29 Mar 2025 20:25:00 +0700 Subject: [PATCH 1/2] [CodeQuality] Handle crash on multiple assert cause undefined variable on AddInstanceofAssertForNullableInstanceRector --- .../Fixture/multiple_assert.php.inc | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector/Fixture/multiple_assert.php.inc diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector/Fixture/multiple_assert.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector/Fixture/multiple_assert.php.inc new file mode 100644 index 00000000..ae339bc6 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector/Fixture/multiple_assert.php.inc @@ -0,0 +1,91 @@ +getSomeObject(); + $value = $someObject->getSomeMethod(); + + $this->assertSame(123, $value); + + $someObject2 = $this->getSomeObject2(); + $value2 = $someObject2->getSomeMethod(); + + $this->assertSame(123, $value2); + } + + private function getSomeObject(): ?SomeClassUsedInTests + { + if (mt_rand(0, 1)) { + return new SomeClassUsedInTests(); + } + + return null; + } + + private function getSomeObject2(): ?SomeClassUsedInTests + { + if (mt_rand(0, 1)) { + return new SomeClassUsedInTests(); + } + + return null; + } +} + +?> +----- +getSomeObject(); + $this->assertInstanceof(\Rector\PHPUnit\Tests\CodeQuality\Rector\ClassMethod\AddInstanceofAssertForNullableInstanceRector\Source\SomeClassUsedInTests::class, $someObject); + $value = $someObject->getSomeMethod(); + + $this->assertSame(123, $value); + + $someObject2 = $this->getSomeObject2(); + $this->assertInstanceof(\Rector\PHPUnit\Tests\CodeQuality\Rector\ClassMethod\AddInstanceofAssertForNullableInstanceRector\Source\SomeClassUsedInTests::class, $someObject2); + $value2 = $someObject2->getSomeMethod(); + + $this->assertSame(123, $value2); + } + + private function getSomeObject(): ?SomeClassUsedInTests + { + if (mt_rand(0, 1)) { + return new SomeClassUsedInTests(); + } + + return null; + } + + private function getSomeObject2(): ?SomeClassUsedInTests + { + if (mt_rand(0, 1)) { + return new SomeClassUsedInTests(); + } + + return null; + } +} + +?> From 67e6bf01c813c8e3b389b32ae3e8d742e535f98c Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 29 Mar 2025 20:38:41 +0700 Subject: [PATCH 2/2] Fix --- .../AddInstanceofAssertForNullableInstanceRector.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rules/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector.php b/rules/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector.php index f4c0bb13..812a7166 100644 --- a/rules/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector.php +++ b/rules/CodeQuality/Rector/ClassMethod/AddInstanceofAssertForNullableInstanceRector.php @@ -118,6 +118,7 @@ public function refactor(Node $node): ?Node $hasChanged = false; $variableNameToTypeCollection = $this->nullableObjectAssignCollector->collect($node); + $next = 0; foreach ($node->stmts as $key => $stmt) { // has callable on nullable variable of already collected name? $matchedNullableVariableNameToType = $this->matchedNullableVariableNameToType( @@ -130,13 +131,15 @@ public function refactor(Node $node): ?Node // adding type here + popping the variable name out $assertInstanceofExpression = $this->createAssertInstanceof($matchedNullableVariableNameToType); - array_splice($node->stmts, $key, 0, [$assertInstanceofExpression]); + array_splice($node->stmts, $key + $next, 0, [$assertInstanceofExpression]); // remove variable name from nullable ones $hasChanged = true; // from now on, the variable is not nullable, remove to avoid double asserts $variableNameToTypeCollection->remove($matchedNullableVariableNameToType); + + ++$next; } if (! $hasChanged) {