1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Fix #334 by allowing interfaces as foreach args to be correctly interpreted

This commit is contained in:
Matthew Brown 2017-11-24 12:57:00 -05:00
parent c86e73ddb6
commit 18e68a60de
2 changed files with 58 additions and 3 deletions

View File

@ -5,6 +5,7 @@ use PhpParser;
use Psalm\Checker\ClassChecker;
use Psalm\Checker\ClassLikeChecker;
use Psalm\Checker\CommentChecker;
use Psalm\Checker\InterfaceChecker;
use Psalm\Checker\MethodChecker;
use Psalm\Checker\Statements\Expression\AssignmentChecker;
use Psalm\Checker\Statements\ExpressionChecker;
@ -178,7 +179,15 @@ class ForeachChecker
$project_checker,
$iterator_type->value,
'Iterator'
)) {
) ||
(InterfaceChecker::interfaceExists($project_checker, $iterator_type->value)
&& InterfaceChecker::interfaceExtends(
$project_checker,
$iterator_type->value,
'Iterator'
)
)
) {
$iterator_method = $iterator_type->value . '::current';
$iterator_class_type = MethodChecker::getMethodReturnType($project_checker, $iterator_method);
@ -202,11 +211,20 @@ class ForeachChecker
$project_checker,
$iterator_type->value,
'Traversable'
)) {
) ||
(InterfaceChecker::interfaceExists($project_checker, $iterator_type->value)
&& InterfaceChecker::interfaceExtends(
$project_checker,
$iterator_type->value,
'Traversable'
)
)
) {
// @todo try and get value type
} elseif (!in_array(
strtolower($iterator_type->value),
['iterator', 'iterable', 'traversable'], true
['iterator', 'iterable', 'traversable'],
true
)) {
if (IssueBuffer::accepts(
new RawObjectIteration(

View File

@ -4,6 +4,43 @@ namespace Psalm\Tests;
class ForeachTest extends TestCase
{
use Traits\FileCheckerInvalidCodeParseTestTrait;
use Traits\FileCheckerValidCodeParseTestTrait;
/**
* @return array
*/
public function providerFileCheckerValidCodeParse()
{
return [
'iteratorAggregateIteration' => [
'<?php
class C implements IteratorAggregate
{
public function getIterator(): Iterator
{
return new ArrayIterator([]);
}
}
function loopT(Traversable $coll): void
{
foreach ($coll as $item) {}
}
function loopI(IteratorAggregate $coll): void
{
foreach ($coll as $item) {}
}
loopT(new C);
loopI(new C);',
'assignments' => [],
'error_levels' => [
'MixedAssignment', 'UndefinedThisPropertyAssignment',
],
],
];
}
/**
* @return array