Skip to content

Commit 22c6949

Browse files
committed
Make phpunit.dataProviderStatic auto-fixable
1 parent d35895e commit 22c6949

File tree

7 files changed

+86
-7
lines changed

7 files changed

+86
-7
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
],
88
"require": {
99
"php": "^7.4 || ^8.0",
10-
"phpstan/phpstan": "^2.0.4"
10+
"phpstan/phpstan": "^2.1.18"
1111
},
1212
"conflict": {
1313
"phpunit/phpunit": "<7.0"

extension.neon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ services:
5454
factory: @PHPStan\Rules\PHPUnit\DataProviderHelperFactory::create()
5555
-
5656
class: PHPStan\Rules\PHPUnit\DataProviderHelperFactory
57+
arguments:
58+
parser: @defaultAnalysisParser
5759

5860
conditionalTags:
5961
PHPStan\PhpDoc\PHPUnit\MockObjectTypeNodeResolverExtension:

src/Rules/PHPUnit/DataProviderHelper.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
namespace PHPStan\Rules\PHPUnit;
44

5+
use PhpParser\Modifiers;
56
use PhpParser\Node\Attribute;
67
use PhpParser\Node\Expr\ClassConstFetch;
78
use PhpParser\Node\Name;
89
use PhpParser\Node\Scalar\String_;
910
use PhpParser\Node\Stmt\ClassMethod;
11+
use PhpParser\NodeFinder;
1012
use PHPStan\Analyser\Scope;
13+
use PHPStan\Parser\Parser;
1114
use PHPStan\PhpDoc\ResolvedPhpDocBlock;
1215
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
1316
use PHPStan\Reflection\ClassReflection;
@@ -37,16 +40,20 @@ class DataProviderHelper
3740
*/
3841
private FileTypeMapper $fileTypeMapper;
3942

43+
private Parser $parser;
44+
4045
private bool $phpunit10OrNewer;
4146

4247
public function __construct(
4348
ReflectionProvider $reflectionProvider,
4449
FileTypeMapper $fileTypeMapper,
50+
Parser $parser,
4551
bool $phpunit10OrNewer
4652
)
4753
{
4854
$this->reflectionProvider = $reflectionProvider;
4955
$this->fileTypeMapper = $fileTypeMapper;
56+
$this->parser = $parser;
5057
$this->phpunit10OrNewer = $phpunit10OrNewer;
5158
}
5259

@@ -188,13 +195,28 @@ public function processDataProvider(
188195
}
189196

190197
if ($deprecationRulesInstalled && $this->phpunit10OrNewer && !$dataProviderMethodReflection->isStatic()) {
191-
$errors[] = RuleErrorBuilder::message(sprintf(
198+
$errorBuilder = RuleErrorBuilder::message(sprintf(
192199
'@dataProvider %s related method must be static in PHPUnit 10 and newer.',
193200
$dataProviderValue,
194201
))
195202
->line($lineNumber)
196-
->identifier('phpunit.dataProviderStatic')
197-
->build();
203+
->identifier('phpunit.dataProviderStatic');
204+
205+
$dataProviderMethodReflectionDeclaringClass = $dataProviderMethodReflection->getDeclaringClass();
206+
if ($dataProviderMethodReflectionDeclaringClass->getFileName() !== null) {
207+
$stmts = $this->parser->parseFile($dataProviderMethodReflectionDeclaringClass->getFileName());
208+
$nodeFinder = new NodeFinder();
209+
/** @var ClassMethod|null $methodNode */
210+
$methodNode = $nodeFinder->findFirst($stmts, static fn ($node) => $node instanceof ClassMethod && $node->name->toString() === $dataProviderMethodReflection->getName());
211+
if ($methodNode !== null) {
212+
$errorBuilder->fixNode($methodNode, static function (ClassMethod $methodNode) {
213+
$methodNode->flags |= Modifiers::STATIC;
214+
215+
return $methodNode;
216+
});
217+
}
218+
}
219+
$errors[] = $errorBuilder->build();
198220
}
199221

200222
return $errors;

src/Rules/PHPUnit/DataProviderHelperFactory.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\PHPUnit;
44

5+
use PHPStan\Parser\Parser;
56
use PHPStan\Reflection\ReflectionProvider;
67
use PHPStan\Type\FileTypeMapper;
78
use PHPUnit\Framework\TestCase;
@@ -18,10 +19,17 @@ class DataProviderHelperFactory
1819

1920
private FileTypeMapper $fileTypeMapper;
2021

21-
public function __construct(ReflectionProvider $reflectionProvider, FileTypeMapper $fileTypeMapper)
22+
private Parser $parser;
23+
24+
public function __construct(
25+
ReflectionProvider $reflectionProvider,
26+
FileTypeMapper $fileTypeMapper,
27+
Parser $parser
28+
)
2229
{
2330
$this->reflectionProvider = $reflectionProvider;
2431
$this->fileTypeMapper = $fileTypeMapper;
32+
$this->parser = $parser;
2533
}
2634

2735
public function create(): DataProviderHelper
@@ -49,7 +57,7 @@ public function create(): DataProviderHelper
4957
}
5058
}
5159

52-
return new DataProviderHelper($this->reflectionProvider, $this->fileTypeMapper, $phpUnit10OrNewer);
60+
return new DataProviderHelper($this->reflectionProvider, $this->fileTypeMapper, $this->parser, $phpUnit10OrNewer);
5361
}
5462

5563
}

tests/Rules/PHPUnit/DataProviderDeclarationRuleTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protected function getRule(): Rule
1717
$reflection = $this->createReflectionProvider();
1818

1919
return new DataProviderDeclarationRule(
20-
new DataProviderHelper($reflection, self::getContainer()->getByType(FileTypeMapper::class),true),
20+
new DataProviderHelper($reflection, self::getContainer()->getByType(FileTypeMapper::class), self::getContainer()->getService('defaultAnalysisParser'), true),
2121
true,
2222
true
2323
);
@@ -65,6 +65,11 @@ public function testRule(): void
6565
]);
6666
}
6767

68+
public function testFixDataProviderStatic(): void
69+
{
70+
$this->fix(__DIR__ . '/data/data-provider-static-fix.php', __DIR__ . '/data/data-provider-static-fix.php.fixed');
71+
}
72+
6873
/**
6974
* @return string[]
7075
*/
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace DataProviderStaticFix;
4+
5+
class FixTestCase extends \PHPUnit\Framework\TestCase
6+
{
7+
8+
public function dataProvide(): iterable
9+
{
10+
yield [];
11+
}
12+
13+
/**
14+
* @dataProvider dataProvide
15+
*/
16+
public function testFoo(): void
17+
{
18+
19+
}
20+
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace DataProviderStaticFix;
4+
5+
class FixTestCase extends \PHPUnit\Framework\TestCase
6+
{
7+
8+
public static function dataProvide(): iterable
9+
{
10+
yield [];
11+
}
12+
13+
/**
14+
* @dataProvider dataProvide
15+
*/
16+
public function testFoo(): void
17+
{
18+
19+
}
20+
21+
}

0 commit comments

Comments
 (0)