1
0
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:
nikic 2011-12-10 12:11:53 +01:00
parent df691065a6
commit 94d4c30a72
4 changed files with 110 additions and 44 deletions

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);