Skip to content

Commit 381efbb

Browse files
committed
Implement DynamicCallToAssertionIgnoreExtension
1 parent 5e30669 commit 381efbb

File tree

5 files changed

+125
-0
lines changed

5 files changed

+125
-0
lines changed

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,13 @@ services:
7272
-
7373
class: PHPStan\Type\PHPUnit\DataProviderReturnTypeIgnoreExtension
7474

75+
-
76+
class: PHPStan\Type\PHPUnit\DynamicCallToAssertionIgnoreExtension
77+
7578
conditionalTags:
7679
PHPStan\PhpDoc\PHPUnit\MockObjectTypeNodeResolverExtension:
7780
phpstan.phpDoc.typeNodeResolverExtension: %phpunit.convertUnionToIntersectionType%
7881
PHPStan\Type\PHPUnit\DataProviderReturnTypeIgnoreExtension:
7982
phpstan.ignoreErrorExtension: [%featureToggles.bleedingEdge%, not(%phpunit.reportMissingDataProviderReturnType%)]
83+
PHPStan\Type\PHPUnit\DynamicCallToAssertionIgnoreExtension:
84+
phpstan.ignoreErrorExtension: %featureToggles.bleedingEdge%
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 PHPUnit\Framework\TestCase;
10+
use function is_string;
11+
use function str_starts_with;
12+
13+
final class DynamicCallToAssertionIgnoreExtension implements IgnoreErrorExtension
14+
{
15+
16+
public function shouldIgnore(Error $error, Node $node, Scope $scope): bool
17+
{
18+
if (!$node instanceof Node\Expr\MethodCall) {
19+
return false;
20+
}
21+
22+
if (!$node->var instanceof Node\Expr\Variable) {
23+
return false;
24+
}
25+
26+
if (!is_string($node->var->name) || $node->var->name !== 'this') {
27+
return false;
28+
}
29+
30+
if ($error->getIdentifier() !== 'staticMethod.dynamicCall') {
31+
return false;
32+
}
33+
34+
if (
35+
!$node->name instanceof Node\Identifier
36+
|| !str_starts_with($node->name->name, 'assert')
37+
) {
38+
return false;
39+
}
40+
41+
if (!$scope->isInClass()) {
42+
return false;
43+
}
44+
45+
$classReflection = $scope->getClassReflection();
46+
return $classReflection->is(TestCase::class);
47+
}
48+
49+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\PHPUnit;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsRule;
7+
use PHPStan\Testing\RuleTestCase;
8+
9+
/**
10+
* @extends RuleTestCase<DynamicCallOnStaticMethodsRule>
11+
*/
12+
class DynamicCallToAssertionIgnoreExtensionTest extends RuleTestCase
13+
{
14+
15+
protected function getRule(): Rule
16+
{
17+
/** @phpstan-ignore phpstanApi.classConstant */
18+
return self::getContainer()->getByType(DynamicCallOnStaticMethodsRule::class);
19+
}
20+
21+
public function testRule(): void
22+
{
23+
$this->analyse([__DIR__ . '/data/dynamic-call-to-assertion.php'], [
24+
[
25+
'Dynamic call to static method DynamicCallToAssertion\Foo::staticFn().',
26+
17,
27+
],
28+
]);
29+
}
30+
31+
public static function getAdditionalConfigFiles(): array
32+
{
33+
return [
34+
__DIR__ . '/data/dynamic-call-to-assertion.neon',
35+
];
36+
}
37+
38+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
parameters:
2+
featureToggles:
3+
bleedingEdge: true
4+
5+
includes:
6+
- ../../../../extension.neon
7+
8+
services:
9+
-
10+
class: PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsRule
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace DynamicCallToAssertion;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
class Foo extends TestCase {
8+
public function testFoo(bool $b):void {
9+
$this->assertTrue($b);
10+
}
11+
12+
public function testBar(bool $b):void {
13+
self::assertTrue($b);
14+
}
15+
16+
public function foo():void {
17+
$x = $this->staticFn();
18+
}
19+
20+
static protected function staticFn():bool {
21+
return true;
22+
}
23+
}

0 commit comments

Comments
 (0)