From 6b7251100050ae4b5d8c7be9d3b1efc69c01d7bd Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 4 Feb 2026 22:40:51 +0100 Subject: [PATCH 1/3] [code-quality] Add RemoveStandaloneCreateMockRector --- config/sets/phpunit-code-quality.php | 4 + .../Fixture/fixture.php.inc | 30 ++++++ .../RemoveStandaloneCreateMockRectorTest.php | 28 +++++ .../config/configured_rule.php | 10 ++ .../RemoveStandaloneCreateMockRector.php | 102 ++++++++++++++++++ .../ExplicitMockExpectsCallRector.php | 2 +- 6 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/fixture.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/RemoveStandaloneCreateMockRectorTest.php create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/config/configured_rule.php create mode 100644 rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php diff --git a/config/sets/phpunit-code-quality.php b/config/sets/phpunit-code-quality.php index 7454a661..7c3c6eb2 100644 --- a/config/sets/phpunit-code-quality.php +++ b/config/sets/phpunit-code-quality.php @@ -21,6 +21,7 @@ use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\EntityDocumentCreateMockToDirectNewRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\NoSetupWithParentCallOverrideRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\RemoveEmptyTestMethodRector; +use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\RemoveStandaloneCreateMockRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\ReplaceTestAnnotationWithPrefixedFunctionRector; use Rector\PHPUnit\CodeQuality\Rector\Expression\AssertArrayCastedObjectToAssertSameRector; use Rector\PHPUnit\CodeQuality\Rector\Foreach_\SimplifyForeachInstanceOfRector; @@ -149,7 +150,10 @@ EntityDocumentCreateMockToDirectNewRector::class, ReplaceAtMethodWithDesiredMatcherRector::class, BareCreateMockAssignToDirectUseRector::class, + + // dead code RemoveNeverUsedMockPropertyRector::class, + RemoveStandaloneCreateMockRector::class, // readability NoSetupWithParentCallOverrideRector::class, diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/fixture.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/fixture.php.inc new file mode 100644 index 00000000..854170b9 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/fixture.php.inc @@ -0,0 +1,30 @@ +createMock('someClass'); + } +} + +?> +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/RemoveStandaloneCreateMockRectorTest.php b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/RemoveStandaloneCreateMockRectorTest.php new file mode 100644 index 00000000..96bafc76 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/RemoveStandaloneCreateMockRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/config/configured_rule.php b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/config/configured_rule.php new file mode 100644 index 00000000..72f7bcc9 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(RemoveStandaloneCreateMockRector::class); +}; diff --git a/rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php b/rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php new file mode 100644 index 00000000..319e5610 --- /dev/null +++ b/rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php @@ -0,0 +1,102 @@ +createMock('SomeClass'); + } +} +CODE_SAMPLE + + , + <<<'CODE_SAMPLE' +use PHPUnit\Framework\TestCase; + +final class SomeTest extends TestCase +{ + public function test() + { + } +} +CODE_SAMPLE + ), + ] + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [ClassMethod::class]; + } + + /** + * @param ClassMethod $node + */ + public function refactor(Node $node): ?Node + { + if (! $this->testsNodeAnalyzer->isInTestClass($node)) { + return null; + } + + $hasChanged = false; + foreach ((array) $node->stmts as $key => $stmt) { + if (! $stmt instanceof Expression) { + continue; + } + + if (! $stmt->expr instanceof MethodCall) { + continue; + } + + $methodCall = $stmt->expr; + if (! $this->isName($methodCall->name, 'createMock')) { + continue; + } + + unset($node->stmts[$key]); + $hasChanged = true; + } + + if ($hasChanged) { + return $node; + } + + return null; + } +} diff --git a/rules/PHPUnit120/Rector/MethodCall/ExplicitMockExpectsCallRector.php b/rules/PHPUnit120/Rector/MethodCall/ExplicitMockExpectsCallRector.php index eae0abfb..bbc41338 100644 --- a/rules/PHPUnit120/Rector/MethodCall/ExplicitMockExpectsCallRector.php +++ b/rules/PHPUnit120/Rector/MethodCall/ExplicitMockExpectsCallRector.php @@ -4,11 +4,11 @@ namespace Rector\PHPUnit\PHPUnit120\Rector\MethodCall; -use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node; use PhpParser\Node\Arg; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Stmt\ClassMethod; use PHPStan\Type\ObjectType; use Rector\PHPUnit\Enum\PHPUnitClassName; use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; From 8590dd38d64e17a8faae01dbced5131805fa6952 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 4 Feb 2026 22:45:59 +0100 Subject: [PATCH 2/3] enable AddInstanceofAssertForNullableArgumentRector --- config/sets/phpunit-code-quality.php | 3 ++- .../Fixture/skip_assigned_call.php.inc | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/skip_assigned_call.php.inc diff --git a/config/sets/phpunit-code-quality.php b/config/sets/phpunit-code-quality.php index 7c3c6eb2..74feb3be 100644 --- a/config/sets/phpunit-code-quality.php +++ b/config/sets/phpunit-code-quality.php @@ -15,6 +15,7 @@ use Rector\PHPUnit\CodeQuality\Rector\Class_\TestWithToDataProviderRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\TypeWillReturnCallableArrowFunctionRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; +use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\AddInstanceofAssertForNullableArgumentRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\AddInstanceofAssertForNullableInstanceRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\BareCreateMockAssignToDirectUseRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\DataProviderArrayItemsNewLinedRector; @@ -112,7 +113,7 @@ AddInstanceofAssertForNullableInstanceRector::class, // enable next after testing - // \Rector\PHPUnit\CodeQuality\Rector\ClassMethod\AddInstanceofAssertForNullableArgumentRector::class, + AddInstanceofAssertForNullableArgumentRector::class, AssertArrayCastedObjectToAssertSameRector::class, diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/skip_assigned_call.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/skip_assigned_call.php.inc new file mode 100644 index 00000000..d34bccfe --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/skip_assigned_call.php.inc @@ -0,0 +1,13 @@ +createMock('someClass'); + } +} From 88053536726d77ba8e80fa9de4e77ced2a8776d2 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 4 Feb 2026 22:48:46 +0100 Subject: [PATCH 3/3] covert topmost call --- .../Fixture/handle_multiples.php.inc | 33 +++++++++++++++++++ .../Fixture/handle_nested_call.php.inc | 32 ++++++++++++++++++ .../RemoveStandaloneCreateMockRector.php | 14 ++++++-- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_multiples.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_nested_call.php.inc diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_multiples.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_multiples.php.inc new file mode 100644 index 00000000..8ebaacf9 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_multiples.php.inc @@ -0,0 +1,33 @@ +createMock('someClass'); + $this->createMock('someClass'); + $this->createMock('someClass'); + $this->createMock('someClass'); + } +} + +?> +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_nested_call.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_nested_call.php.inc new file mode 100644 index 00000000..eabceae7 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector/Fixture/handle_nested_call.php.inc @@ -0,0 +1,32 @@ +createMock('someClass') + ->method('some') + ->willReturn(100); + } +} + +?> +----- + diff --git a/rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php b/rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php index 319e5610..1d9f2739 100644 --- a/rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php +++ b/rules/CodeQuality/Rector/ClassMethod/RemoveStandaloneCreateMockRector.php @@ -84,8 +84,8 @@ public function refactor(Node $node): ?Node continue; } - $methodCall = $stmt->expr; - if (! $this->isName($methodCall->name, 'createMock')) { + $topmostCall = $this->resolveTopmostCall($stmt->expr); + if (! $this->isName($topmostCall->name, 'createMock')) { continue; } @@ -99,4 +99,14 @@ public function refactor(Node $node): ?Node return null; } + + private function resolveTopmostCall(MethodCall $methodCall): MethodCall + { + $currentMethodCall = $methodCall; + while ($currentMethodCall->var instanceof MethodCall) { + $currentMethodCall = $currentMethodCall->var; + } + + return $currentMethodCall; + } }