Skip to content

Commit d3993ea

Browse files
authored
[rules] Add NoMissingVariableDimFetchRule (#254)
1 parent 00c87d1 commit d3993ea

File tree

8 files changed

+150
-0
lines changed

8 files changed

+150
-0
lines changed

config/code-complexity-rules.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ rules:
44
- Symplify\PHPStanRules\Rules\Complexity\NoArrayMapWithArrayCallableRule
55
- Symplify\PHPStanRules\Rules\Complexity\NoConstructorOverrideRule
66
- Symplify\PHPStanRules\Rules\Complexity\ForeachCeptionRule
7+
- Symplify\PHPStanRules\Rules\Explicit\NoMissingVariableDimFetchRule

src/Enum/RuleIdentifier.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,6 @@ final class RuleIdentifier
7777
public const NO_ARRAY_MAP_WITH_ARRAY_CALLABLE = 'symplify.noArrayMapWithArrayCallable';
7878

7979
public const RULE_IDENTIFIER = 'symplify.foreachCeption';
80+
81+
public const NO_MISSING_VARIABLE_DIM_FETCH = 'symplify.noMissingVariableDimFetch';
8082
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symplify\PHPStanRules\Rules\Explicit;
6+
7+
use PhpParser\Node\Expr\Variable;
8+
use PHPStan\Rules\RuleErrorBuilder;
9+
use PhpParser\Node;
10+
use PhpParser\Node\Expr\ArrayDimFetch;
11+
use PhpParser\Node\Expr\Assign;
12+
use PHPStan\Analyser\Scope;
13+
use PHPStan\Rules\Rule;
14+
use Symplify\PHPStanRules\Enum\RuleIdentifier;
15+
16+
/**
17+
* @implements Rule<Assign>
18+
* @see \Symplify\PHPStanRules\Tests\Rules\Explicit\NoMissingVariableDimFetchRule\NoMissingVariableDimFetchRuleTest
19+
*/
20+
final class NoMissingVariableDimFetchRule implements Rule
21+
{
22+
/**
23+
* @api
24+
* @var string
25+
*/
26+
public const ERROR_MESSAGE = 'Dim fetch assign variable is missing, create it first';
27+
28+
public function getNodeType(): string
29+
{
30+
return Assign::class;
31+
}
32+
33+
/**
34+
* @param Assign $node
35+
*/
36+
public function processNode(Node $node, Scope $scope): array
37+
{
38+
if (! $node->var instanceof ArrayDimFetch) {
39+
return [];
40+
}
41+
42+
$arrayDimFetch = $node->var;
43+
if (! $arrayDimFetch->var instanceof Variable) {
44+
return [];
45+
}
46+
47+
$dimFetchVariable = $arrayDimFetch->var;
48+
49+
if (! is_string($dimFetchVariable->name)) {
50+
return [];
51+
}
52+
53+
if (! $scope->hasVariableType($dimFetchVariable->name)->no()) {
54+
return [];
55+
}
56+
57+
$identifierRuleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
58+
->identifier(RuleIdentifier::NO_MISSING_VARIABLE_DIM_FETCH)
59+
->build();
60+
61+
return [$identifierRuleError];
62+
}
63+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Symplify\PHPStanRules\Tests\Rules\Explicit\NoMissingVariableDimFetchRule\Fixture;
4+
5+
final class MissingDimFetch
6+
{
7+
public function some()
8+
{
9+
$dim['key'] = 'value';
10+
}
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Symplify\PHPStanRules\Tests\Rules\Explicit\NoMissingVariableDimFetchRule\Fixture;
4+
5+
final class SkipDefinedVariable
6+
{
7+
public function some()
8+
{
9+
$dim = [];
10+
$dim['key'] = 'value';
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Symplify\PHPStanRules\Tests\Rules\Explicit\NoMissingVariableDimFetchRule\Fixture;
4+
5+
final class SkipProperty
6+
{
7+
private $someProperty = [];
8+
9+
public function some()
10+
{
11+
$this->someProperty['key'] = 'value';
12+
}
13+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symplify\PHPStanRules\Tests\Rules\Explicit\NoMissingVariableDimFetchRule;
6+
7+
use Iterator;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Testing\RuleTestCase;
10+
use PHPUnit\Framework\Attributes\DataProvider;
11+
use Symplify\PHPStanRules\Rules\Explicit\NoMissingVariableDimFetchRule;
12+
13+
final class NoMissingVariableDimFetchRuleTest extends RuleTestCase
14+
{
15+
#[DataProvider('provideData')]
16+
public function testRule(string $filePath, array $expectedErrorsWithLines): void
17+
{
18+
$this->analyse([$filePath], $expectedErrorsWithLines);
19+
}
20+
21+
public static function provideData(): Iterator
22+
{
23+
yield [__DIR__ . '/Fixture/SkipDefinedVariable.php', []];
24+
yield [__DIR__ . '/Fixture/SkipProperty.php', []];
25+
26+
yield [__DIR__ . '/Fixture/MissingDimFetch.php', [
27+
[NoMissingVariableDimFetchRule::ERROR_MESSAGE, 9],
28+
]];
29+
}
30+
31+
/**
32+
* @return string[]
33+
*/
34+
public static function getAdditionalConfigFiles(): array
35+
{
36+
return [__DIR__ . '/config/configured_rule.neon'];
37+
}
38+
39+
protected function getRule(): Rule
40+
{
41+
return self::getContainer()->getByType(NoMissingVariableDimFetchRule::class);
42+
}
43+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
includes:
2+
- ../../../../config/included_services.neon
3+
4+
rules:
5+
- Symplify\PHPStanRules\Rules\Explicit\NoMissingVariableDimFetchRule

0 commit comments

Comments
 (0)