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