diff --git a/rules/type-declaration/src/TypeInferer/ReturnTypeInferer.php b/rules/type-declaration/src/TypeInferer/ReturnTypeInferer.php index 212d0c2638f..ca850a751ad 100644 --- a/rules/type-declaration/src/TypeInferer/ReturnTypeInferer.php +++ b/rules/type-declaration/src/TypeInferer/ReturnTypeInferer.php @@ -53,9 +53,12 @@ final class ReturnTypeInferer extends AbstractPriorityAwareTypeInferer $type = $this->typeNormalizer->uniqueateConstantArrayType($type); $type = $this->typeNormalizer->normalizeArrayOfUnionToUnionArray($type); - if (! $type instanceof MixedType) { - return $type; + // in case of void, check return type of children methods + if ($type instanceof MixedType) { + continue; } + + return $type; } return new MixedType(); diff --git a/rules/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php b/rules/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php index 263d707d020..99300f2ed7b 100644 --- a/rules/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php +++ b/rules/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php @@ -8,6 +8,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\Closure; use PhpParser\Node\FunctionLike; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Interface_; @@ -30,15 +31,18 @@ final class ReturnedNodesReturnTypeInferer extends AbstractTypeInferer implement { /** @var Class_|Trait_|Interface_|null $classLike */ $classLike = $functionLike->getAttribute(AttributeKey::CLASS_NODE); + if ($classLike === null) { + return new MixedType(); + } + if ($functionLike instanceof ClassMethod && $classLike instanceof Interface_) { return new MixedType(); } $localReturnNodes = $this->collectReturns($functionLike); - if ($localReturnNodes === []) { // void type - if ($functionLike instanceof ClassMethod && ! $functionLike->isAbstract()) { + if (! $this->isAbstractMethod($classLike, $functionLike)) { return new VoidType(); } @@ -92,4 +96,15 @@ final class ReturnedNodesReturnTypeInferer extends AbstractTypeInferer implement return $returns; } + + private function isAbstractMethod(ClassLike $classLike, FunctionLike $functionLike): bool + { + // abstract class method + if ($functionLike instanceof ClassMethod && $functionLike->isAbstract()) { + return true; + } + + // abstract class + return $classLike instanceof Class_ && $classLike->isAbstract(); + } } diff --git a/rules/type-declaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/parent_override.php.inc b/rules/type-declaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/parent_override.php.inc new file mode 100644 index 00000000000..4745a87ebd4 --- /dev/null +++ b/rules/type-declaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/parent_override.php.inc @@ -0,0 +1,47 @@ + +----- +