diff --git a/rules-tests/DeadCode/Rector/StaticCall/RemoveParentCallWithoutParentRector/Fixture/skip_broken_hierarchy.php.inc b/rules-tests/DeadCode/Rector/StaticCall/RemoveParentCallWithoutParentRector/Fixture/skip_broken_hierarchy.php.inc new file mode 100644 index 00000000000..b4e4d3a0d01 --- /dev/null +++ b/rules-tests/DeadCode/Rector/StaticCall/RemoveParentCallWithoutParentRector/Fixture/skip_broken_hierarchy.php.inc @@ -0,0 +1,13 @@ +classMethodManipulator->hasParentMethodOrInterfaceMethod($class, $calledMethodName); + if ($this->classMethodManipulator->hasParentMethodOrInterfaceMethod($class, $calledMethodName)) { + return true; + } + + // the called method may be defined in an ancestor that cannot be resolved + // (e.g. a grandparent class is not autoloadable); in that case we cannot + // safely tell the method does not exist, so the call must not be removed + return $this->hasUnresolvableAncestor($class->extends); + } + + private function hasUnresolvableAncestor(Name $parentName): bool + { + $parentClassName = $this->getName($parentName); + if (! is_string($parentClassName)) { + return false; + } + + if (! $this->reflectionProvider->hasClass($parentClassName)) { + return true; + } + + $parentClass = $this->astResolver->resolveClassFromName($parentClassName); + if (! $parentClass instanceof Class_) { + return false; + } + + if (! $parentClass->extends instanceof Name) { + return false; + } + + return $this->hasUnresolvableAncestor($parentClass->extends); } }