From 0a9f7c917deb15635023e6e03584e76dd0e3fea8 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 19 Nov 2024 14:50:35 +0100 Subject: [PATCH 1/2] [CodeQuality] Handle createMock as well in PreferPHPUnitThisCallRector --- .../Fixture/create_mock.php.inc | 31 +++++++++++++++++++ .../Class_/PreferPHPUnitThisCallRector.php | 21 ++++++++----- 2 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/create_mock.php.inc diff --git a/rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/create_mock.php.inc b/rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/create_mock.php.inc new file mode 100644 index 00000000..a9b8d44a --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/create_mock.php.inc @@ -0,0 +1,31 @@ + +----- +createMock('stdClass'); + } +} + +?> diff --git a/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php b/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php index db9214ce..7df19610 100644 --- a/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php +++ b/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php @@ -21,6 +21,11 @@ */ final class PreferPHPUnitThisCallRector extends AbstractRector { + /** + * @var string[] + */ + private const NON_ASSERT_STATIC_METHODS = ['createMock']; + public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, ) { @@ -75,9 +80,10 @@ public function refactor(Node $node): ?Node } $hasChanged = false; + $this->traverseNodesWithCallable($node, function (Node $node) use (&$hasChanged): int|null|MethodCall { - $isStatic = ($node instanceof ClassMethod && $node->isStatic()) || ($node instanceof Closure && $node->static); - if ($isStatic) { + $isInsideStaticFunctionLike = ($node instanceof ClassMethod && $node->isStatic()) || ($node instanceof Closure && $node->static); + if ($isInsideStaticFunctionLike) { return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; } @@ -85,20 +91,21 @@ public function refactor(Node $node): ?Node return null; } - $methodName = $this->getName($node->name); - if (! is_string($methodName)) { + if ($node->isFirstClassCallable()) { return null; } - if (! $this->isNames($node->class, ['static', 'self'])) { + + $methodName = $this->getName($node->name); + if (! is_string($methodName)) { return null; } - if (! str_starts_with($methodName, 'assert')) { + if (! $this->isNames($node->class, ['static', 'self'])) { return null; } - if ($node->isFirstClassCallable()) { + if (! str_starts_with($methodName, 'assert') && ! in_array($methodName, self::NON_ASSERT_STATIC_METHODS)) { return null; } From 68f76cec112eadcad343a85e39e4e6f3764f6417 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 19 Nov 2024 14:52:16 +0100 Subject: [PATCH 2/2] Covert expectations mock invoke as well --- composer.json | 4 +- rector.php | 11 ++---- .../Fixture/at_least_once.php.inc | 37 +++++++++++++++++++ .../Class_/PreferPHPUnitThisCallRector.php | 3 +- 4 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/at_least_once.php.inc diff --git a/composer.json b/composer.json index 40fc4c45..a0834909 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "php": ">=8.2" }, "require-dev": { - "rector/rector-src": "dev-main#e3ba39d", + "rector/rector-src": "dev-main", "phpunit/phpunit": "^10.5", "phpstan/phpstan": "^1.12", "symplify/phpstan-rules": "^13.0", @@ -17,7 +17,7 @@ "phpstan/phpstan-webmozart-assert": "^1.2", "symplify/vendor-patches": "^11.3", "tracy/tracy": "^2.10", - "tomasvotruba/class-leak": "^1.1.2", + "tomasvotruba/class-leak": "^1.2", "rector/type-perfect": "^1.0", "rector/swiss-knife": "^1.0" }, diff --git a/rector.php b/rector.php index 9d662ce0..be43a2aa 100644 --- a/rector.php +++ b/rector.php @@ -4,7 +4,6 @@ use Rector\Config\RectorConfig; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; -use Rector\PHPUnit\Set\PHPUnitSetList; return RectorConfig::configure() ->withImportNames(removeUnusedImports: true) @@ -30,7 +29,8 @@ __DIR__ . '/src/NodeFinder/DataProviderClassMethodFinder.php', ], ]) - ->withPhpSets(php82: true) + ->withPhpSets() + ->withAttributesSets(all: true) ->withPreparedSets( deadCode: true, codeQuality: true, @@ -39,12 +39,9 @@ naming: true, typeDeclarations: true, privatization: true, - rectorPreset: true + rectorPreset: true, + phpunitCodeQuality: true ) - ->withSets([ - PHPUnitSetList::PHPUNIT_100, - PHPUnitSetList::PHPUNIT_CODE_QUALITY, - ]) ->withConfiguredRule(StringClassNameToClassConstantRector::class, [ // keep unprefixed to protected from downgrade 'PHPUnit\Framework\*', diff --git a/rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/at_least_once.php.inc b/rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/at_least_once.php.inc new file mode 100644 index 00000000..827a121e --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector/Fixture/at_least_once.php.inc @@ -0,0 +1,37 @@ + +----- +once(); + $matcher = $this->atLeast(5); + $matcher = $this->never(); + $matcher = $this->atLeastOnce(); + } +} + +?> diff --git a/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php b/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php index 7df19610..e3eda8b3 100644 --- a/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php +++ b/rules/CodeQuality/Rector/Class_/PreferPHPUnitThisCallRector.php @@ -24,7 +24,7 @@ final class PreferPHPUnitThisCallRector extends AbstractRector /** * @var string[] */ - private const NON_ASSERT_STATIC_METHODS = ['createMock']; + private const NON_ASSERT_STATIC_METHODS = ['createMock', 'atLeast', 'atLeastOnce', 'once', 'never']; public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, @@ -95,7 +95,6 @@ public function refactor(Node $node): ?Node return null; } - $methodName = $this->getName($node->name); if (! is_string($methodName)) { return null;