Skip to content

Commit ed60a22

Browse files
authored
[Alternative][DeadCode][Php80] Handle crash on mix ClassPropertyAssignToConstructorPromotionRector+RemoveParentDelegatingConstructorRector (#7799)
* [DeadCode][Php80] Handle crash on mix ClassPropertyAssignToConstructorPromotionRector+RemoveParentDelegatingConstructorRector * fix finalize class * alternative fix: reindex in after refactor only, but via traverser * final touch: typo comment
1 parent 3e0bfbf commit ed60a22

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

src/Application/ChangedNodeScopeRefresher.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,18 @@ public function refresh(Node $node, string $filePath, ?MutatingScope $mutatingSc
5858
throw new ShouldNotHappenException($errorMessage);
5959
}
6060

61-
NodeAttributeReIndexer::reIndexNodeAttributes($node);
61+
/**
62+
* The reindex is needed to:
63+
* - be used by PHPStan processNodes() that relies on indexed arrays start from 0
64+
* - use traverser to avoid issues when multiples rules apply, and higher node remove deep node,
65+
* which the next rule use deep node, for example:
66+
* - first rule: - Class_ → ClassMethod → remove stmt with index 0
67+
* - second rule: - ClassMethod → here fetch the index 0 that no longer exists
68+
*/
69+
SimpleCallableNodeTraverser::traverse(
70+
$node,
71+
fn (Node $subNode): ?Node => NodeAttributeReIndexer::reIndexNodeAttributes($subNode)
72+
);
6273

6374
$stmts = $this->resolveStmts($node);
6475
$this->phpStanNodeScopeResolver->processNodes($stmts, $filePath, $mutatingScope);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Rector\Tests\Issues\IssuePropertyPromoRemoveDelegatingParent\Fixture;
4+
5+
use Rector\Tests\Issues\IssuePropertyPromoRemoveDelegatingParent\Source\SomeParentWithEmptyConstruct;
6+
7+
class Fixture extends SomeParentWithEmptyConstruct
8+
{
9+
private string $prop;
10+
11+
public function __construct(string $prop)
12+
{
13+
$this->prop = $prop;
14+
parent::__construct();
15+
}
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
namespace Rector\Tests\Issues\IssuePropertyPromoRemoveDelegatingParent\Fixture;
23+
24+
use Rector\Tests\Issues\IssuePropertyPromoRemoveDelegatingParent\Source\SomeParentWithEmptyConstruct;
25+
26+
class Fixture extends SomeParentWithEmptyConstruct
27+
{
28+
public function __construct(private string $prop)
29+
{
30+
parent::__construct();
31+
}
32+
}
33+
34+
?>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Issues\IssuePropertyPromoRemoveDelegatingParent;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class IssuePropertyPromoRemoveDelegatingParentTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Issues\IssuePropertyPromoRemoveDelegatingParent\Source;
6+
7+
abstract class SomeParentWithEmptyConstruct
8+
{
9+
public function __construct()
10+
{
11+
$this->init();
12+
}
13+
14+
private function init(): void
15+
{
16+
echo 'A init';
17+
}
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
use Rector\Config\RectorConfig;
4+
use Rector\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstructorRector;
5+
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
6+
7+
return RectorConfig::configure()
8+
->withRules([
9+
ClassPropertyAssignToConstructorPromotionRector::class,
10+
RemoveParentDelegatingConstructorRector::class,
11+
]);

0 commit comments

Comments
 (0)