[Php81] Skip ReadOnlyPropertyRector on Stmt is not inline with __construct (#1846)

* [PHP81] Skip readonly on promoted property change

# Failing Test for ReadOnlyPropertyRector
Based on https://getrector.org/demo/1e2cb1b3-8dd5-46fc-925b-1df01d0b73c0

This is probably due to constructor property promotion generating additional assignment that is not visible by rector, related to https://github.com/rectorphp/rector/issues/7012.

* Closes #1845

* [ci-review] Rector Rectify

* [ci-review] Rector Rectify

* phpstan

Co-authored-by: Kacper Donat <kadet1090@gmail.com>
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Abdul Malik Ikhsan 2022-02-21 10:43:26 +07:00 committed by GitHub
parent 59f6b29698
commit 886aad92f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 3 deletions

View File

@ -0,0 +1,16 @@
<?php
namespace Rector\Tests\Php81\Rector\Property\ReadOnlyPropertyRector\Fixture;
final class SkipConditionallyChangedProperty
{
public function __construct(private Converter $converter)
{
if ($this->converter instanceof CacheableConverter) {
$this->converter = clone $this->converter;
$this->converter->reset();
}
}
}
?>

View File

@ -19,6 +19,7 @@ use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
@ -154,9 +155,9 @@ final class PropertyManipulator
// skip for constructor? it is allowed to set value in constructor method
$classMethod = $this->betterNodeFinder->findParentType($propertyFetch, ClassMethod::class);
if ($classMethod instanceof ClassMethod && $this->nodeNameResolver->isName(
$classMethod->name,
MethodName::CONSTRUCT
if ($classMethod instanceof ClassMethod && $this->isInlineStmtWithConstructMethod(
$propertyFetch,
$classMethod
)) {
continue;
}
@ -186,6 +187,23 @@ final class PropertyManipulator
return false;
}
private function isInlineStmtWithConstructMethod(
PropertyFetch|StaticPropertyFetch $propertyFetch,
ClassMethod $classMethod
): bool {
if (! $this->nodeNameResolver->isName($classMethod->name, MethodName::CONSTRUCT)) {
return false;
}
$currentStmt = $propertyFetch->getAttribute(AttributeKey::CURRENT_STATEMENT);
if (! $currentStmt instanceof Stmt) {
return false;
}
$parent = $currentStmt->getAttribute(AttributeKey::PARENT_NODE);
return $parent === $classMethod;
}
private function isChangeableContext(PropertyFetch | StaticPropertyFetch $propertyFetch): bool
{
$parent = $propertyFetch->getAttribute(AttributeKey::PARENT_NODE);