addVisitor(new NameResolver); $stmts = $parser->parse($code); $stmts = $traverser->traverse($stmts); $this->assertSame( $this->canonicalize($expectedCode), $prettyPrinter->prettyPrint($stmts) ); } /** * @covers PhpParser\NodeVisitor\NameResolver */ public function testResolveLocations() { $code = <<<'EOC' addVisitor(new NameResolver); $stmts = $parser->parse($code); $stmts = $traverser->traverse($stmts); $this->assertSame( $this->canonicalize($expectedCode), $prettyPrinter->prettyPrint($stmts) ); } public function testNoResolveSpecialName() { $stmts = array(new Node\Expr\New_(new Name('self'))); $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver); $this->assertEquals($stmts, $traverser->traverse($stmts)); } public function testAddDeclarationNamespacedName() { $nsStmts = array( new Stmt\Class_('A'), new Stmt\Interface_('B'), new Stmt\Function_('C'), new Stmt\Const_(array( new Node\Const_('D', new Node\Scalar\LNumber(42)) )), new Stmt\Trait_('E'), new Expr\New_(new Stmt\Class_(null)), ); $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver); $stmts = $traverser->traverse([new Stmt\Namespace_(new Name('NS'), $nsStmts)]); $this->assertSame('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName); $this->assertSame('NS\\B', (string) $stmts[0]->stmts[1]->namespacedName); $this->assertSame('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName); $this->assertSame('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName); $this->assertSame('NS\\E', (string) $stmts[0]->stmts[4]->namespacedName); $this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class); $stmts = $traverser->traverse([new Stmt\Namespace_(null, $nsStmts)]); $this->assertSame('A', (string) $stmts[0]->stmts[0]->namespacedName); $this->assertSame('B', (string) $stmts[0]->stmts[1]->namespacedName); $this->assertSame('C', (string) $stmts[0]->stmts[2]->namespacedName); $this->assertSame('D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName); $this->assertSame('E', (string) $stmts[0]->stmts[4]->namespacedName); $this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class); } public function testAddRuntimeResolvedNamespacedName() { $stmts = array( new Stmt\Namespace_(new Name('NS'), array( new Expr\FuncCall(new Name('foo')), new Expr\ConstFetch(new Name('FOO')), )), new Stmt\Namespace_(null, array( new Expr\FuncCall(new Name('foo')), new Expr\ConstFetch(new Name('FOO')), )), ); $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver); $stmts = $traverser->traverse($stmts); $this->assertSame('NS\\foo', (string) $stmts[0]->stmts[0]->name->getAttribute('namespacedName')); $this->assertSame('NS\\FOO', (string) $stmts[0]->stmts[1]->name->getAttribute('namespacedName')); $this->assertFalse($stmts[1]->stmts[0]->name->hasAttribute('namespacedName')); $this->assertFalse($stmts[1]->stmts[1]->name->hasAttribute('namespacedName')); } /** * @dataProvider provideTestError */ public function testError(Node $stmt, $errorMsg) { $this->expectException('PhpParser\Error'); $this->expectExceptionMessage($errorMsg); $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver); $traverser->traverse(array($stmt)); } public function provideTestError() { return array( array( new Stmt\Use_(array( new Stmt\UseUse(new Name('A\B'), 'B', 0, array('startLine' => 1)), new Stmt\UseUse(new Name('C\D'), 'B', 0, array('startLine' => 2)), ), Stmt\Use_::TYPE_NORMAL), 'Cannot use C\D as B because the name is already in use on line 2' ), array( new Stmt\Use_(array( new Stmt\UseUse(new Name('a\b'), 'b', 0, array('startLine' => 1)), new Stmt\UseUse(new Name('c\d'), 'B', 0, array('startLine' => 2)), ), Stmt\Use_::TYPE_FUNCTION), 'Cannot use function c\d as B because the name is already in use on line 2' ), array( new Stmt\Use_(array( new Stmt\UseUse(new Name('A\B'), 'B', 0, array('startLine' => 1)), new Stmt\UseUse(new Name('C\D'), 'B', 0, array('startLine' => 2)), ), Stmt\Use_::TYPE_CONSTANT), 'Cannot use const C\D as B because the name is already in use on line 2' ), array( new Expr\New_(new Name\FullyQualified('self', array('startLine' => 3))), "'\\self' is an invalid class name on line 3" ), array( new Expr\New_(new Name\Relative('self', array('startLine' => 3))), "'\\self' is an invalid class name on line 3" ), array( new Expr\New_(new Name\FullyQualified('PARENT', array('startLine' => 3))), "'\\PARENT' is an invalid class name on line 3" ), array( new Expr\New_(new Name\Relative('STATIC', array('startLine' => 3))), "'\\STATIC' is an invalid class name on line 3" ), ); } public function testClassNameIsCaseInsensitive() { $source = <<<'EOC' parse($source); $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver); $stmts = $traverser->traverse($stmts); $stmt = $stmts[0]; $assign = $stmt->stmts[1]->expr; $this->assertSame(array('Bar', 'Baz'), $assign->expr->class->parts); } public function testSpecialClassNamesAreCaseInsensitive() { $source = <<<'EOC' parse($source); $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver); $stmts = $traverser->traverse($stmts); $classStmt = $stmts[0]; $methodStmt = $classStmt->stmts[0]->stmts[0]; $this->assertSame('SELF', (string)$methodStmt->stmts[0]->expr->class); $this->assertSame('PARENT', (string)$methodStmt->stmts[1]->expr->class); $this->assertSame('STATIC', (string)$methodStmt->stmts[2]->expr->class); } public function testAddOriginalNames() { $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver(null, ['preserveOriginalNames' => true])); $n1 = new Name('Bar'); $n2 = new Name('bar'); $origStmts = [ new Stmt\Namespace_(new Name('Foo'), [ new Expr\ClassConstFetch($n1, 'FOO'), new Expr\FuncCall($n2), ]) ]; $stmts = $traverser->traverse($origStmts); $this->assertSame($n1, $stmts[0]->stmts[0]->class->getAttribute('originalName')); $this->assertSame($n2, $stmts[0]->stmts[1]->name->getAttribute('originalName')); } public function testAttributeOnlyMode() { $traverser = new PhpParser\NodeTraverser; $traverser->addVisitor(new NameResolver(null, ['replaceNodes' => false])); $n1 = new Name('Bar'); $n2 = new Name('bar'); $origStmts = [ new Stmt\Namespace_(new Name('Foo'), [ new Expr\ClassConstFetch($n1, 'FOO'), new Expr\FuncCall($n2), ]) ]; $traverser->traverse($origStmts); $this->assertEquals( new Name\FullyQualified('Foo\Bar'), $n1->getAttribute('resolvedName')); $this->assertFalse($n2->hasAttribute('resolvedName')); $this->assertEquals( new Name\FullyQualified('Foo\bar'), $n2->getAttribute('namespacedName')); } }