Skip to content

Commit a9bcc21

Browse files
committed
Ignore missingType.iterableValue for data-providers
1 parent 53e33fc commit a9bcc21

File tree

6 files changed

+166
-4
lines changed

6 files changed

+166
-4
lines changed

data-provider-iterable-value.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace DataProviderIterableValueTest;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
class Foo extends TestCase {
8+
/**
9+
* @dataProvider dataProvider
10+
* @dataProvider dataProvider2
11+
*/
12+
public function testFoo() {
13+
14+
}
15+
16+
public function dataProvider(): iterable {
17+
return [
18+
[1, 2],
19+
[3, 4],
20+
[5, 6],
21+
];
22+
}
23+
24+
public function dataProvider2(): iterable {
25+
$i = rand(0, 10);
26+
27+
return [
28+
[$i, 2],
29+
];
30+
}
31+
32+
public function dataProvider3(): iterable {
33+
$i = rand(0, 10);
34+
35+
return [
36+
[$i, 2],
37+
];
38+
}
39+
40+
private function returnsMixed(): mixed {
41+
return rand(0, 1) ? [[1, 2]] : "string";
42+
}
43+
}

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ services:
6767
arguments:
6868
parser: @defaultAnalysisParser
6969

70+
-
71+
class: PHPStan\Type\PHPUnit\DataProviderReturnTypeIgnoreExtension
72+
tags:
73+
- phpstan.ignoreErrorExtension
74+
7075
conditionalTags:
7176
PHPStan\PhpDoc\PHPUnit\MockObjectTypeNodeResolverExtension:
7277
phpstan.phpDoc.typeNodeResolverExtension: %phpunit.convertUnionToIntersectionType%

src/Rules/PHPUnit/DataProviderHelper.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,23 @@ public function __construct(
5353
}
5454

5555
/**
56-
* @param ReflectionMethod|ClassMethod $node
56+
* @param ReflectionMethod|ClassMethod $testMethod
5757
*
5858
* @return iterable<array{ClassReflection|null, string, int}>
5959
*/
6060
public function getDataProviderMethods(
6161
Scope $scope,
62-
$node,
62+
$testMethod,
6363
ClassReflection $classReflection
6464
): iterable
6565
{
66-
yield from $this->yieldDataProviderAnnotations($node, $scope, $classReflection);
66+
yield from $this->yieldDataProviderAnnotations($testMethod, $scope, $classReflection);
6767

6868
if (!$this->phpunit10OrNewer) {
6969
return;
7070
}
7171

72-
yield from $this->yieldDataProviderAttributes($node, $classReflection);
72+
yield from $this->yieldDataProviderAttributes($testMethod, $classReflection);
7373
}
7474

7575
/**
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\PHPUnit;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Error;
7+
use PHPStan\Analyser\IgnoreErrorExtension;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Node\InClassMethodNode;
10+
use PHPStan\Rules\PHPUnit\DataProviderHelper;
11+
use PHPStan\Rules\PHPUnit\TestMethodsHelper;
12+
13+
final class DataProviderReturnTypeIgnoreExtension implements IgnoreErrorExtension
14+
{
15+
16+
private TestMethodsHelper $testMethodsHelper;
17+
18+
private DataProviderHelper $dataProviderHelper;
19+
20+
public function __construct(
21+
TestMethodsHelper $testMethodsHelper,
22+
DataProviderHelper $dataProviderHelper
23+
)
24+
{
25+
$this->testMethodsHelper = $testMethodsHelper;
26+
$this->dataProviderHelper = $dataProviderHelper;
27+
}
28+
29+
public function shouldIgnore(Error $error, Node $node, Scope $scope): bool
30+
{
31+
if (! $node instanceof InClassMethodNode) { // @phpstan-ignore phpstanApi.instanceofAssumption
32+
return false;
33+
}
34+
35+
if ($error->getIdentifier() !== 'missingType.iterableValue') {
36+
return false;
37+
}
38+
39+
$classReflection = $node->getClassReflection();
40+
$methodReflection = $node->getMethodReflection();
41+
$testMethods = $this->testMethodsHelper->getTestMethods($classReflection, $scope);
42+
foreach ($testMethods as $testMethod) {
43+
foreach ($this->dataProviderHelper->getDataProviderMethods($scope, $testMethod, $classReflection) as [, $providerMethodName]) {
44+
if ($providerMethodName === $methodReflection->getName()) {
45+
return true;
46+
}
47+
}
48+
}
49+
50+
return false;
51+
}
52+
53+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\PHPUnit;
4+
5+
use PHPStan\Rules\Methods\MissingMethodReturnTypehintRule;
6+
use PHPStan\Rules\Rule;
7+
use PHPStan\Testing\RuleTestCase;
8+
9+
/**
10+
* @extends RuleTestCase<MissingMethodReturnTypehintRule>
11+
*/
12+
class DataProviderReturnTypeIgnoreExtensionTest extends RuleTestCase {
13+
protected function getRule(): Rule
14+
{
15+
/** @phpstan-ignore phpstanApi.classConstant */
16+
$rule = self::getContainer()->getByType(MissingMethodReturnTypehintRule::class);
17+
return $rule;
18+
}
19+
20+
public function testRule(): void
21+
{
22+
$this->analyse([__DIR__ . '/data/data-provider-iterable-value.php'], [
23+
]);
24+
}
25+
26+
static public function getAdditionalConfigFiles(): array
27+
{
28+
return [__DIR__ . '/../../../extension.neon'];
29+
}
30+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace DataProviderIterableValueTest;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
class Foo extends TestCase {
8+
/**
9+
* @dataProvider dataProvider
10+
* @dataProvider dataProvider2
11+
*/
12+
public function testFoo():void {
13+
14+
}
15+
16+
public function dataProvider(): iterable {
17+
return [
18+
[1, 2],
19+
[3, 4],
20+
[5, 6],
21+
];
22+
}
23+
24+
public function dataProvider2(): iterable {
25+
$i = rand(0, 10);
26+
27+
return [
28+
[$i, 2],
29+
];
30+
}
31+
}

0 commit comments

Comments
 (0)