Skip to content

Commit eb5ecd6

Browse files
staabmphpstan-bot
authored andcommitted
Fix phpstan/phpstan#14439: infinite loop with @extends parent<T>
- Use native reflection instead of getParentClass() when resolving `parent` type in TypeNodeResolver - getParentClass() resolves @extends PHPDoc tags, which can create infinite recursion when the tag itself uses `parent` - New integration test in tests/PHPStan/Analyser/AnalyserIntegrationTest.php
1 parent f570f88 commit eb5ecd6

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

src/PhpDoc/TypeNodeResolver.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,9 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
483483
case 'parent':
484484
if ($this->getReflectionProvider()->hasClass($nameScope->getClassName())) {
485485
$classReflection = $this->getReflectionProvider()->getClass($nameScope->getClassName());
486-
if ($classReflection->getParentClass() !== null) {
487-
return new ObjectType($classReflection->getParentClass()->getName());
486+
$parentClass = $classReflection->getNativeReflection()->getParentClass();
487+
if ($parentClass !== false) {
488+
return new ObjectType($parentClass->getName());
488489
}
489490
}
490491

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,13 @@ public function testBug8835(): void
15131513
$this->assertNoErrors($errors);
15141514
}
15151515

1516+
public function testBug14439(): void
1517+
{
1518+
// endless loop crash with @extends parent<T>
1519+
$errors = $this->runAnalyse(__DIR__ . '/data/bug-14439.php');
1520+
$this->assertNoErrors($errors);
1521+
}
1522+
15161523
/**
15171524
* @param string[]|null $allAnalysedFiles
15181525
* @return list<Error>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug14439;
4+
5+
/**
6+
* @template T
7+
*/
8+
abstract class AbstractBar
9+
{
10+
}
11+
12+
/**
13+
* @template T
14+
* @extends parent<T>
15+
*/
16+
abstract class AbstractFoo extends AbstractBar
17+
{
18+
}
19+
20+
/**
21+
* @template T of int
22+
* @extends parent<T>
23+
*/
24+
class Foo extends AbstractFoo
25+
{
26+
}

0 commit comments

Comments
 (0)