Skip to content

Commit 4984270

Browse files
committed
ImpossibleCheckTypeStaticMethodCallRule - respect reportAlwaysTrueInLastCondition
1 parent 0115f49 commit 4984270

File tree

4 files changed

+80
-9
lines changed

4 files changed

+80
-9
lines changed

conf/config.level4.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ services:
120120
arguments:
121121
checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall%
122122
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
123+
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
123124
tags:
124125
- phpstan.rules.rule
125126

src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function __construct(
2222
private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper,
2323
private bool $checkAlwaysTrueCheckTypeFunctionCall,
2424
private bool $treatPhpDocTypesAsCertain,
25+
private bool $reportAlwaysTrueInLastCondition,
2526
)
2627
{
2728
}
@@ -67,20 +68,23 @@ public function processNode(Node $node, Scope $scope): array
6768
)))->build(),
6869
];
6970
} elseif ($this->checkAlwaysTrueCheckTypeFunctionCall) {
70-
if ($node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME) === true) {
71+
$isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME);
72+
if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) {
7173
return [];
7274
}
7375

7476
$method = $this->getMethod($node->class, $node->name->name, $scope);
77+
$errorBuilder = $addTip(RuleErrorBuilder::message(sprintf(
78+
'Call to static method %s::%s()%s will always evaluate to true.',
79+
$method->getDeclaringClass()->getDisplayName(),
80+
$method->getName(),
81+
$this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()),
82+
)));
83+
if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) {
84+
$errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.');
85+
}
7586

76-
return [
77-
$addTip(RuleErrorBuilder::message(sprintf(
78-
'Call to static method %s::%s()%s will always evaluate to true.',
79-
$method->getDeclaringClass()->getDisplayName(),
80-
$method->getName(),
81-
$this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()),
82-
)))->build(),
83-
];
87+
return [$errorBuilder->build()];
8488
}
8589

8690
return [];

tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class ImpossibleCheckTypeStaticMethodCallRuleTest extends RuleTestCase
1313

1414
private bool $treatPhpDocTypesAsCertain;
1515

16+
private bool $reportAlwaysTrueInLastCondition = false;
17+
1618
public function getRule(): Rule
1719
{
1820
return new ImpossibleCheckTypeStaticMethodCallRule(
@@ -25,6 +27,7 @@ public function getRule(): Rule
2527
),
2628
true,
2729
$this->treatPhpDocTypesAsCertain,
30+
$this->reportAlwaysTrueInLastCondition,
2831
);
2932
}
3033

@@ -64,6 +67,7 @@ public function testRule(): void
6467
[
6568
'Call to static method ImpossibleStaticMethodCall\ConditionalAlwaysTrue::isInt() with int will always evaluate to true.',
6669
66,
70+
'Remove remaining cases below this one and this error will disappear too.',
6771
],
6872
]);
6973
}
@@ -109,6 +113,38 @@ public function testAssertUnresolvedGeneric(): void
109113
$this->analyse([__DIR__ . '/data/assert-unresolved-generic.php'], []);
110114
}
111115

116+
public function dataReportAlwaysTrueInLastCondition(): iterable
117+
{
118+
yield [false, [
119+
[
120+
'Call to static method PHPStan\Tests\AssertionClass::assertInt() with int will always evaluate to true.',
121+
23,
122+
'Remove remaining cases below this one and this error will disappear too.',
123+
],
124+
]];
125+
yield [true, [
126+
[
127+
'Call to static method PHPStan\Tests\AssertionClass::assertInt() with int will always evaluate to true.',
128+
14,
129+
],
130+
[
131+
'Call to static method PHPStan\Tests\AssertionClass::assertInt() with int will always evaluate to true.',
132+
23,
133+
],
134+
]];
135+
}
136+
137+
/**
138+
* @dataProvider dataReportAlwaysTrueInLastCondition
139+
* @param list<array{0: string, 1: int, 2?: string}> $expectedErrors
140+
*/
141+
public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLastCondition, array $expectedErrors): void
142+
{
143+
$this->treatPhpDocTypesAsCertain = true;
144+
$this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition;
145+
$this->analyse([__DIR__ . '/data/impossible-static-method-report-always-true-last-condition.php'], $expectedErrors);
146+
}
147+
112148
public static function getAdditionalConfigFiles(): array
113149
{
114150
return [
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace ImpossibleStaticMethodReportAlwaysTrueLastCondition;
4+
5+
use PHPStan\Tests\AssertionClass;
6+
7+
class Foo
8+
{
9+
10+
public function doFoo(int $i)
11+
{
12+
if (rand(0, 1)) {
13+
14+
} elseif (AssertionClass::assertInt($i)) {
15+
16+
}
17+
}
18+
19+
public function doBar(int $i)
20+
{
21+
if (rand(0, 1)) {
22+
23+
} elseif (AssertionClass::assertInt($i)) {
24+
25+
} else {
26+
27+
}
28+
}
29+
30+
}

0 commit comments

Comments
 (0)