@@ -146,6 +146,10 @@ public function refactor(Node $node): ?Node
146146 return null ;
147147 }
148148
149+ if (! $ this ->isNarrowingValidFromParent ($ node , $ actualReturnClass )) {
150+ return null ;
151+ }
152+
149153 $ node ->returnType = new FullyQualified ($ actualReturnClass );
150154
151155 $ this ->updateDocblock ($ node , $ actualReturnClass );
@@ -246,6 +250,56 @@ private function isNarrowingValid(ClassMethod $classMethod, string $declaredType
246250 return ! $ returnType instanceof GenericObjectType;
247251 }
248252
253+ private function isNarrowingValidFromParent (ClassMethod $ classMethod , string $ actualReturnClass ): bool
254+ {
255+ if ($ classMethod ->isPrivate ()) {
256+ return true ;
257+ }
258+
259+ $ classReflection = $ this ->reflectionResolver ->resolveClassReflection ($ classMethod );
260+
261+ if (! $ classReflection instanceof ClassReflection) {
262+ return true ;
263+ }
264+
265+ $ ancestors = array_filter (
266+ $ classReflection ->getAncestors (),
267+ fn (ClassReflection $ ancestorClassReflection ): bool => $ classReflection ->getName () !== $ ancestorClassReflection ->getName ()
268+ );
269+
270+ $ methodName = $ this ->getName ($ classMethod );
271+
272+ foreach ($ ancestors as $ ancestor ) {
273+ if ($ ancestor ->getFileName () === null ) {
274+ continue ;
275+ }
276+
277+ if (! $ ancestor ->hasNativeMethod ($ methodName )) {
278+ continue ;
279+ }
280+
281+ $ parentClassMethod = $ this ->astResolver ->resolveClassMethod ($ ancestor ->getName (), $ methodName );
282+
283+ if (! $ parentClassMethod instanceof ClassMethod) {
284+ continue ;
285+ }
286+
287+ $ parentReturnType = $ parentClassMethod ->returnType ;
288+
289+ if (! $ parentReturnType instanceof Node) {
290+ continue ;
291+ }
292+
293+ $ parentReturnTypeName = $ parentReturnType ->toString ();
294+
295+ if (! $ this ->isNarrowingValid ($ parentReturnTypeName , $ actualReturnClass )) {
296+ return false ;
297+ }
298+ }
299+
300+ return true ;
301+ }
302+
249303 private function getActualReturnClass (ClassMethod $ classMethod ): ?string
250304 {
251305 $ returnStatements = $ this ->betterNodeFinder ->findReturnsScoped ($ classMethod );
0 commit comments