mirror of
https://github.com/danog/PHP-Parser.git
synced 2025-01-21 21:31:29 +01:00
Fully Cover and fix NameResolver
Previously type hints were not resolved due to a typo. Also trait uses were not resolved.
This commit is contained in:
parent
df691065a6
commit
94d4c30a72
@ -10,11 +10,11 @@ class PHPParser_Node_Stmt_UseUse extends PHPParser_Node_Stmt
|
||||
* Constructs an alias (use) node.
|
||||
*
|
||||
* @param PHPParser_Node_Name $name Namespace/Class to alias
|
||||
* @param string $alias Alias
|
||||
* @param null|string $alias Alias
|
||||
* @param int $line Line
|
||||
* @param null|string $docComment Nearest doc comment
|
||||
*/
|
||||
public function __construct(PHPParser_Node_Name $name, $alias, $line = -1, $docComment = null) {
|
||||
public function __construct(PHPParser_Node_Name $name, $alias = null, $line = -1, $docComment = null) {
|
||||
if (null === $alias) {
|
||||
$alias = $name->getLast();
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class PHPParser_NodeVisitor_NameResolver extends PHPParser_NodeVisitorAbstract
|
||||
if (isset($this->aliases[$node->alias])) {
|
||||
throw new PHPParser_Error(
|
||||
sprintf(
|
||||
'Cannot use %s as %s because the name is already in use',
|
||||
'Cannot use "%s" as "%s" because the name is already in use',
|
||||
$node->name, $node->alias
|
||||
),
|
||||
$node->getLine()
|
||||
@ -72,8 +72,12 @@ class PHPParser_NodeVisitor_NameResolver extends PHPParser_NodeVisitorAbstract
|
||||
if ($node->name instanceof PHPParser_Node_Name) {
|
||||
$node->name = $this->resolveOtherName($node->name);
|
||||
}
|
||||
} elseif ($node instanceof PHPParser_Node_Stmt_TraitUse) {
|
||||
foreach ($node->traits as &$trait) {
|
||||
$trait = $this->resolveClassName($trait);
|
||||
}
|
||||
} elseif ($node instanceof PHPParser_Node_Param
|
||||
&& $node instanceof PHPParser_Node_Name
|
||||
&& $node->type instanceof PHPParser_Node_Name
|
||||
) {
|
||||
$node->type = $this->resolveClassName($node->type);
|
||||
}
|
||||
|
@ -87,68 +87,132 @@ EOC;
|
||||
/**
|
||||
* @covers PHPParser_NodeVisitor_NameResolver
|
||||
*/
|
||||
public function testAddNamespacedName() {
|
||||
public function testResolveLocations() {
|
||||
$code = <<<EOC
|
||||
<?php
|
||||
namespace NS {
|
||||
class A extends B implements C {
|
||||
use A;
|
||||
}
|
||||
|
||||
namespace Foo {
|
||||
class A {}
|
||||
interface B {}
|
||||
function D() {}
|
||||
const E = 'F';
|
||||
interface A extends C {
|
||||
public function a(A \$a);
|
||||
}
|
||||
|
||||
A::b();
|
||||
A::\$b;
|
||||
A::B;
|
||||
new A;
|
||||
\$a instanceof A;
|
||||
|
||||
namespace\a();
|
||||
namespace\A;
|
||||
}
|
||||
namespace {
|
||||
class A {}
|
||||
interface B {}
|
||||
function D() {}
|
||||
const E = 'F';
|
||||
EOC;
|
||||
$expectedCode = <<<EOC
|
||||
namespace NS {
|
||||
class A extends \\NS\\B implements \\NS\\C
|
||||
{
|
||||
use \\NS\\A;
|
||||
}
|
||||
interface A extends \\NS\\C
|
||||
{
|
||||
public function a(\\NS\\A \$a);
|
||||
}
|
||||
\\NS\\A::b();
|
||||
\\NS\\A::\$b;
|
||||
\\NS\\A::B;
|
||||
new \\NS\\A();
|
||||
\$a instanceof \\NS\\A;
|
||||
\\NS\\a();
|
||||
\\NS\\A;
|
||||
}
|
||||
EOC;
|
||||
|
||||
$parser = new PHPParser_Parser;
|
||||
$prettyPrinter = new PHPParser_PrettyPrinter_Zend;
|
||||
$traverser = new PHPParser_NodeTraverser;
|
||||
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver);
|
||||
|
||||
$stmts = $parser->parse(new PHPParser_Lexer($code));
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
|
||||
$this->assertEquals('Foo\\A', (string) $stmts[0]->stmts[0]->namespacedName);
|
||||
$this->assertEquals('Foo\\B', (string) $stmts[0]->stmts[1]->namespacedName);
|
||||
$this->assertEquals('Foo\\D', (string) $stmts[0]->stmts[2]->namespacedName);
|
||||
$this->assertEquals('Foo\\E', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
||||
$this->assertEquals('A', (string) $stmts[1]->stmts[0]->namespacedName);
|
||||
$this->assertEquals('B', (string) $stmts[1]->stmts[1]->namespacedName);
|
||||
$this->assertEquals('D', (string) $stmts[1]->stmts[2]->namespacedName);
|
||||
$this->assertEquals('E', (string) $stmts[1]->stmts[3]->consts[0]->namespacedName);
|
||||
$this->assertEquals($expectedCode, $prettyPrinter->prettyPrint($stmts));
|
||||
}
|
||||
|
||||
public function testNoResolveSpecialName() {
|
||||
$stmts = array(new PHPParser_Node_Expr_New(new PHPParser_Node_Name('self')));
|
||||
|
||||
$traverser = new PHPParser_NodeTraverser;
|
||||
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver);
|
||||
|
||||
$this->assertEquals($stmts, $traverser->traverse($stmts));
|
||||
}
|
||||
|
||||
protected function createNamespacedAndNonNamespaced(array $stmts) {
|
||||
return array(
|
||||
new PHPParser_Node_Stmt_Namespace(new PHPParser_Node_Name('NS'), $stmts),
|
||||
new PHPParser_Node_Stmt_Namespace(null, $stmts),
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddNamespacedName() {
|
||||
$stmts = $this->createNamespacedAndNonNamespaced(array(
|
||||
new PHPParser_Node_Stmt_Class('A'),
|
||||
new PHPParser_Node_Stmt_Interface('B'),
|
||||
new PHPParser_Node_Stmt_Function('C'),
|
||||
new PHPParser_Node_Stmt_Const(array(
|
||||
new PHPParser_Node_Const('D', new PHPParser_Node_Scalar_String('E'))
|
||||
)),
|
||||
));
|
||||
|
||||
$traverser = new PHPParser_NodeTraverser;
|
||||
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver);
|
||||
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
|
||||
$this->assertEquals('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
|
||||
$this->assertEquals('NS\\B', (string) $stmts[0]->stmts[1]->namespacedName);
|
||||
$this->assertEquals('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName);
|
||||
$this->assertEquals('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
||||
$this->assertEquals('A', (string) $stmts[1]->stmts[0]->namespacedName);
|
||||
$this->assertEquals('B', (string) $stmts[1]->stmts[1]->namespacedName);
|
||||
$this->assertEquals('C', (string) $stmts[1]->stmts[2]->namespacedName);
|
||||
$this->assertEquals('D', (string) $stmts[1]->stmts[3]->consts[0]->namespacedName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers PHPParser_NodeVisitor_NameResolver
|
||||
*/
|
||||
public function testAddTraitNamespacedName() {
|
||||
if (!version_compare(PHP_VERSION, '5.4.0RC1', '>=')) {
|
||||
$this->markTestSkipped('The test requires PHP 5.4');
|
||||
}
|
||||
|
||||
$code = <<<EOC
|
||||
<?php
|
||||
$stmts = $this->createNamespacedAndNonNamespaced(array(
|
||||
new PHPParser_Node_Stmt_Trait('A')
|
||||
));
|
||||
|
||||
namespace Foo {
|
||||
trait C {}
|
||||
}
|
||||
namespace {
|
||||
trait C {}
|
||||
}
|
||||
EOC;
|
||||
|
||||
$parser = new PHPParser_Parser;
|
||||
$traverser = new PHPParser_NodeTraverser;
|
||||
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver);
|
||||
|
||||
$stmts = $parser->parse(new PHPParser_Lexer($code));
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
|
||||
$this->assertEquals('Foo\\C', (string) $stmts[0]->stmts[0]->namespacedName);
|
||||
$this->assertEquals('C', (string) $stmts[1]->stmts[0]->namespacedName);
|
||||
$this->assertEquals('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
|
||||
$this->assertEquals('A', (string) $stmts[1]->stmts[0]->namespacedName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException PHPParser_Error
|
||||
* @expectedExceptionMessage Cannot use "C" as "B" because the name is already in use on line 2
|
||||
*/
|
||||
public function testAlreadyInUseError() {
|
||||
$stmts = array(
|
||||
new PHPParser_Node_Stmt_Use(array(
|
||||
new PHPParser_Node_Stmt_UseUse(new PHPParser_Node_Name('A\B'), 'B', 1),
|
||||
new PHPParser_Node_Stmt_UseUse(new PHPParser_Node_Name('C'), 'B', 2),
|
||||
))
|
||||
);
|
||||
|
||||
$traverser = new PHPParser_NodeTraverser;
|
||||
$traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver);
|
||||
$traverser->traverse($stmts);
|
||||
}
|
||||
}
|
@ -68,8 +68,6 @@ XML;
|
||||
|
||||
/**
|
||||
* @dataProvider provideTestErrors
|
||||
* @expectedException DomainException
|
||||
* @expectedExceptionMessage false, true and null scalars must be empty elements
|
||||
*/
|
||||
public function testErrors($xml, $errorMsg) {
|
||||
$this->setExpectedException('DomainException', $errorMsg);
|
||||
|
Loading…
x
Reference in New Issue
Block a user