Skip to content

Commit 6d241d1

Browse files
committed
skip parent magic called method in PrivatizeFinalClassMethodRector
1 parent fb58990 commit 6d241d1

File tree

4 files changed

+79
-1
lines changed

4 files changed

+79
-1
lines changed

rules/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public function getNodeTypes(): array
8686
public function refactor(Node $node): null|CallLike
8787
{
8888
if ($node instanceof Assign) {
89+
// @todo handle by existing attribute already
8990
if ($node->expr instanceof Closure || $node->expr instanceof ArrowFunction) {
9091
$node->expr->setAttribute(self::IS_IN_ASSIGN, true);
9192
}

rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function __construct(
3030
private readonly OverrideByParentClassGuard $overrideByParentClassGuard,
3131
private readonly BetterNodeFinder $betterNodeFinder,
3232
private readonly LaravelModelGuard $laravelModelGuard,
33+
private readonly \Rector\Privatization\VisibilityGuard\ParentClassMagicCallGuard $parentClassMagicCallGuard
3334
) {
3435
}
3536

@@ -107,6 +108,10 @@ public function refactor(Node $node): ?Node
107108
continue;
108109
}
109110

111+
if ($this->parentClassMagicCallGuard->containsParentClassMagicCall($node)) {
112+
continue;
113+
}
114+
110115
if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByTrait(
111116
$classMethod,
112117
$classReflection
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Privatization\VisibilityGuard;
6+
7+
use PhpParser\Node\Expr;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Stmt\Class_;
10+
use Rector\NodeNameResolver\NodeNameResolver;
11+
use Rector\PhpParser\AstResolver;
12+
use Rector\PhpParser\Node\BetterNodeFinder;
13+
14+
final class ParentClassMagicCallGuard
15+
{
16+
/**
17+
* @var array<string, bool>
18+
*/
19+
private array $cachedContainsByClassName = [];
20+
21+
public function __construct(
22+
private readonly NodeNameResolver $nodeNameResolver,
23+
private readonly AstResolver $astResolver,
24+
private readonly BetterNodeFinder $betterNodeFinder
25+
) {
26+
}
27+
28+
/**
29+
* E.g. parent class has $this->{$magicName} call that might call the protected method
30+
* If we make it private, it will break the code
31+
*/
32+
public function containsParentClassMagicCall(Class_ $class): bool
33+
{
34+
// cache as heavy AST parsing here
35+
$className = $this->nodeNameResolver->getName($class);
36+
if (isset($this->cachedContainsByClassName[$className])) {
37+
return $this->cachedContainsByClassName[$className];
38+
}
39+
40+
if ($class->extends === null) {
41+
return false;
42+
}
43+
44+
$parentClassName = $this->nodeNameResolver->getName($class->extends);
45+
46+
$parentClass = $this->astResolver->resolveClassFromName($parentClassName);
47+
if (! $parentClass instanceof Class_) {
48+
$this->cachedContainsByClassName[$className] = false;
49+
return false;
50+
}
51+
52+
foreach ($parentClass->getMethods() as $classMethod) {
53+
if ($classMethod->isAbstract()) {
54+
continue;
55+
}
56+
57+
/** @var MethodCall[] $methodCalls */
58+
$methodCalls = $this->betterNodeFinder->findInstancesOfScoped(
59+
(array) $classMethod->stmts,
60+
MethodCall::class
61+
);
62+
foreach ($methodCalls as $methodCall) {
63+
if ($methodCall->name instanceof Expr) {
64+
$this->cachedContainsByClassName[$className] = true;
65+
return true;
66+
}
67+
}
68+
}
69+
70+
return $this->containsParentClassMagicCall($parentClass);
71+
}
72+
}

src/ValueObject/Application/File.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
namespace Rector\ValueObject\Application;
66

7-
use PhpParser\Node\Stmt\Namespace_;
87
use PhpParser\Node;
98
use PhpParser\Node\Stmt;
109
use PhpParser\Node\Stmt\InlineHTML;
10+
use PhpParser\Node\Stmt\Namespace_;
1111
use PhpParser\NodeFinder;
1212
use PhpParser\Token;
1313
use Rector\ChangesReporting\ValueObject\RectorWithLineChange;

0 commit comments

Comments
 (0)