From fd5827c0a72bb46a7ce69ecfab4f0e01e46b466c Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Wed, 11 May 2022 22:49:34 +0200 Subject: [PATCH] Fix endless recursion with nested traits via anonymous classes --- src/Analyser/MutatingScope.php | 11 ++++++++++ src/Analyser/NodeScopeResolver.php | 12 +++++++++++ .../Analyser/AnalyserIntegrationTest.php | 8 +++++++ tests/PHPStan/Analyser/data/bug-7214.php | 21 +++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 tests/PHPStan/Analyser/data/bug-7214.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 5f73560bd7..601e0fac45 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3176,6 +3176,17 @@ public function enterClass(ClassReflection $classReflection): self [ 'this' => VariableTypeHolder::createYes(new ThisType($classReflection)), ], + [], + [], + null, + null, + true, + [], + [], + [], + [], + false, + $classReflection->isAnonymous() ? $this : null, ); } diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 3d25b2bf98..dc02481948 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3725,8 +3725,20 @@ static function (): void { */ private function processTraitUse(Node\Stmt\TraitUse $node, MutatingScope $classScope, callable $nodeCallback): void { + $parentTraitNames = []; + $parent = $classScope->getParentScope(); + while ($parent !== null) { + if ($parent->isInTrait()) { + $parentTraitNames[] = $parent->getTraitReflection()->getName(); + } + $parent = $parent->getParentScope(); + } + foreach ($node->traits as $trait) { $traitName = (string) $trait; + if (in_array($traitName, $parentTraitNames, true)) { + continue; + } if (!$this->reflectionProvider->hasClass($traitName)) { continue; } diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index bdbc0b5413..007df3888e 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -800,6 +800,14 @@ public function testDiscussion7124(): void $this->assertSame(59, $errors[3]->getLine()); } + public function testBug7214(): void + { + $errors = $this->runAnalyse(__DIR__ . '/data/bug-7214.php'); + $this->assertCount(1, $errors); + $this->assertSame('Method Bug7214\HelloWorld::getFoo() has no return type specified.', $errors[0]->getMessage()); + $this->assertSame(6, $errors[0]->getLine()); + } + /** * @param string[]|null $allAnalysedFiles * @return Error[] diff --git a/tests/PHPStan/Analyser/data/bug-7214.php b/tests/PHPStan/Analyser/data/bug-7214.php new file mode 100644 index 0000000000..a5f336356e --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-7214.php @@ -0,0 +1,21 @@ +getFoo()->getFoo()); +};