Skip to content

Commit

Permalink
feat: Add array_destructuring as option for `trailing_comma_in_mult…
Browse files Browse the repository at this point in the history
…iline` (#8172)
  • Loading branch information
SpacePossum authored Aug 23, 2024
1 parent 601f01f commit 370943c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 26 deletions.
6 changes: 3 additions & 3 deletions doc/rules/control_structure/trailing_comma_in_multiline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
Rule ``trailing_comma_in_multiline``
====================================

Multi-line arrays, arguments list, parameters list and ``match`` expressions
must have a trailing comma.
Arguments lists, array destructuring lists, arrays that are multi-line,
``match``-lines and parameters lists must have a trailing comma.

Configuration
-------------
Expand All @@ -23,7 +23,7 @@ Default value: ``false``
Where to fix multiline trailing comma (PHP >= 8.0 for ``parameters`` and
``match``).

Allowed values: a subset of ``['arguments', 'arrays', 'match', 'parameters']``
Allowed values: a subset of ``['arguments', 'array_destructuring', 'arrays', 'match', 'parameters']``

Default value: ``['arrays']``

Expand Down
2 changes: 1 addition & 1 deletion doc/rules/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ Control Structure
Switch case must not be ended with ``continue`` but with ``break``.
- `trailing_comma_in_multiline <./control_structure/trailing_comma_in_multiline.rst>`_

Multi-line arrays, arguments list, parameters list and ``match`` expressions must have a trailing comma.
Arguments lists, array destructuring lists, arrays that are multi-line, ``match``-lines and parameters lists must have a trailing comma.
- `yoda_style <./control_structure/yoda_style.rst>`_

Write conditions in Yoda style (``true``), non-Yoda style (``['equal' => false, 'identical' => false, 'less_and_greater' => false]``) or ignore those conditions (``null``) based on configuration.
Expand Down
78 changes: 56 additions & 22 deletions src/Fixer/ControlStructure/TrailingCommaInMultilineFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@
*
* @phpstan-type _AutogeneratedInputConfiguration array{
* after_heredoc?: bool,
* elements?: list<'arguments'|'arrays'|'match'|'parameters'>
* elements?: list<'arguments'|'array_destructuring'|'arrays'|'match'|'parameters'>
* }
* @phpstan-type _AutogeneratedComputedConfiguration array{
* after_heredoc: bool,
* elements: list<'arguments'|'arrays'|'match'|'parameters'>
* elements: list<'arguments'|'array_destructuring'|'arrays'|'match'|'parameters'>
* }
*/
final class TrailingCommaInMultilineFixer extends AbstractFixer implements ConfigurableFixerInterface
Expand All @@ -69,10 +69,12 @@ final class TrailingCommaInMultilineFixer extends AbstractFixer implements Confi

private const MATCH_EXPRESSIONS = 'match';

private const ARRAY_DESTRUCTURING = 'array_destructuring';

public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Multi-line arrays, arguments list, parameters list and `match` expressions must have a trailing comma.',
'Arguments lists, array destructuring lists, arrays that are multi-line, `match`-lines and parameters lists must have a trailing comma.',
[
new CodeSample("<?php\narray(\n 1,\n 2\n);\n"),
new CodeSample(
Expand All @@ -97,7 +99,7 @@ public function getDefinition(): FixerDefinitionInterface

public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN, '(']);
return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN, '(', CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN]);
}

protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
Expand All @@ -109,30 +111,42 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn
->getOption(),
(new FixerOptionBuilder('elements', \sprintf('Where to fix multiline trailing comma (PHP >= 8.0 for `%s` and `%s`).', self::ELEMENTS_PARAMETERS, self::MATCH_EXPRESSIONS))) // @TODO: remove text when PHP 8.0+ is required
->setAllowedTypes(['string[]'])
->setAllowedValues([new AllowedValueSubset([self::ELEMENTS_ARRAYS, self::ELEMENTS_ARGUMENTS, self::ELEMENTS_PARAMETERS, self::MATCH_EXPRESSIONS])])
->setAllowedValues([
new AllowedValueSubset([
self::ARRAY_DESTRUCTURING,
self::ELEMENTS_ARGUMENTS,
self::ELEMENTS_ARRAYS,
self::ELEMENTS_PARAMETERS,
self::MATCH_EXPRESSIONS,
]),
])
->setDefault([self::ELEMENTS_ARRAYS])
->getOption(),
]);
}

protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$fixArrays = \in_array(self::ELEMENTS_ARRAYS, $this->configuration['elements'], true);
$fixArguments = \in_array(self::ELEMENTS_ARGUMENTS, $this->configuration['elements'], true);
$fixParameters = \PHP_VERSION_ID >= 8_00_00 && \in_array(self::ELEMENTS_PARAMETERS, $this->configuration['elements'], true); // @TODO: drop condition when PHP 8.0+ is required
$fixMatch = \PHP_VERSION_ID >= 8_00_00 && \in_array(self::MATCH_EXPRESSIONS, $this->configuration['elements'], true); // @TODO: drop condition when PHP 8.0+ is required
$configuredElements = $this->configuration['elements'];
$fixArrays = \in_array(self::ELEMENTS_ARRAYS, $configuredElements, true);
$fixArguments = \in_array(self::ELEMENTS_ARGUMENTS, $configuredElements, true);
$fixParameters = \PHP_VERSION_ID >= 8_00_00 && \in_array(self::ELEMENTS_PARAMETERS, $configuredElements, true); // @TODO: drop condition when PHP 8.0+ is required
$fixMatch = \PHP_VERSION_ID >= 8_00_00 && \in_array(self::MATCH_EXPRESSIONS, $configuredElements, true); // @TODO: drop condition when PHP 8.0+ is required
$fixDestructuring = \in_array(self::ARRAY_DESTRUCTURING, $configuredElements, true);

for ($index = $tokens->count() - 1; $index >= 0; --$index) {
$prevIndex = $tokens->getPrevMeaningfulToken($index);
if ($tokens[$index]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)) {
if ($fixDestructuring) { // array destructing short syntax
$this->fixBlock($tokens, $index);
}

if (
$fixArrays
&& (
$tokens[$index]->equals('(') && $tokens[$prevIndex]->isGivenKind(T_ARRAY) // long syntax
|| $tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN) // short syntax
)
) {
$this->fixBlock($tokens, $index);
continue;
}

if ($tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
if ($fixArrays) { // array short syntax
$this->fixBlock($tokens, $index);
}

continue;
}
Expand All @@ -141,6 +155,30 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
continue;
}

$prevIndex = $tokens->getPrevMeaningfulToken($index);

if ($tokens[$prevIndex]->isGivenKind(T_ARRAY)) {
if ($fixArrays) { // array long syntax
$this->fixBlock($tokens, $index);
}

continue;
}

if ($tokens[$prevIndex]->isGivenKind(T_LIST)) {
if ($fixDestructuring || $fixArguments) { // array destructing long syntax
$this->fixBlock($tokens, $index);
}

continue;
}

if ($fixMatch && $tokens[$prevIndex]->isGivenKind(T_MATCH)) {
$this->fixMatch($tokens, $index);

continue;
}

$prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);

if ($fixArguments
Expand All @@ -162,10 +200,6 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
) {
$this->fixBlock($tokens, $index);
}

if ($fixMatch && $tokens[$prevIndex]->isGivenKind(T_MATCH)) {
$this->fixMatch($tokens, $index);
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions tests/Fixer/ControlStructure/TrailingCommaInMultilineFixerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,24 @@ function a()
); }};',
['elements' => [TrailingCommaInMultilineFixer::ELEMENTS_ARGUMENTS]],
];

yield [
'<?php
$a = [11,2,3];
[
$c,
$d,
] = $a;
',
'<?php
$a = [11,2,3];
[
$c,
$d
] = $a;
',
['elements' => ['array_destructuring']],
];
}

/**
Expand Down

0 comments on commit 370943c

Please sign in to comment.