diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector/Fixture/get_repository_via_variable.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector/Fixture/get_repository_via_variable.php.inc new file mode 100644 index 00000000000..b3f8bab0213 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector/Fixture/get_repository_via_variable.php.inc @@ -0,0 +1,54 @@ +em->getRepository(Event::class); + + $repo->setDispatcher($this->dispatcher); + + return $repo; + } +} + +?> +----- +em->getRepository(Event::class); + + $repo->setDispatcher($this->dispatcher); + + return $repo; + } +} + +?> diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector/Fixture/skip_reassigned_variable.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector/Fixture/skip_reassigned_variable.php.inc new file mode 100644 index 00000000000..0afb9270f81 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector/Fixture/skip_reassigned_variable.php.inc @@ -0,0 +1,24 @@ +em->getRepository(Event::class); + $repo = someOther(); + + return $repo; + } +} diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector.php index 4895b9b8b8d..9e1fb312ea3 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromGetRepositoryDocblockRector.php @@ -5,7 +5,9 @@ namespace Rector\TypeDeclaration\Rector\ClassMethod; use PhpParser\Node; +use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name; use PhpParser\Node\Stmt\ClassMethod; use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode; @@ -141,11 +143,28 @@ private function isGetRepositoryReturnOnly(ClassMethod $classMethod): bool return false; } - $methodCall = $returns[0]->expr; - if (! $methodCall instanceof MethodCall) { - return false; + $returnedExpr = $returns[0]->expr; + + // direct return: return $this->em->getRepository(...); + if ($returnedExpr instanceof MethodCall) { + return $this->isGetRepositoryMethodCall($returnedExpr); + } + + // indirect return: $repo = $this->em->getRepository(...); ...; return $repo; + if ($returnedExpr instanceof Variable) { + $assignedMethodCall = $this->findVariableAssignMethodCall($classMethod, $returnedExpr); + if (! $assignedMethodCall instanceof MethodCall) { + return false; + } + + return $this->isGetRepositoryMethodCall($assignedMethodCall); } + return false; + } + + private function isGetRepositoryMethodCall(MethodCall $methodCall): bool + { if (! $this->isName($methodCall->name, 'getRepository')) { return false; } @@ -153,6 +172,32 @@ private function isGetRepositoryReturnOnly(ClassMethod $classMethod): bool return $this->isEntityManagerType($methodCall); } + private function findVariableAssignMethodCall(ClassMethod $classMethod, Variable $variable): ?MethodCall + { + /** @var Assign[] $assigns */ + $assigns = $this->betterNodeFinder->findInstanceOf($classMethod, Assign::class); + + $methodCall = null; + foreach ($assigns as $assign) { + if (! $assign->var instanceof Variable) { + continue; + } + + if (! $this->nodeComparator->areNodesEqual($assign->var, $variable)) { + continue; + } + + // reassigned to something else, cannot be sure of the type + if (! $assign->expr instanceof MethodCall) { + return null; + } + + $methodCall = $assign->expr; + } + + return $methodCall; + } + private function isEntityManagerType(MethodCall $methodCall): bool { $callerType = $this->nodeTypeResolver->getType($methodCall->var);