Skip to content

Commit

Permalink
Fixed situation where ancestors appeared multiple times in the hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 3, 2020
1 parent b6e90d6 commit 65e578c
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 6 deletions.
20 changes: 14 additions & 6 deletions src/Reflection/ClassReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -826,25 +826,33 @@ private function getAncestors(): array
$this->getName() => $this,
];

$addToAncestors = static function (string $name, ClassReflection $classReflection) use (&$ancestors): void {
if (array_key_exists($name, $ancestors)) {
return;
}

$ancestors[$name] = $classReflection;
};

foreach ($this->getInterfaces() as $interface) {
$ancestors[$interface->getName()] = $interface;
$addToAncestors($interface->getName(), $interface);
foreach ($interface->getAncestors() as $name => $ancestor) {
$ancestors[$name] = $ancestor;
$addToAncestors($name, $ancestor);
}
}

foreach ($this->getTraits() as $trait) {
$ancestors[$trait->getName()] = $trait;
$addToAncestors($trait->getName(), $trait);
foreach ($trait->getAncestors() as $name => $ancestor) {
$ancestors[$name] = $ancestor;
$addToAncestors($name, $ancestor);
}
}

$parent = $this->getParentClass();
if ($parent !== false) {
$ancestors[$parent->getName()] = $parent;
$addToAncestors($parent->getName(), $parent);
foreach ($parent->getAncestors() as $name => $ancestor) {
$ancestors[$name] = $ancestor;
$addToAncestors($name, $ancestor);
}
}

Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9773,6 +9773,11 @@ public function dataBug2648(): array
return $this->gatherAssertTypes(__DIR__ . '/data/bug-2648.php');
}

public function dataBug2740(): array
{
return $this->gatherAssertTypes(__DIR__ . '/data/bug-2740.php');
}

/**
* @dataProvider dataBug2574
* @dataProvider dataBug2577
Expand All @@ -9791,6 +9796,7 @@ public function dataBug2648(): array
* @dataProvider dataPsalmPrefixedTagsWithUnresolvableTypes
* @dataProvider dataComplexGenericsExample
* @dataProvider dataBug2648
* @dataProvider dataBug2740
* @param ConstantStringType $expectedType
* @param Type $actualType
*/
Expand Down
12 changes: 12 additions & 0 deletions tests/PHPStan/Analyser/data/bug-2740.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Bug2740;

use function PHPStan\Analyser\assertType;

function (Member $member): void
{
foreach ($member as $i) {
assertType('Bug2740\Member', $i);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,9 @@ public function testRule(): void
]);
}

public function testIndirectInheritanceBug2740(): void
{
$this->analyse([__DIR__ . '/data/bug2740.php'], []);
}

}
66 changes: 66 additions & 0 deletions tests/PHPStan/Rules/Methods/data/bug2740.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace Bug2740;

/**
* A collection that can contain members.
*
* @extends \IteratorAggregate<int,Member>
*/
interface Collection extends \IteratorAggregate
{
}

/**
* A member of a collection. Also a collection containing only itself.
*
* In the real world, this would contain additional methods.
*/
interface Member extends Collection
{

}

class MemberImpl implements Member
{

/**
* @return \Iterator<int,Member>
*/
public function getIterator(): \Iterator
{
return new \ArrayIterator([$this]);
}

}

class CollectionImpl implements Collection
{

/**
* @var array<int,Member>
*/
private $members;

public function __construct(Member ...$members)
{
$this->members = $members;
}

/**
* @return Member
*/
public function getMember(): Member
{
return new MemberImpl();
}

/**
* @return \Iterator<int,Member>
*/
public function getIterator(): \Iterator
{
return new \ArrayIterator($this->members);
}

}

0 comments on commit 65e578c

Please sign in to comment.