Skip to content

Commit f1cc911

Browse files
committed
Rule for checking matching type between switch condition and case condition
1 parent 8c5f82a commit f1cc911

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

rules.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ services:
3636
class: PHPStan\Rules\StrictCalls\StrictFunctionCallsRule
3737
tags:
3838
- phpstan.rules.rule
39+
40+
-
41+
class: PHPStan\Rules\SwitchConditions\MatchingTypeInSwitchCaseConditionRule
42+
tags:
43+
- phpstan.rules.rule
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\Rules\SwitchConditions;
4+
5+
class MatchingTypeInSwitchCaseConditionRule implements \PHPStan\Rules\Rule
6+
{
7+
8+
/** @var \PhpParser\PrettyPrinter\Standard */
9+
private $printer;
10+
11+
public function __construct(\PhpParser\PrettyPrinter\Standard $printer)
12+
{
13+
$this->printer = $printer;
14+
}
15+
16+
public function getNodeType(): string
17+
{
18+
return \PhpParser\Node\Stmt\Switch_::class;
19+
}
20+
21+
/**
22+
* @param \PhpParser\Node\Stmt\Switch_ $node
23+
* @param \PHPStan\Analyser\Scope $scope
24+
* @return string[] errors
25+
*/
26+
public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array
27+
{
28+
$messages = [];
29+
$conditionType = $scope->getType($node->cond);
30+
foreach ($node->cases as $case) {
31+
if ($case->cond === null) {
32+
continue;
33+
}
34+
35+
$caseType = $scope->getType($case->cond);
36+
if ($conditionType->isSupersetOf($caseType)->no()) {
37+
$messages[] = sprintf(
38+
'Switch condition type (%s) does not match case condition %s (%s).',
39+
$conditionType->describe(),
40+
$this->printer->prettyPrintExpr($case->cond),
41+
$caseType->describe()
42+
);
43+
}
44+
}
45+
46+
return $messages;
47+
}
48+
49+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\SwitchConditions;
4+
5+
use PHPStan\Rules\Rule;
6+
7+
class MatchingTypeInSwitchCaseConditionRuleTest extends \PHPStan\Testing\RuleTestCase
8+
{
9+
10+
protected function getRule(): Rule
11+
{
12+
return new MatchingTypeInSwitchCaseConditionRule(new \PhpParser\PrettyPrinter\Standard());
13+
}
14+
15+
public function testRule()
16+
{
17+
$this->analyse([__DIR__ . '/data/matching-type.php'], [
18+
[
19+
'Switch condition type (int) does not match case condition \'test\' (string).',
20+
8,
21+
],
22+
[
23+
'Switch condition type (int) does not match case condition 1 > 2 (bool).',
24+
8,
25+
],
26+
[
27+
'Switch condition type (string) does not match case condition 1 (int).',
28+
19,
29+
],
30+
[
31+
'Switch condition type (string) does not match case condition 1 > 2 (bool).',
32+
19,
33+
],
34+
]);
35+
}
36+
37+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace SwitchConditions;
4+
5+
$int = 1;
6+
$string = '1';
7+
8+
switch ($int) {
9+
case 1:
10+
break;
11+
case 'test':
12+
break;
13+
case 1 > 2:
14+
break;
15+
default:
16+
return;
17+
}
18+
19+
switch ($string) {
20+
case 1:
21+
break;
22+
case 'test':
23+
break;
24+
case 1 > 2:
25+
break;
26+
default:
27+
return;
28+
}

0 commit comments

Comments
 (0)