diff --git a/grammar/php.y b/grammar/php.y index 44c76f8b0f..52ad413d53 100644 --- a/grammar/php.y +++ b/grammar/php.y @@ -1267,13 +1267,19 @@ class_constant: array_short_syntax: '[' array_pair_list ']' - { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT; + { $attrs = attributes(); + $attrs['kind'] = $this->isMultiline($attrs) + ? Expr\Array_::KIND_SHORT | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_SHORT; $$ = new Expr\Array_($2, $attrs); } ; dereferenceable_scalar: T_ARRAY '(' array_pair_list ')' - { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG; + { $attrs = attributes(); + $attrs['kind'] = $this->isMultiline($attrs) + ? Expr\Array_::KIND_LONG | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_LONG; $$ = new Expr\Array_($3, $attrs); $this->createdArrays->offsetSet($$); } | array_short_syntax diff --git a/lib/PhpParser/Node/Expr/Array_.php b/lib/PhpParser/Node/Expr/Array_.php index 3c8c9c2fcf..11ca813509 100644 --- a/lib/PhpParser/Node/Expr/Array_.php +++ b/lib/PhpParser/Node/Expr/Array_.php @@ -9,6 +9,7 @@ class Array_ extends Expr { // For use in "kind" attribute public const KIND_LONG = 1; // array() syntax public const KIND_SHORT = 2; // [] syntax + public const KIND_MULTILINE = 4; // force multiline formatting /** @var ArrayItem[] Items */ public array $items; diff --git a/lib/PhpParser/Parser/Php7.php b/lib/PhpParser/Parser/Php7.php index 7784e8806c..4b799e4f03 100644 --- a/lib/PhpParser/Parser/Php7.php +++ b/lib/PhpParser/Parser/Php7.php @@ -2686,11 +2686,17 @@ protected function initReduceCallbacks(): void { $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(3-3)], $self->tokenEndStack[$stackPos-(3-3)])), $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2; }, 560 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_SHORT; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_SHORT | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_SHORT; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(3-2)], $attrs); }, 561 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_LONG | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_LONG; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs); $self->createdArrays->offsetSet($self->semValue); }, diff --git a/lib/PhpParser/Parser/Php8.php b/lib/PhpParser/Parser/Php8.php index 7a15cef564..e7090be411 100644 --- a/lib/PhpParser/Parser/Php8.php +++ b/lib/PhpParser/Parser/Php8.php @@ -2687,11 +2687,17 @@ protected function initReduceCallbacks(): void { $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(3-3)], $self->tokenEndStack[$stackPos-(3-3)])), $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2; }, 563 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_SHORT; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_SHORT | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_SHORT; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(3-2)], $attrs); }, 564 => static function ($self, $stackPos) { - $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG; + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->isMultiline($attrs) + ? Expr\Array_::KIND_LONG | Expr\Array_::KIND_MULTILINE + : Expr\Array_::KIND_LONG; $self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs); $self->createdArrays->offsetSet($self->semValue); }, diff --git a/lib/PhpParser/ParserAbstract.php b/lib/PhpParser/ParserAbstract.php index c10a0c9757..7890dfdd96 100644 --- a/lib/PhpParser/ParserAbstract.php +++ b/lib/PhpParser/ParserAbstract.php @@ -1264,6 +1264,17 @@ private function isSimpleExit(array $args): bool { return false; } + /** + * @param array{startLine?:int, endLine?: int} $attrs + */ + protected function isMultiline(array $attrs): bool { + if (!isset($attrs['startLine']) || !isset($attrs['endLine'])) { + return false; + } + + return $attrs['startLine'] !== $attrs['endLine']; + } + /** * @param array $args * @param array $attrs diff --git a/lib/PhpParser/PrettyPrinter/Standard.php b/lib/PhpParser/PrettyPrinter/Standard.php index 0a9dfd750c..541dd45b93 100644 --- a/lib/PhpParser/PrettyPrinter/Standard.php +++ b/lib/PhpParser/PrettyPrinter/Standard.php @@ -600,12 +600,16 @@ protected function pExpr_Variable(Expr\Variable $node): string { } protected function pExpr_Array(Expr\Array_ $node): string { - $syntax = $node->getAttribute('kind', + $kind = $node->getAttribute('kind', $this->shortArraySyntax ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG); + + $forceMultiline = ($kind & Expr\Array_::KIND_MULTILINE) === Expr\Array_::KIND_MULTILINE; + $syntax = $kind & ~Expr\Array_::KIND_MULTILINE; + if ($syntax === Expr\Array_::KIND_SHORT) { - return '[' . $this->pMaybeMultiline($node->items, true) . ']'; + return '[' . $this->pMaybeMultiline($node->items, true, $forceMultiline) . ']'; } else { - return 'array(' . $this->pMaybeMultiline($node->items, true) . ')'; + return 'array(' . $this->pMaybeMultiline($node->items, true, $forceMultiline) . ')'; } } @@ -1181,12 +1185,12 @@ protected function hasNodeWithComments(array $nodes): bool { } /** @param Node[] $nodes */ - protected function pMaybeMultiline(array $nodes, bool $trailingComma = false): string { - if (!$this->hasNodeWithComments($nodes)) { - return $this->pCommaSeparated($nodes); - } else { + protected function pMaybeMultiline(array $nodes, bool $trailingComma = false, bool $forceMultiline = false): string { + if ($forceMultiline || $this->hasNodeWithComments($nodes)) { return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl; } + + return $this->pCommaSeparated($nodes); } /** @param Node\Param[] $params diff --git a/test/code/prettyPrinter/stmt/arrays.test b/test/code/prettyPrinter/stmt/arrays.test new file mode 100644 index 0000000000..38fccbdb85 --- /dev/null +++ b/test/code/prettyPrinter/stmt/arrays.test @@ -0,0 +1,83 @@ +Arrays +----- +