diff --git a/rules-tests/Php82/Rector/Class_/ReadOnlyClassRector/Fixture/child_extends_parent_already_readonly.php.inc b/rules-tests/Php82/Rector/Class_/ReadOnlyClassRector/Fixture/child_extends_parent_already_readonly.php.inc new file mode 100644 index 00000000000..a5ee64c9da0 --- /dev/null +++ b/rules-tests/Php82/Rector/Class_/ReadOnlyClassRector/Fixture/child_extends_parent_already_readonly.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/rules-tests/Php82/Rector/Class_/ReadOnlyClassRector/Source/ParentAlreadyReadonly.php b/rules-tests/Php82/Rector/Class_/ReadOnlyClassRector/Source/ParentAlreadyReadonly.php new file mode 100644 index 00000000000..f15b0c5b6c7 --- /dev/null +++ b/rules-tests/Php82/Rector/Class_/ReadOnlyClassRector/Source/ParentAlreadyReadonly.php @@ -0,0 +1,7 @@ +reflectionResolver->resolveClassReflection($class); + if (! $classReflection instanceof ClassReflection) { + return []; + } + + return $classReflection->getParents(); + } + + /** + * @param Property[] $properties + */ + private function hasNonTypedProperty(array $properties): bool + { + foreach ($properties as $property) { + // properties of readonly class must always have type + if ($property->type === null) { + return true; + } + } + + return false; + } + private function shouldSkip(Class_ $class): bool { if ($this->shouldSkipClass($class)) { return true; } + $parents = $this->resolveParentClassReflections($class); + if (! $class->isFinal()) { + return ! $this->isExtendsReadonlyClass($parents); + } + + foreach ($parents as $parent) { + if (! $parent->isReadOnly()) { + return true; + } + } + $properties = $class->getProperties(); if ($this->hasWritableProperty($properties)) { return true; } - foreach ($properties as $property) { - // properties of readonly class must always have type - if ($property->type === null) { - return true; - } + if ($this->hasNonTypedProperty($properties)) { + return true; } $constructClassMethod = $class->getMethod(MethodName::CONSTRUCT); @@ -137,6 +173,20 @@ private function shouldSkip(Class_ $class): bool return $this->shouldSkipParams($params); } + /** + * @param ClassReflection[] $parents + */ + private function isExtendsReadonlyClass(array $parents): bool + { + foreach ($parents as $parent) { + if ($parent->isReadOnly()) { + return true; + } + } + + return false; + } + /** * @param Property[] $properties */ @@ -162,22 +212,6 @@ private function shouldSkipClass(Class_ $class): bool return true; } - if (! $class->isFinal()) { - return true; - } - - $classReflection = $this->reflectionResolver->resolveClassReflection($class); - if (! $classReflection instanceof ClassReflection) { - return true; - } - - $parents = $classReflection->getParents(); - foreach ($parents as $parent) { - if (! $parent->isReadOnly()) { - return true; - } - } - return $this->phpAttributeAnalyzer->hasPhpAttribute($class, AttributeName::ALLOW_DYNAMIC_PROPERTIES); }