Skip to content

Commit

Permalink
Fixed type seen by IterableInForeachRule with inline @var right above…
Browse files Browse the repository at this point in the history
… foreach
  • Loading branch information
ondrejmirtes committed Feb 5, 2022
1 parent d5e6df7 commit b6bbbaf
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
use PHPStan\Node\InClassMethodNode;
use PHPStan\Node\InClassNode;
use PHPStan\Node\InClosureNode;
use PHPStan\Node\InForeachNode;
use PHPStan\Node\InFunctionNode;
use PHPStan\Node\InstantiationCallableNode;
use PHPStan\Node\LiteralArrayItem;
Expand Down Expand Up @@ -765,6 +766,11 @@ private function processStmtNode(
$stmt->expr,
new Array_([]),
);
$inForeachScope = $scope;
if ($stmt->expr instanceof Variable && is_string($stmt->expr->name)) {
$inForeachScope = $this->processVarAnnotation($scope, [$stmt->expr->name], $stmt);
}
$nodeCallback(new InForeachNode($stmt), $inForeachScope);
$bodyScope = $this->enterForeach($scope->filterByTruthyValue($arrayComparisonExpr), $stmt);
$count = 0;
do {
Expand Down
34 changes: 34 additions & 0 deletions src/Node/InForeachNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node\Stmt\Foreach_;
use PhpParser\NodeAbstract;

class InForeachNode extends NodeAbstract implements VirtualNode
{

public function __construct(private Foreach_ $originalNode)
{
parent::__construct($originalNode->getAttributes());
}

public function getOriginalNode(): Foreach_
{
return $this->originalNode;
}

public function getType(): string
{
return 'PHPStan_Node_InForeachNode';
}

/**
* @return string[]
*/
public function getSubNodeNames(): array
{
return [];
}

}
10 changes: 6 additions & 4 deletions src/Rules/Arrays/IterableInForeachRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InForeachNode;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
Expand All @@ -13,7 +14,7 @@
use function sprintf;

/**
* @implements Rule<Node\Stmt\Foreach_>
* @implements Rule<InForeachNode>
*/
class IterableInForeachRule implements Rule
{
Expand All @@ -24,14 +25,15 @@ public function __construct(private RuleLevelHelper $ruleLevelHelper)

public function getNodeType(): string
{
return Node\Stmt\Foreach_::class;
return InForeachNode::class;
}

public function processNode(Node $node, Scope $scope): array
{
$originalNode = $node->getOriginalNode();
$typeResult = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$node->expr,
$originalNode->expr,
'Iterating over an object of an unknown class %s.',
static fn (Type $type): bool => $type->isIterable()->yes(),
);
Expand All @@ -47,7 +49,7 @@ public function processNode(Node $node, Scope $scope): array
RuleErrorBuilder::message(sprintf(
'Argument of an invalid type %s supplied for foreach, only iterables are supported.',
$type->describe(VerbosityLevel::typeOnly()),
))->line($node->expr->getLine())->build(),
))->line($originalNode->expr->getLine())->build(),
];
}

Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,10 @@ public function testRuleWithNullsafeVariant(): void
]);
}

public function testBug6564(): void
{
$this->checkExplicitMixed = true;
$this->analyse([__DIR__ . '/data/bug-6564.php'], []);
}

}
20 changes: 20 additions & 0 deletions tests/PHPStan/Rules/Arrays/data/bug-6564.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Bug6564;

class HelloWorld
{
public function exportFileDataProvider(mixed $value): void
{
if ($this->isValueIterable()) {
/** @var mixed[] $value */
foreach ($value as $_value) {
}
}


}
public function isValueIterable(): bool {
return true;
}
}

0 comments on commit b6bbbaf

Please sign in to comment.