Skip to content

Commit 211f0dc

Browse files
Check if narrowing is valid from parent
1 parent d96c9d4 commit 211f0dc

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ public function refactor(Node $node): ?Node
145145
return null;
146146
}
147147

148+
if (! $this->isNarrowingValidFromParent($node, $actualReturnClass)) {
149+
return null;
150+
}
151+
148152
$node->returnType = new FullyQualified($actualReturnClass);
149153

150154
$this->updateDocblock($node, $actualReturnClass);
@@ -235,6 +239,56 @@ private function isNarrowingValid(string $declaredType, string $actualType): boo
235239
->yes();
236240
}
237241

242+
private function isNarrowingValidFromParent(ClassMethod $classMethod, string $actualReturnClass): bool
243+
{
244+
if ($classMethod->isPrivate()) {
245+
return true;
246+
}
247+
248+
$classReflection = $this->reflectionResolver->resolveClassReflection($classMethod);
249+
250+
if (! $classReflection instanceof ClassReflection) {
251+
return true;
252+
}
253+
254+
$ancestors = array_filter(
255+
$classReflection->getAncestors(),
256+
fn (ClassReflection $ancestorClassReflection): bool => $classReflection->getName() !== $ancestorClassReflection->getName()
257+
);
258+
259+
$methodName = $this->getName($classMethod);
260+
261+
foreach ($ancestors as $ancestor) {
262+
if ($ancestor->getFileName() === null) {
263+
continue;
264+
}
265+
266+
if (! $ancestor->hasNativeMethod($methodName)) {
267+
continue;
268+
}
269+
270+
$parentClassMethod = $this->astResolver->resolveClassMethod($ancestor->getName(), $methodName);
271+
272+
if (! $parentClassMethod instanceof ClassMethod) {
273+
continue;
274+
}
275+
276+
$parentReturnType = $parentClassMethod->returnType;
277+
278+
if (! $parentReturnType instanceof Node) {
279+
continue;
280+
}
281+
282+
$parentReturnTypeName = $parentReturnType->toString();
283+
284+
if (! $this->isNarrowingValid($parentReturnTypeName, $actualReturnClass)) {
285+
return false;
286+
}
287+
}
288+
289+
return true;
290+
}
291+
238292
private function getActualReturnClass(ClassMethod $classMethod): ?string
239293
{
240294
$returnStatements = $this->betterNodeFinder->findReturnsScoped($classMethod);

0 commit comments

Comments
 (0)