diff --git a/lib/PhpParser/PrettyPrinter/Standard.php b/lib/PhpParser/PrettyPrinter/Standard.php index 9db5b099..7c32e5a3 100644 --- a/lib/PhpParser/PrettyPrinter/Standard.php +++ b/lib/PhpParser/PrettyPrinter/Standard.php @@ -529,7 +529,7 @@ class Standard extends PrettyPrinterAbstract } protected function pExpr_StaticCall(Expr\StaticCall $node) { - return $this->pDereferenceLhs($node->class) . '::' + return $this->pStaticDereferenceLhs($node->class) . '::' . ($node->name instanceof Expr ? ($node->name instanceof Expr\Variable ? $this->p($node->name) @@ -606,7 +606,7 @@ class Standard extends PrettyPrinterAbstract } protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) { - return $this->pDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name); + return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name); } protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) { @@ -618,7 +618,7 @@ class Standard extends PrettyPrinterAbstract } protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) { - return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); + return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); } protected function pExpr_ShellExec(Expr\ShellExec $node) { @@ -1069,6 +1069,14 @@ class Standard extends PrettyPrinterAbstract } } + protected function pStaticDereferenceLhs(Node $node) { + if (!$this->staticDereferenceLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pCallLhs(Node $node) { if (!$this->callLhsRequiresParens($node)) { return $this->p($node); diff --git a/lib/PhpParser/PrettyPrinterAbstract.php b/lib/PhpParser/PrettyPrinterAbstract.php index 3c8af570..8d48cdfb 100644 --- a/lib/PhpParser/PrettyPrinterAbstract.php +++ b/lib/PhpParser/PrettyPrinterAbstract.php @@ -22,6 +22,7 @@ abstract class PrettyPrinterAbstract const FIXUP_VAR_BRACED_NAME = 5; // Name operand that may require ${} bracing const FIXUP_ENCAPSED = 6; // Encapsed string part const FIXUP_NEW = 7; // New/instanceof operand + const FIXUP_STATIC_DEREF_LHS = 8; // LHS of static dereferencing operation protected $precedenceMap = [ // [precedence, associativity] @@ -978,6 +979,13 @@ abstract class PrettyPrinterAbstract return '(' . $this->p($subNode) . ')'; } break; + case self::FIXUP_STATIC_DEREF_LHS: + if ($this->staticDereferenceLhsRequiresParens($subNode) + && !$this->origTokens->haveParens($subStartPos, $subEndPos) + ) { + return '(' . $this->p($subNode) . ')'; + } + break; case self::FIXUP_NEW: if ($this->newOperandRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { @@ -1054,13 +1062,26 @@ abstract class PrettyPrinterAbstract } /** - * Determines whether the LHS of a dereferencing operation must be wrapped in parenthesis. + * Determines whether the LHS of an array/object operation must be wrapped in parentheses. * * @param Node $node LHS of dereferencing operation * * @return bool Whether parentheses are required */ protected function dereferenceLhsRequiresParens(Node $node) : bool { + // A constant can occur on the LHS of an array/object deref, but not a static deref. + return $this->staticDereferenceLhsRequiresParens($node) + && !$node instanceof Expr\ConstFetch; + } + + /** + * Determines whether the LHS of a static operation must be wrapped in parentheses. + * + * @param Node $node LHS of dereferencing operation + * + * @return bool Whether parentheses are required + */ + protected function staticDereferenceLhsRequiresParens(Node $node): bool { return !($node instanceof Expr\Variable || $node instanceof Node\Name || $node instanceof Expr\ArrayDimFetch @@ -1073,7 +1094,6 @@ abstract class PrettyPrinterAbstract || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_ || $node instanceof Scalar\String_ - || $node instanceof Expr\ConstFetch || $node instanceof Expr\ClassConstFetch); } @@ -1208,9 +1228,9 @@ abstract class PrettyPrinterAbstract ], Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS], - Expr\StaticCall::class => ['class' => self::FIXUP_DEREF_LHS], + Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS], Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS], - Expr\ClassConstFetch::class => ['var' => self::FIXUP_DEREF_LHS], + Expr\ClassConstFetch::class => ['class' => self::FIXUP_STATIC_DEREF_LHS], Expr\New_::class => ['class' => self::FIXUP_NEW], Expr\MethodCall::class => [ 'var' => self::FIXUP_DEREF_LHS, @@ -1221,7 +1241,7 @@ abstract class PrettyPrinterAbstract 'name' => self::FIXUP_BRACED_NAME, ], Expr\StaticPropertyFetch::class => [ - 'class' => self::FIXUP_DEREF_LHS, + 'class' => self::FIXUP_STATIC_DEREF_LHS, 'name' => self::FIXUP_VAR_BRACED_NAME, ], Expr\PropertyFetch::class => [ diff --git a/test/code/formatPreservation/fixup.test b/test/code/formatPreservation/fixup.test index de385327..ec3afe61 100644 --- a/test/code/formatPreservation/fixup.test +++ b/test/code/formatPreservation/fixup.test @@ -44,6 +44,9 @@ self :: $foo; self :: $foo; new Foo(); $x instanceof Foo; +Foo :: bar; +Foo :: $bar; +Foo :: bar(); ----- $stmts[0]->expr->name = new Expr\Variable('a'); $stmts[1]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b')); @@ -58,6 +61,9 @@ $stmts[7]->expr->name = new Node\VarLikeIdentifier('bar'); $stmts[8]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b')); $stmts[9]->expr->class = new Scalar\String_('Foo'); $stmts[10]->expr->class = new Scalar\String_('Foo'); +$stmts[11]->expr->class = new Expr\ConstFetch(new Node\Name('FOO')); +$stmts[12]->expr->class = new Expr\ConstFetch(new Node\Name('FOO')); +$stmts[13]->expr->class = new Expr\ConstFetch(new Node\Name('FOO')); ----- <?php $a (); @@ -71,3 +77,6 @@ self :: $bar; self :: ${$a . $b}; new ('Foo')(); $x instanceof ('Foo'); +(FOO) :: bar; +(FOO) :: $bar; +(FOO) :: bar(); diff --git a/test/code/prettyPrinter/expr/newVariable.test b/test/code/prettyPrinter/expr/newVariable.test index ef010d9d..499e5aaa 100644 --- a/test/code/prettyPrinter/expr/newVariable.test +++ b/test/code/prettyPrinter/expr/newVariable.test @@ -18,6 +18,6 @@ new (foo())(); new ('foo')(); new (x[0])(); new (x->y)(); -new (x::$y)(); +new ((x)::$y)(); $x instanceof ('a' . 'b'); $x instanceof ($y++); diff --git a/test/code/prettyPrinter/expr/uvs.test b/test/code/prettyPrinter/expr/uvs.test index 087e7129..58f85206 100644 --- a/test/code/prettyPrinter/expr/uvs.test +++ b/test/code/prettyPrinter/expr/uvs.test @@ -11,6 +11,9 @@ A::$$b[$c](); ($a->b)(); (A::$b)(); ('a' . 'b')::X; +(A)::X; +(A)::$x; +(A)::x(); ----- !!php7 (function () { @@ -22,4 +25,7 @@ $A::{$b[$c]}(); A::${$b}[$c](); ($a->b)(); (A::$b)(); -('a' . 'b')::X; \ No newline at end of file +('a' . 'b')::X; +(A)::X; +(A)::$x; +(A)::x();