sonarrradarrplexorganizrnginxdashboardlandingpagestartpagelandinghtpcserverhomepagesabnzbdheimdallembycouchpotatonzbgetbookmarkapplication-dashboardmuximux
		
		
		
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							468 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							468 lines
						
					
					
						
							12 KiB
						
					
					
				
								<?php
							 | 
						|
								
							 | 
						|
								namespace PhpParser\NodeVisitor;
							 | 
						|
								
							 | 
						|
								use PhpParser;
							 | 
						|
								use PhpParser\Node;
							 | 
						|
								use PhpParser\Node\Expr;
							 | 
						|
								use PhpParser\Node\Name;
							 | 
						|
								use PhpParser\Node\Stmt;
							 | 
						|
								
							 | 
						|
								class NameResolverTest extends \PHPUnit_Framework_TestCase
							 | 
						|
								{
							 | 
						|
								    private function canonicalize($string) {
							 | 
						|
								        return str_replace("\r\n", "\n", $string);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @covers PhpParser\NodeVisitor\NameResolver
							 | 
						|
								     */
							 | 
						|
								    public function testResolveNames() {
							 | 
						|
								        $code = <<<'EOC'
							 | 
						|
								<?php
							 | 
						|
								
							 | 
						|
								namespace Foo {
							 | 
						|
								    use Hallo as Hi;
							 | 
						|
								
							 | 
						|
								    new Bar();
							 | 
						|
								    new Hi();
							 | 
						|
								    new Hi\Bar();
							 | 
						|
								    new \Bar();
							 | 
						|
								    new namespace\Bar();
							 | 
						|
								
							 | 
						|
								    bar();
							 | 
						|
								    hi();
							 | 
						|
								    Hi\bar();
							 | 
						|
								    foo\bar();
							 | 
						|
								    \bar();
							 | 
						|
								    namespace\bar();
							 | 
						|
								}
							 | 
						|
								namespace {
							 | 
						|
								    use Hallo as Hi;
							 | 
						|
								
							 | 
						|
								    new Bar();
							 | 
						|
								    new Hi();
							 | 
						|
								    new Hi\Bar();
							 | 
						|
								    new \Bar();
							 | 
						|
								    new namespace\Bar();
							 | 
						|
								
							 | 
						|
								    bar();
							 | 
						|
								    hi();
							 | 
						|
								    Hi\bar();
							 | 
						|
								    foo\bar();
							 | 
						|
								    \bar();
							 | 
						|
								    namespace\bar();
							 | 
						|
								}
							 | 
						|
								namespace Bar {
							 | 
						|
								    use function foo\bar as baz;
							 | 
						|
								    use const foo\BAR as BAZ;
							 | 
						|
								    use foo as bar;
							 | 
						|
								
							 | 
						|
								    bar();
							 | 
						|
								    baz();
							 | 
						|
								    bar\foo();
							 | 
						|
								    baz\foo();
							 | 
						|
								    BAR();
							 | 
						|
								    BAZ();
							 | 
						|
								    BAR\FOO();
							 | 
						|
								    BAZ\FOO();
							 | 
						|
								
							 | 
						|
								    bar;
							 | 
						|
								    baz;
							 | 
						|
								    bar\foo;
							 | 
						|
								    baz\foo;
							 | 
						|
								    BAR;
							 | 
						|
								    BAZ;
							 | 
						|
								    BAR\FOO;
							 | 
						|
								    BAZ\FOO;
							 | 
						|
								}
							 | 
						|
								namespace Baz {
							 | 
						|
								    use A\T\{B\C, D\E};
							 | 
						|
								    use function X\T\{b\c, d\e};
							 | 
						|
								    use const Y\T\{B\C, D\E};
							 | 
						|
								    use Z\T\{G, function f, const K};
							 | 
						|
								
							 | 
						|
								    new C;
							 | 
						|
								    new E;
							 | 
						|
								    new C\D;
							 | 
						|
								    new E\F;
							 | 
						|
								    new G;
							 | 
						|
								
							 | 
						|
								    c();
							 | 
						|
								    e();
							 | 
						|
								    f();
							 | 
						|
								    C;
							 | 
						|
								    E;
							 | 
						|
								    K;
							 | 
						|
								}
							 | 
						|
								EOC;
							 | 
						|
								        $expectedCode = <<<'EOC'
							 | 
						|
								namespace Foo {
							 | 
						|
								    use Hallo as Hi;
							 | 
						|
								    new \Foo\Bar();
							 | 
						|
								    new \Hallo();
							 | 
						|
								    new \Hallo\Bar();
							 | 
						|
								    new \Bar();
							 | 
						|
								    new \Foo\Bar();
							 | 
						|
								    bar();
							 | 
						|
								    hi();
							 | 
						|
								    \Hallo\bar();
							 | 
						|
								    \Foo\foo\bar();
							 | 
						|
								    \bar();
							 | 
						|
								    \Foo\bar();
							 | 
						|
								}
							 | 
						|
								namespace {
							 | 
						|
								    use Hallo as Hi;
							 | 
						|
								    new \Bar();
							 | 
						|
								    new \Hallo();
							 | 
						|
								    new \Hallo\Bar();
							 | 
						|
								    new \Bar();
							 | 
						|
								    new \Bar();
							 | 
						|
								    \bar();
							 | 
						|
								    \hi();
							 | 
						|
								    \Hallo\bar();
							 | 
						|
								    \foo\bar();
							 | 
						|
								    \bar();
							 | 
						|
								    \bar();
							 | 
						|
								}
							 | 
						|
								namespace Bar {
							 | 
						|
								    use function foo\bar as baz;
							 | 
						|
								    use const foo\BAR as BAZ;
							 | 
						|
								    use foo as bar;
							 | 
						|
								    bar();
							 | 
						|
								    \foo\bar();
							 | 
						|
								    \foo\foo();
							 | 
						|
								    \Bar\baz\foo();
							 | 
						|
								    BAR();
							 | 
						|
								    \foo\bar();
							 | 
						|
								    \foo\FOO();
							 | 
						|
								    \Bar\BAZ\FOO();
							 | 
						|
								    bar;
							 | 
						|
								    baz;
							 | 
						|
								    \foo\foo;
							 | 
						|
								    \Bar\baz\foo;
							 | 
						|
								    BAR;
							 | 
						|
								    \foo\BAR;
							 | 
						|
								    \foo\FOO;
							 | 
						|
								    \Bar\BAZ\FOO;
							 | 
						|
								}
							 | 
						|
								namespace Baz {
							 | 
						|
								    use A\T\{B\C, D\E};
							 | 
						|
								    use function X\T\{b\c, d\e};
							 | 
						|
								    use const Y\T\{B\C, D\E};
							 | 
						|
								    use Z\T\{G, function f, const K};
							 | 
						|
								    new \A\T\B\C();
							 | 
						|
								    new \A\T\D\E();
							 | 
						|
								    new \A\T\B\C\D();
							 | 
						|
								    new \A\T\D\E\F();
							 | 
						|
								    new \Z\T\G();
							 | 
						|
								    \X\T\b\c();
							 | 
						|
								    \X\T\d\e();
							 | 
						|
								    \Z\T\f();
							 | 
						|
								    \Y\T\B\C;
							 | 
						|
								    \Y\T\D\E;
							 | 
						|
								    \Z\T\K;
							 | 
						|
								}
							 | 
						|
								EOC;
							 | 
						|
								
							 | 
						|
								        $parser        = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
							 | 
						|
								        $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
							 | 
						|
								        $traverser     = new PhpParser\NodeTraverser;
							 | 
						|
								        $traverser->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'
							 | 
						|
								<?php
							 | 
						|
								namespace NS;
							 | 
						|
								
							 | 
						|
								class A extends B implements C, D {
							 | 
						|
								    use E, F, G {
							 | 
						|
								        f as private g;
							 | 
						|
								        E::h as i;
							 | 
						|
								        E::j insteadof F, G;
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								interface A extends C, D {
							 | 
						|
								    public function a(A $a) : A;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function fn(A $a) : A {}
							 | 
						|
								function fn2(array $a) : array {}
							 | 
						|
								function(A $a) : A {};
							 | 
						|
								
							 | 
						|
								function fn3(?A $a) : ?A {}
							 | 
						|
								function fn4(?array $a) : ?array {}
							 | 
						|
								
							 | 
						|
								A::b();
							 | 
						|
								A::$b;
							 | 
						|
								A::B;
							 | 
						|
								new A;
							 | 
						|
								$a instanceof A;
							 | 
						|
								
							 | 
						|
								namespace\a();
							 | 
						|
								namespace\A;
							 | 
						|
								
							 | 
						|
								try {
							 | 
						|
								    $someThing;
							 | 
						|
								} catch (A $a) {
							 | 
						|
								    $someThingElse;
							 | 
						|
								}
							 | 
						|
								EOC;
							 | 
						|
								        $expectedCode = <<<'EOC'
							 | 
						|
								namespace NS;
							 | 
						|
								
							 | 
						|
								class A extends \NS\B implements \NS\C, \NS\D
							 | 
						|
								{
							 | 
						|
								    use \NS\E, \NS\F, \NS\G {
							 | 
						|
								        f as private g;
							 | 
						|
								        \NS\E::h as i;
							 | 
						|
								        \NS\E::j insteadof \NS\F, \NS\G;
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								interface A extends \NS\C, \NS\D
							 | 
						|
								{
							 | 
						|
								    public function a(\NS\A $a) : \NS\A;
							 | 
						|
								}
							 | 
						|
								function fn(\NS\A $a) : \NS\A
							 | 
						|
								{
							 | 
						|
								}
							 | 
						|
								function fn2(array $a) : array
							 | 
						|
								{
							 | 
						|
								}
							 | 
						|
								function (\NS\A $a) : \NS\A {
							 | 
						|
								};
							 | 
						|
								function fn3(?\NS\A $a) : ?\NS\A
							 | 
						|
								{
							 | 
						|
								}
							 | 
						|
								function fn4(?array $a) : ?array
							 | 
						|
								{
							 | 
						|
								}
							 | 
						|
								\NS\A::b();
							 | 
						|
								\NS\A::$b;
							 | 
						|
								\NS\A::B;
							 | 
						|
								new \NS\A();
							 | 
						|
								$a instanceof \NS\A;
							 | 
						|
								\NS\a();
							 | 
						|
								\NS\A;
							 | 
						|
								try {
							 | 
						|
								    $someThing;
							 | 
						|
								} catch (\NS\A $a) {
							 | 
						|
								    $someThingElse;
							 | 
						|
								}
							 | 
						|
								EOC;
							 | 
						|
								
							 | 
						|
								        $parser        = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
							 | 
						|
								        $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
							 | 
						|
								        $traverser     = new PhpParser\NodeTraverser;
							 | 
						|
								        $traverser->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->setExpectedException('PhpParser\Error', $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'
							 | 
						|
								<?php
							 | 
						|
								namespace Foo;
							 | 
						|
								use Bar\Baz;
							 | 
						|
								$test = new baz();
							 | 
						|
								EOC;
							 | 
						|
								
							 | 
						|
								        $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
							 | 
						|
								        $stmts = $parser->parse($source);
							 | 
						|
								
							 | 
						|
								        $traverser = new PhpParser\NodeTraverser;
							 | 
						|
								        $traverser->addVisitor(new NameResolver);
							 | 
						|
								
							 | 
						|
								        $stmts = $traverser->traverse($stmts);
							 | 
						|
								        $stmt = $stmts[0];
							 | 
						|
								
							 | 
						|
								        $this->assertSame(array('Bar', 'Baz'), $stmt->stmts[1]->expr->class->parts);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function testSpecialClassNamesAreCaseInsensitive() {
							 | 
						|
								        $source = <<<'EOC'
							 | 
						|
								<?php
							 | 
						|
								namespace Foo;
							 | 
						|
								
							 | 
						|
								class Bar
							 | 
						|
								{
							 | 
						|
								    public static function method()
							 | 
						|
								    {
							 | 
						|
								        SELF::method();
							 | 
						|
								        PARENT::method();
							 | 
						|
								        STATIC::method();
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								EOC;
							 | 
						|
								
							 | 
						|
								        $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
							 | 
						|
								        $stmts = $parser->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]->class);
							 | 
						|
								        $this->assertSame('PARENT', (string)$methodStmt->stmts[1]->class);
							 | 
						|
								        $this->assertSame('STATIC', (string)$methodStmt->stmts[2]->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'));
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 |