Skip to content

Commit 84bbc96

Browse files
authored
Deprecate MultilinePromotedPropertiesFixer (#1043)
1 parent 09a2956 commit 84bbc96

File tree

6 files changed

+62
-146
lines changed

6 files changed

+62
-146
lines changed

.dev-tools/src/Readme/ReadmeCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private function fixers(): string
221221
"\n- `%s` (`%s`): %s; defaults to `%s`",
222222
$option->getName(),
223223
\implode('`, `', $allowed),
224-
$option->getDescription(),
224+
\lcfirst(\rtrim($option->getDescription(), '.')),
225225
Utils::toString($option->getDefault()),
226226
);
227227
}

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG for PHP CS Fixer: custom fixers
22

3+
## v3.28.0
4+
- Deprecate MultilinePromotedPropertiesFixer - use "multiline_promoted_properties"
5+
- Update minimum PHP CS Fixer version to 3.76.1
6+
37
## v3.27.0
48
- Add PhpdocTagNoNamedArgumentsFixer
59

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Latest stable version](https://img.shields.io/packagist/v/kubawerlos/php-cs-fixer-custom-fixers.svg?label=current%20version)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers)
66
[![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net)
77
[![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE)
8-
![Tests](https://img.shields.io/badge/tests-3796-brightgreen.svg)
8+
![Tests](https://img.shields.io/badge/tests-3798-brightgreen.svg)
99
[![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers)
1010

1111
[![CI status](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/actions/workflows/ci.yaml/badge.svg)](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/actions/workflows/ci.yaml)
@@ -210,11 +210,13 @@ Multiline comments or PHPDocs must contain an opening and closing line with no a
210210

211211
#### MultilinePromotedPropertiesFixer
212212
Promoted properties must be on separate lines.
213+
DEPRECATED: use `multiline_promoted_properties` instead.
213214
Configuration options:
214215
- `keep_blank_lines` (`bool`): whether to keep blank lines between properties; defaults to `false`
215216
- `minimum_number_of_parameters` (`int`): minimum number of parameters in the constructor to fix; defaults to `1`
216217
```diff
217-
<?php class Foo {
218+
<?php
219+
class Foo {
218220
- public function __construct(private array $a, private bool $b, private int $i) {}
219221
+ public function __construct(
220222
+ private array $a,
@@ -427,11 +429,11 @@ There must be no useless write visibility.
427429
Numeric literals must have configured separators.
428430
DEPRECATED: use `numeric_literal_separator` instead.
429431
Configuration options:
430-
- `binary` (`bool`, `null`): whether add, remove or ignore separators in binary numbers.; defaults to `false`
431-
- `decimal` (`bool`, `null`): whether add, remove or ignore separators in decimal numbers.; defaults to `false`
432-
- `float` (`bool`, `null`): whether add, remove or ignore separators in float numbers.; defaults to `false`
433-
- `hexadecimal` (`bool`, `null`): whether add, remove or ignore separators in hexadecimal numbers.; defaults to `false`
434-
- `octal` (`bool`, `null`): whether add, remove or ignore separators in octal numbers.; defaults to `false`
432+
- `binary` (`bool`, `null`): whether add, remove or ignore separators in binary numbers; defaults to `false`
433+
- `decimal` (`bool`, `null`): whether add, remove or ignore separators in decimal numbers; defaults to `false`
434+
- `float` (`bool`, `null`): whether add, remove or ignore separators in float numbers; defaults to `false`
435+
- `hexadecimal` (`bool`, `null`): whether add, remove or ignore separators in hexadecimal numbers; defaults to `false`
436+
- `octal` (`bool`, `null`): whether add, remove or ignore separators in octal numbers; defaults to `false`
435437
```diff
436438
<?php
437439
-echo 0b01010100_01101000; // binary

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"php": "^7.4 || ^8.0",
1414
"ext-filter": "*",
1515
"ext-tokenizer": "*",
16-
"friendsofphp/php-cs-fixer": "^3.61.1"
16+
"friendsofphp/php-cs-fixer": "^3.76"
1717
},
1818
"require-dev": {
1919
"phpunit/phpunit": "^9.6.22 || 10.5.45 || ^11.5.7"

src/Fixer/MultilinePromotedPropertiesFixer.php

Lines changed: 24 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -12,81 +12,54 @@
1212
namespace PhpCsFixerCustomFixers\Fixer;
1313

1414
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
15+
use PhpCsFixer\Fixer\DeprecatedFixerInterface;
16+
use PhpCsFixer\Fixer\FunctionNotation\MultilinePromotedPropertiesFixer as PhpCsFixerMultilinePromotedPropertiesFixer;
1517
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
16-
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
1718
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
18-
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
19-
use PhpCsFixer\FixerDefinition\FixerDefinition;
2019
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
21-
use PhpCsFixer\FixerDefinition\VersionSpecification;
22-
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
23-
use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
24-
use PhpCsFixer\Tokenizer\CT;
2520
use PhpCsFixer\Tokenizer\Tokens;
2621
use PhpCsFixer\WhitespacesFixerConfig;
27-
use PhpCsFixerCustomFixers\Analyzer\ConstructorAnalyzer;
2822

2923
/**
24+
* @deprecated
25+
*
3026
* @implements ConfigurableFixerInterface<_InputConfig, _Config>
3127
*
3228
* @phpstan-type _InputConfig array{keep_blank_lines?: bool, minimum_number_of_parameters?: int}
3329
* @phpstan-type _Config array{keep_blank_lines: bool, minimum_number_of_parameters: int}
3430
*
3531
* @no-named-arguments
3632
*/
37-
final class MultilinePromotedPropertiesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
33+
final class MultilinePromotedPropertiesFixer extends AbstractFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface, WhitespacesAwareFixerInterface
3834
{
39-
private int $minimumNumberOfParameters = 1;
40-
private bool $keepBlankLines = false;
41-
private WhitespacesFixerConfig $whitespacesConfig;
35+
private PhpCsFixerMultilinePromotedPropertiesFixer $multilinePromotedPropertiesFixer;
36+
37+
public function __construct()
38+
{
39+
$this->multilinePromotedPropertiesFixer = new PhpCsFixerMultilinePromotedPropertiesFixer();
40+
}
4241

4342
public function getDefinition(): FixerDefinitionInterface
4443
{
45-
return new FixerDefinition(
46-
'Promoted properties must be on separate lines.',
47-
[
48-
new VersionSpecificCodeSample(
49-
'<?php class Foo {
50-
public function __construct(private array $a, private bool $b, private int $i) {}
51-
}
52-
',
53-
new VersionSpecification(80000),
54-
),
55-
],
56-
'',
57-
);
44+
return $this->multilinePromotedPropertiesFixer->getDefinition();
5845
}
5946

6047
public function getConfigurationDefinition(): FixerConfigurationResolverInterface
6148
{
62-
return new FixerConfigurationResolver([
63-
(new FixerOptionBuilder('keep_blank_lines', 'whether to keep blank lines between properties'))
64-
->setAllowedTypes(['bool'])
65-
->setDefault($this->keepBlankLines)
66-
->getOption(),
67-
(new FixerOptionBuilder('minimum_number_of_parameters', 'minimum number of parameters in the constructor to fix'))
68-
->setAllowedTypes(['int'])
69-
->setDefault($this->minimumNumberOfParameters)
70-
->getOption(),
71-
]);
49+
return $this->multilinePromotedPropertiesFixer->getConfigurationDefinition();
7250
}
7351

7452
/**
7553
* @param array{minimum_number_of_parameters?: int, keep_blank_lines?: bool} $configuration
7654
*/
7755
public function configure(array $configuration): void
7856
{
79-
if (\array_key_exists('minimum_number_of_parameters', $configuration)) {
80-
$this->minimumNumberOfParameters = $configuration['minimum_number_of_parameters'];
81-
}
82-
if (\array_key_exists('keep_blank_lines', $configuration)) {
83-
$this->keepBlankLines = $configuration['keep_blank_lines'];
84-
}
57+
$this->multilinePromotedPropertiesFixer->configure($configuration);
8558
}
8659

8760
public function setWhitespacesConfig(WhitespacesFixerConfig $config): void
8861
{
89-
$this->whitespacesConfig = $config;
62+
$this->multilinePromotedPropertiesFixer->setWhitespacesConfig($config);
9063
}
9164

9265
/**
@@ -95,112 +68,29 @@ public function setWhitespacesConfig(WhitespacesFixerConfig $config): void
9568
*/
9669
public function getPriority(): int
9770
{
98-
return 0;
71+
return $this->multilinePromotedPropertiesFixer->getPriority();
9972
}
10073

10174
public function isCandidate(Tokens $tokens): bool
10275
{
103-
return $tokens->isAnyTokenKindsFound([
104-
CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
105-
CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
106-
CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
107-
]);
76+
return $this->multilinePromotedPropertiesFixer->isCandidate($tokens);
10877
}
10978

11079
public function isRisky(): bool
11180
{
112-
return false;
81+
return $this->multilinePromotedPropertiesFixer->isRisky();
11382
}
11483

11584
public function fix(\SplFileInfo $file, Tokens $tokens): void
11685
{
117-
$constructorAnalyzer = new ConstructorAnalyzer();
118-
119-
for ($index = $tokens->count() - 1; $index > 0; $index--) {
120-
if (!$tokens[$index]->isGivenKind(\T_CLASS)) {
121-
continue;
122-
}
123-
124-
$constructorAnalysis = $constructorAnalyzer->findNonAbstractConstructor($tokens, $index);
125-
if ($constructorAnalysis === null) {
126-
continue;
127-
}
128-
129-
$openParenthesis = $tokens->getNextTokenOfKind($constructorAnalysis->getConstructorIndex(), ['(']);
130-
\assert(\is_int($openParenthesis));
131-
$closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);
132-
133-
if (!$this->shouldBeFixed($tokens, $openParenthesis, $closeParenthesis)) {
134-
continue;
135-
}
136-
137-
$this->fixParameters($tokens, $openParenthesis, $closeParenthesis);
138-
}
139-
}
140-
141-
private function shouldBeFixed(Tokens $tokens, int $openParenthesis, int $closeParenthesis): bool
142-
{
143-
$promotedParameterFound = false;
144-
$minimumNumberOfParameters = 0;
145-
for ($index = $openParenthesis + 1; $index < $closeParenthesis; $index++) {
146-
if ($tokens[$index]->isGivenKind(\T_VARIABLE)) {
147-
$minimumNumberOfParameters++;
148-
}
149-
if (
150-
$tokens[$index]->isGivenKind([
151-
CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE,
152-
CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED,
153-
CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC,
154-
])
155-
) {
156-
$promotedParameterFound = true;
157-
}
158-
}
159-
160-
return $promotedParameterFound && $minimumNumberOfParameters >= $this->minimumNumberOfParameters;
86+
$this->multilinePromotedPropertiesFixer->fix($file, $tokens);
16187
}
16288

163-
private function fixParameters(Tokens $tokens, int $openParenthesis, int $closeParenthesis): void
164-
{
165-
$indent = WhitespacesAnalyzer::detectIndent($tokens, $openParenthesis);
166-
167-
$tokens->ensureWhitespaceAtIndex(
168-
$closeParenthesis - 1,
169-
1,
170-
$this->whitespacesConfig->getLineEnding() . $indent,
171-
);
172-
173-
$index = $tokens->getPrevMeaningfulToken($closeParenthesis);
174-
\assert(\is_int($index));
175-
176-
while ($index > $openParenthesis) {
177-
$index = $tokens->getPrevMeaningfulToken($index);
178-
\assert(\is_int($index));
179-
180-
$blockType = Tokens::detectBlockType($tokens[$index]);
181-
if ($blockType !== null && !$blockType['isStart']) {
182-
$index = $tokens->findBlockStart($blockType['type'], $index);
183-
continue;
184-
}
185-
186-
if (!$tokens[$index]->equalsAny(['(', ','])) {
187-
continue;
188-
}
189-
190-
$this->fixParameter($tokens, $index + 1, $indent);
191-
}
192-
}
193-
194-
private function fixParameter(Tokens $tokens, int $index, string $indent): void
89+
/**
90+
* @return list<string>
91+
*/
92+
public function getSuccessorsNames(): array
19593
{
196-
if ($this->keepBlankLines && $tokens[$index]->isWhitespace() && \str_contains($tokens[$index]->getContent(), "\n")) {
197-
return;
198-
}
199-
200-
$tokens->ensureWhitespaceAtIndex(
201-
$index,
202-
0,
203-
$this->whitespacesConfig->getLineEnding() . $indent . $this->whitespacesConfig->getIndent(),
204-
);
94+
return [$this->multilinePromotedPropertiesFixer->getName()];
20595
}
20696
}

tests/Fixer/MultilinePromotedPropertiesFixerTest.php

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Tests\Fixer;
1313

14+
use PhpCsFixer\WhitespacesFixerConfig;
15+
1416
/**
1517
* @internal
1618
*
@@ -20,6 +22,11 @@
2022
*/
2123
final class MultilinePromotedPropertiesFixerTest extends AbstractFixerTestCase
2224
{
25+
public function testSuccessorName(): void
26+
{
27+
self::assertSuccessorName('multiline_promoted_properties');
28+
}
29+
2330
public function testConfiguration(): void
2431
{
2532
$options = self::getConfigurationOptions();
@@ -40,13 +47,13 @@ public function testIsRisky(): void
4047
*
4148
* @dataProvider provideFixCases
4249
*/
43-
public function testFix(string $expected, ?string $input = null, array $configuration = []): void
50+
public function testFix(string $expected, ?string $input = null, array $configuration = [], ?WhitespacesFixerConfig $whitespacesFixerConfig = null): void
4451
{
45-
$this->doTest($expected, $input, $configuration);
52+
$this->doTest($expected, $input, $configuration, $whitespacesFixerConfig);
4653
}
4754

4855
/**
49-
* @return iterable<array{0: string, 1: null|string, 2?: array<string, bool|int>}>
56+
* @return iterable<array{0: string, 1: null|string, 2?: array<string, bool|int>, 3?: WhitespacesFixerConfig}>
5057
*/
5158
public static function provideFixCases(): iterable
5259
{
@@ -252,5 +259,18 @@ public function __construct(
252259
}',
253260
['keep_blank_lines' => true],
254261
];
262+
263+
yield '2 spaces intent and windows line endings' => [
264+
\str_replace("\n", "\r\n", '<?php class Foo {
265+
public function __construct(
266+
public int $x
267+
) {}
268+
}'),
269+
\str_replace("\n", "\r\n", '<?php class Foo {
270+
public function __construct(public int $x) {}
271+
}'),
272+
[],
273+
new WhitespacesFixerConfig(' ', "\r\n"),
274+
];
255275
}
256276
}

0 commit comments

Comments
 (0)