Skip to content

Commit

Permalink
Fixed infinite recursion with a class and trait in the same file
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 2, 2017
1 parent 72f4084 commit 928d80a
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 5 deletions.
1 change: 1 addition & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<arg value="--encoding=utf-8"/>
<arg value="--tab-width=4"/>
<arg value="--ignore=tests/*/data"/>
<arg value="--ignore=tests/*/traits"/>
<arg value="-sp"/>
<arg path="src"/>
<arg path="tests"/>
Expand Down
34 changes: 29 additions & 5 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1028,11 +1028,35 @@ private function processTraitUse(Node\Stmt\TraitUse $node, Scope $classScope, \C
$classScope->getClass() !== null ? sprintf('class %s', $classScope->getClass()) : 'anonymous class'
)
);
$this->processNodes($parserNodes, new Scope($this->broker, $this->printer, $fileName), function (\PhpParser\Node $node) use ($traitName, $classScope, $nodeCallback) {
if ($node instanceof Node\Stmt\Trait_ && $traitName === (string) $node->namespacedName) {
$this->processNodes($node->stmts, $classScope->enterFirstLevelStatements(), $nodeCallback);
}
});

$this->processNodesForTraitUse($parserNodes, $traitName, $classScope, $nodeCallback);
}
}

/**
* @param \PhpParser\Node[]|\PhpParser\Node $node
* @param string $traitName
* @param \PHPStan\Analyser\Scope $classScope
* @param \Closure $nodeCallback
*/
private function processNodesForTraitUse($node, string $traitName, Scope $classScope, \Closure $nodeCallback)
{
if ($node instanceof Node) {
if ($node instanceof Node\Stmt\Trait_ && $traitName === (string) $node->namespacedName) {
$this->processNodes($node->stmts, $classScope->enterFirstLevelStatements(), $nodeCallback);
return;
}
if ($node instanceof Node\Stmt\ClassLike) {
return;
}
foreach ($node->getSubNodeNames() as $subNodeName) {
$subNode = $node->{$subNodeName};
$this->processNodesForTraitUse($subNode, $traitName, $classScope, $nodeCallback);
}
} elseif (is_array($node)) {
foreach ($node as $subNode) {
$this->processNodesForTraitUse($subNode, $traitName, $classScope, $nodeCallback);
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/AnalyserTraitsIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ public function testTraitsAreNotAnalysedDirectly()
$this->assertEmpty($errors);
}

public function testClassAndTraitInTheSameFile()
{
$errors = $this->runAnalyse(__DIR__ . '/traits/classAndTrait.php');
$this->assertEmpty($errors);
}

/**
* @param string $file
* @return \PHPStan\Analyser\Error[]|string[]
Expand Down
15 changes: 15 additions & 0 deletions tests/PHPStan/Analyser/traits/classAndTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace ClassAndTrait;

class Foo
{

use FooTrait;

}

trait FooTrait
{

}

0 comments on commit 928d80a

Please sign in to comment.