From fdf888be6a3f662e663b1ffd755849a935df9727 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 25 Oct 2026 21:26:06 +0100 Subject: [PATCH] [TypeDeclaration] Retarget ReturnTypeFromMockObjectRector to Class_ node --- .../Fixture/skip_filled_type.php.inc | 2 +- .../Fixture/skip_possible_void.php.inc | 2 +- .../Fixture/skip_return_by_docblock.php.inc | 2 +- .../Fixture/some_test_with_mock.php.inc | 4 +- .../ReturnTypeFromMockObjectRectorTest.php | 2 +- .../config/configured_rule.php | 2 +- .../ReturnTypeFromMockObjectRector.php | 82 ++++++++++--------- src/Config/Level/TypeDeclarationLevel.php | 2 +- 8 files changed, 51 insertions(+), 47 deletions(-) rename rules-tests/TypeDeclaration/Rector/{ClassMethod => Class_}/ReturnTypeFromMockObjectRector/Fixture/skip_filled_type.php.inc (73%) rename rules-tests/TypeDeclaration/Rector/{ClassMethod => Class_}/ReturnTypeFromMockObjectRector/Fixture/skip_possible_void.php.inc (71%) rename rules-tests/TypeDeclaration/Rector/{ClassMethod => Class_}/ReturnTypeFromMockObjectRector/Fixture/skip_return_by_docblock.php.inc (73%) rename rules-tests/TypeDeclaration/Rector/{ClassMethod => Class_}/ReturnTypeFromMockObjectRector/Fixture/some_test_with_mock.php.inc (71%) rename rules-tests/TypeDeclaration/Rector/{ClassMethod => Class_}/ReturnTypeFromMockObjectRector/ReturnTypeFromMockObjectRectorTest.php (87%) rename rules-tests/TypeDeclaration/Rector/{ClassMethod => Class_}/ReturnTypeFromMockObjectRector/config/configured_rule.php (66%) rename rules/TypeDeclaration/Rector/{ClassMethod => Class_}/ReturnTypeFromMockObjectRector.php (63%) diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_filled_type.php.inc b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_filled_type.php.inc similarity index 73% rename from rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_filled_type.php.inc rename to rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_filled_type.php.inc index 5bf3b608f06..cb821eca57c 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_filled_type.php.inc +++ b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_filled_type.php.inc @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector\Fixture; +namespace Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector\Fixture; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_possible_void.php.inc b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_possible_void.php.inc similarity index 71% rename from rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_possible_void.php.inc rename to rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_possible_void.php.inc index 2ffa3b2e8b4..c2a4b553ea7 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_possible_void.php.inc +++ b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_possible_void.php.inc @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector\Fixture; +namespace Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector\Fixture; use PHPUnit\Framework\TestCase; diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_return_by_docblock.php.inc b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_return_by_docblock.php.inc similarity index 73% rename from rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_return_by_docblock.php.inc rename to rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_return_by_docblock.php.inc index 6c952a1dcc3..e6bf5b26d9a 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/skip_return_by_docblock.php.inc +++ b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/skip_return_by_docblock.php.inc @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector\Fixture; +namespace Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector\Fixture; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/some_test_with_mock.php.inc b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/some_test_with_mock.php.inc similarity index 71% rename from rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/some_test_with_mock.php.inc rename to rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/some_test_with_mock.php.inc index 7031295b6f0..bc7ac8e0e89 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/Fixture/some_test_with_mock.php.inc +++ b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/Fixture/some_test_with_mock.php.inc @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector\Fixture; +namespace Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector\Fixture; use PHPUnit\Framework\TestCase; @@ -20,7 +20,7 @@ final class SomeTestWithMock extends TestCase declare(strict_types=1); -namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector\Fixture; +namespace Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector\Fixture; use PHPUnit\Framework\TestCase; diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/ReturnTypeFromMockObjectRectorTest.php b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/ReturnTypeFromMockObjectRectorTest.php similarity index 87% rename from rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/ReturnTypeFromMockObjectRectorTest.php rename to rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/ReturnTypeFromMockObjectRectorTest.php index ca11affd54d..67ab9307fdc 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/ReturnTypeFromMockObjectRectorTest.php +++ b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/ReturnTypeFromMockObjectRectorTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector; +namespace Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector; use Iterator; use PHPUnit\Framework\Attributes\DataProvider; diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/config/configured_rule.php b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/config/configured_rule.php similarity index 66% rename from rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/config/configured_rule.php rename to rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/config/configured_rule.php index 16a43e57ea5..3314336f1b6 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector/config/configured_rule.php +++ b/rules-tests/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector/config/configured_rule.php @@ -3,7 +3,7 @@ declare(strict_types=1); use Rector\Config\RectorConfig; -use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector; +use Rector\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector; return RectorConfig::configure() ->withRules([ReturnTypeFromMockObjectRector::class]); diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector.php b/rules/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector.php similarity index 63% rename from rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector.php rename to rules/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector.php index ee5e5cbcc87..5e9f7f8f8b3 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromMockObjectRector.php +++ b/rules/TypeDeclaration/Rector/Class_/ReturnTypeFromMockObjectRector.php @@ -2,13 +2,12 @@ declare(strict_types=1); -namespace Rector\TypeDeclaration\Rector\ClassMethod; +namespace Rector\TypeDeclaration\Rector\Class_; use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Stmt\ClassMethod; -use PHPStan\Analyser\Scope; +use PhpParser\Node\Stmt\Class_; use PHPStan\Reflection\ClassReflection; use PHPStan\Type\IntersectionType; use PHPStan\Type\ObjectType; @@ -25,7 +24,7 @@ use Rector\VersionBonding\Contract\MinPhpVersionInterface; /** - * @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector\ReturnTypeFromMockObjectRectorTest + * @see \Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector\ReturnTypeFromMockObjectRectorTest */ final class ReturnTypeFromMockObjectRector extends AbstractRector implements MinPhpVersionInterface { @@ -68,49 +67,65 @@ public function createSomeMock(): \PHPUnit\Framework\MockObject\MockObject public function getNodeTypes(): array { - return [ClassMethod::class]; + return [Class_::class]; } /** - * @param ClassMethod $node + * @param Class_ $node */ public function refactor(Node $node): ?Node { - // type is already known - if ($node->returnType instanceof Node) { + $classReflection = $this->getClassReflection($node); + if (! $classReflection instanceof ClassReflection) { return null; } - // we need exactly 1 return - $returns = $this->betterNodeFinder->findReturnsScoped($node); - if (count($returns) !== 1) { + // is phpunit test case? + if (! $classReflection->is(ClassName::TEST_CASE_CLASS)) { return null; } - if (! $this->returnAnalyzer->hasOnlyReturnWithExpr($node, $returns)) { - return null; - } + $hasChanged = false; + $scope = null; - $scope = ScopeFetcher::fetch($node); - if (! $this->isInsideTestCaseClass($scope)) { - return null; - } + foreach ($node->getMethods() as $classMethod) { + // type is already known + if ($classMethod->returnType instanceof Node) { + continue; + } - if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) { - return null; - } + // we need exactly 1 return + $returns = $this->betterNodeFinder->findReturnsScoped($classMethod); + if (count($returns) !== 1) { + continue; + } - /** @var Expr $expr */ - $expr = $returns[0]->expr; - $returnType = $this->nodeTypeResolver->getNativeType($expr); + if (! $this->returnAnalyzer->hasOnlyReturnWithExpr($classMethod, $returns)) { + continue; + } - if (! $this->isMockObjectType($returnType)) { - return null; + $scope ??= ScopeFetcher::fetch($node); + if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($classMethod, $scope)) { + continue; + } + + /** @var Expr $expr */ + $expr = $returns[0]->expr; + $returnType = $this->nodeTypeResolver->getNativeType($expr); + + if (! $this->isMockObjectType($returnType)) { + continue; + } + + $classMethod->returnType = new FullyQualified(ClassName::MOCK_OBJECT); + $hasChanged = true; } - $node->returnType = new FullyQualified(ClassName::MOCK_OBJECT); + if ($hasChanged) { + return $node; + } - return $node; + return null; } public function provideMinPhpVersion(): int @@ -139,15 +154,4 @@ private function isMockObjectType(Type $returnType): bool return $this->isIntersectionWithMockObjectType($returnType); } - - private function isInsideTestCaseClass(Scope $scope): bool - { - $classReflection = $scope->getClassReflection(); - if (! $classReflection instanceof ClassReflection) { - return false; - } - - // is phpunit test case? - return $classReflection->is(ClassName::TEST_CASE_CLASS); - } } diff --git a/src/Config/Level/TypeDeclarationLevel.php b/src/Config/Level/TypeDeclarationLevel.php index f4d3e7508ab..44f33b6895a 100644 --- a/src/Config/Level/TypeDeclarationLevel.php +++ b/src/Config/Level/TypeDeclarationLevel.php @@ -13,6 +13,7 @@ use Rector\TypeDeclaration\Rector\Class_\MergeDateTimePropertyTypeDeclarationRector; use Rector\TypeDeclaration\Rector\Class_\ObjectTypedPropertyFromJMSSerializerAttributeTypeRector; use Rector\TypeDeclaration\Rector\Class_\PropertyTypeFromStrictSetterGetterRector; +use Rector\TypeDeclaration\Rector\Class_\ReturnTypeFromMockObjectRector; use Rector\TypeDeclaration\Rector\Class_\ReturnTypeFromStrictTernaryRector; use Rector\TypeDeclaration\Rector\Class_\ScalarTypedPropertyFromJMSSerializerAttributeTypeRector; use Rector\TypeDeclaration\Rector\Class_\TypedPropertyFromContainerGetSetUpRector; @@ -38,7 +39,6 @@ use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNullableTypeRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromGetRepositoryDocblockRector; -use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromMockObjectRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnCastRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnDirectArrayRector; use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector;