Skip to content

Commit

Permalink
[TypeDeclaration] Handle Parent ClassMethod has no Return_ stmt on Re…
Browse files Browse the repository at this point in the history
…turnTypeDeclarationRector (#2980)

* [TypeDeclaration] Handle Parent ClassMethod has no Return_ stmt on ReturnTypeDeclarationRector

* [ci-review] Rector Rectify

* check child return type

* handle both parent and child void

* final touch: eol

* better comment

Co-authored-by: GitHub Action <action@github.com>
  • Loading branch information
samsonasik and actions-user committed Oct 7, 2022
1 parent 0c2b4f7 commit 1d88337
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
use PHPStan\Type\MixedType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\VoidType;
use Rector\Core\PhpParser\AstResolver;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\StaticTypeMapper\PhpDoc\CustomPHPStanDetector;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;

final class ClassMethodReturnTypeOverrideGuard
{
Expand All @@ -38,7 +40,8 @@ public function __construct(
private readonly BetterNodeFinder $betterNodeFinder,
private readonly AstResolver $astResolver,
private readonly ReflectionResolver $reflectionResolver,
private readonly CustomPHPStanDetector $customPHPStanDetector
private readonly CustomPHPStanDetector $customPHPStanDetector,
private readonly ReturnTypeInferer $returnTypeInferer
) {
}

Expand Down Expand Up @@ -102,6 +105,8 @@ public function shouldSkipClassMethodOldTypeWithNewType(
*/
private function shouldSkipHasChildHasReturnType(array $childrenClassReflections, ClassMethod $classMethod): bool
{
$returnType = $this->returnTypeInferer->inferFunctionLike($classMethod);

$methodName = $this->nodeNameResolver->getName($classMethod);
foreach ($childrenClassReflections as $childClassReflection) {
if (! $childClassReflection->hasNativeMethod($methodName)) {
Expand All @@ -118,6 +123,11 @@ private function shouldSkipHasChildHasReturnType(array $childrenClassReflections
if ($method->returnType instanceof Node) {
return true;
}

$childReturnType = $this->returnTypeInferer->inferFunctionLike($method);
if ($returnType instanceof VoidType && ! $childReturnType instanceof VoidType) {
return true;
}
}

return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;

/**
* Both class parent and child need to be in same fixture file
* as demonstrate the changed parts are both
*/
class ParentNoReturnStmt2
{
public function run()
{
// this method is optional, not marked as abstract
// and leave the child to implements or not
}
}

final class SomeChildOverrideParentMethod2 extends ParentNoReturnStmt2
{
public function run()
{
echo 'test';
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;

/**
* Both class parent and child need to be in same fixture file
* as demonstrate the changed parts are both
*/
class ParentNoReturnStmt2
{
public function run(): void
{
// this method is optional, not marked as abstract
// and leave the child to implements or not
}
}

final class SomeChildOverrideParentMethod2 extends ParentNoReturnStmt2
{
public function run(): void
{
echo 'test';
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;

use stdClass;

/**
* Both class parent and child need to be in same fixture file
* as demonstrate the changed parts are both, which should only child
*/
class ParentNoReturnStmt
{
/**
* @return stdClass
*/
public function run()
{
// this method is optional, not marked as abstract
// and leave the child to implements or not
}
}

final class SomeChildOverrideParentMethod extends ParentNoReturnStmt
{
public function run()
{
return new stdClass;
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;

use stdClass;

/**
* Both class parent and child need to be in same fixture file
* as demonstrate the changed parts are both, which should only child
*/
class ParentNoReturnStmt
{
/**
* @return stdClass
*/
public function run()
{
// this method is optional, not marked as abstract
// and leave the child to implements or not
}
}

final class SomeChildOverrideParentMethod extends ParentNoReturnStmt
{
public function run(): \stdClass
{
return new stdClass;
}
}

?>

0 comments on commit 1d88337

Please sign in to comment.