Skip to content

Commit 3d365fc

Browse files
committed
WrongVariableNameInVarTagRule - fix iteratee variable above foreach
1 parent 8b2bc59 commit 3d365fc

7 files changed

Lines changed: 63 additions & 9 deletions

File tree

src/Analyser/NodeScopeResolver.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2897,6 +2897,9 @@ private function processVarAnnotation(MutatingScope $scope, array $variableNames
28972897

28982898
private function enterForeach(MutatingScope $scope, Foreach_ $stmt): MutatingScope
28992899
{
2900+
if ($stmt->expr instanceof Variable && is_string($stmt->expr->name)) {
2901+
$scope = $this->processVarAnnotation($scope, [$stmt->expr->name], $stmt);
2902+
}
29002903
$iterateeType = $scope->getType($stmt->expr);
29012904
$vars = [];
29022905
if ($stmt->valueVar instanceof Variable && is_string($stmt->valueVar->name)) {

src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public function processNode(Node $node, Scope $scope): array
6262
}
6363

6464
if ($node instanceof Node\Stmt\Foreach_) {
65-
return $this->processForeach($node->keyVar, $node->valueVar, $varTags);
65+
return $this->processForeach($node->expr, $node->keyVar, $node->valueVar, $varTags);
6666
}
6767

6868
if ($node instanceof Node\Stmt\Static_) {
@@ -168,9 +168,12 @@ private function getAssignedVariables(Expr $expr): array
168168
* @param \PHPStan\PhpDoc\Tag\VarTag[] $varTags
169169
* @return \PHPStan\Rules\RuleError[]
170170
*/
171-
private function processForeach(?Node\Expr $keyVar, Node\Expr $valueVar, array $varTags): array
171+
private function processForeach(Node\Expr $iterateeExpr, ?Node\Expr $keyVar, Node\Expr $valueVar, array $varTags): array
172172
{
173173
$variableNames = [];
174+
if ($iterateeExpr instanceof Node\Expr\Variable && is_string($iterateeExpr->name)) {
175+
$variableNames[] = $iterateeExpr->name;
176+
}
174177
if ($keyVar instanceof Node\Expr\Variable && is_string($keyVar->name)) {
175178
$variableNames[] = $keyVar->name;
176179
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4776,7 +4776,7 @@ public function dataForeachArrayType(): array
47764776
],
47774777
[
47784778
__DIR__ . '/data/foreach/type-in-comment-no-variable-2.php',
4779-
'mixed',
4779+
'*ERROR*',
47804780
'$value',
47814781
],
47824782
[
@@ -10758,6 +10758,11 @@ public function dataBug4500(): array
1075810758
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4500.php');
1075910759
}
1076010760

10761+
public function dataBug4504(): array
10762+
{
10763+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4504.php');
10764+
}
10765+
1076110766
/**
1076210767
* @param string $file
1076310768
* @return array<string, mixed[]>
@@ -10972,6 +10977,7 @@ private function gatherAssertTypes(string $file): array
1097210977
* @dataProvider dataBug4415
1097310978
* @dataProvider dataCompact
1097410979
* @dataProvider dataBug4500
10980+
* @dataProvider dataBug4504
1097510981
* @param string $assertType
1097610982
* @param string $file
1097710983
* @param mixed ...$args
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Bug4504TypeInference;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
class Foo
8+
{
9+
10+
public function sayHello($models): void
11+
{
12+
/** @var \Iterator<A> $models */
13+
foreach ($models as $k => $v) {
14+
assertType('Bug4504TypeInference\A', $v);
15+
}
16+
17+
assertType('array()|Iterator<mixed, Bug4504TypeInference\A>', $models);
18+
}
19+
20+
}
21+

tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,7 @@ public function testRule(): void
3131
23,
3232
],
3333
[
34-
'Variable $list in PHPDoc tag @var does not match any variable in the foreach loop: $key, $var',
35-
29,
36-
],
37-
[
38-
'Variable $foo in PHPDoc tag @var does not match any variable in the foreach loop: $key, $val',
34+
'Variable $foo in PHPDoc tag @var does not match any variable in the foreach loop: $list, $key, $val',
3935
66,
4036
],
4137
[
@@ -86,6 +82,10 @@ public function testRule(): void
8682
'Variable $foo in PHPDoc tag @var does not exist.',
8783
210,
8884
],
85+
[
86+
'PHPDoc tag @var above foreach loop does not specify variable name.',
87+
234,
88+
],
8989
[
9090
'Variable $foo in PHPDoc tag @var does not exist.',
9191
248,
@@ -151,4 +151,9 @@ public function testBug4500(): void
151151
]);
152152
}
153153

154+
public function testBug4504(): void
155+
{
156+
$this->analyse([__DIR__ . '/data/bug-4504.php'], []);
157+
}
158+
154159
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Bug4504;
4+
5+
class Foo
6+
{
7+
8+
public function sayHello($models): void
9+
{
10+
/** @var \Iterator<A> $models */
11+
foreach ($models as $k => $v) {
12+
13+
}
14+
}
15+
16+
}

tests/PHPStan/Rules/PhpDoc/data/wrong-variable-name-var.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function doFoo()
2626
public function doBar(array $list)
2727
{
2828
/** @var int[] $list */
29-
foreach ($list as $key => $var) { // ERROR
29+
foreach ($list as $key => $var) {
3030

3131
}
3232

0 commit comments

Comments
 (0)