From 5e982794de99215f2683f29feac1095ca1ffc18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Wed, 28 May 2025 23:01:51 +0200 Subject: [PATCH 01/20] Add `TypedClassConstantFixer` --- .github/workflows/ci.yaml | 2 + .php-cs-fixer.php | 2 + CHANGELOG.md | 3 + README.md | 15 +- composer.json | 4 + src/Fixer/TypedClassConstantFixer.php | 147 ++++++++++++++++ tests/Fixer/TypedClassConstantFixerTest.php | 176 ++++++++++++++++++++ 7 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 src/Fixer/TypedClassConstantFixer.php create mode 100644 tests/Fixer/TypedClassConstantFixerTest.php diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b005b900..f6415266 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,6 +23,8 @@ jobs: - if: github.event_name != 'pull_request' run: rm ./.dev-tools/composer.lock - run: composer update --no-progress + - run: "sed -i 's#constant: 0#constant: 100#g' .dev-tools/phpstan.neon" + - run: composer apply-typed_class_constant - run: composer analyse test: diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 9e9734e5..5c9bc939 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -20,6 +20,7 @@ use PhpCsFixerCustomFixers\Fixer\NoSuperfluousConcatenationFixer; use PhpCsFixerCustomFixers\Fixer\PhpdocOnlyAllowedAnnotationsFixer; use PhpCsFixerCustomFixers\Fixer\PromotedConstructorPropertyFixer; +use PhpCsFixerCustomFixers\Fixer\TypedClassConstantFixer; use PhpCsFixerCustomFixers\Fixers; // sanity check @@ -54,6 +55,7 @@ unset($rules['modernize_strpos']); // TODO: remove when dropping support to PHP <8.0 unset($rules['php_unit_attributes']); // TODO: remove when dropping support to PHP <8.0 unset($rules[PromotedConstructorPropertyFixer::name()]); // TODO: remove when dropping support to PHP <8.0 +unset($rules[TypedClassConstantFixer::name()]); // TODO: remove when dropping support to PHP <8.3 $rules['trailing_comma_in_multiline'] = ['after_heredoc' => true, 'elements' => ['arguments', 'arrays']]; // TODO: remove when dropping support to PHP <8.0 $rules[PhpdocOnlyAllowedAnnotationsFixer::name()]['elements'][] = 'phpstan-type'; diff --git a/CHANGELOG.md b/CHANGELOG.md index cb802792..47dee370 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGELOG for PHP CS Fixer: custom fixers +## v3.26.0 +- Add TypedClassConstantFixer + ## v3.25.0 - Add ForeachUseValueFixer - Add NoUselessWriteVisibilityFixer diff --git a/README.md b/README.md index f680dde7..7e1fb00e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3691-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3729-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) @@ -724,6 +724,19 @@ The string key of an array or generator must be trimmed and have no double space ]; ``` +#### TypedClassConstantFixer +Class constants must have a type. + *Risky: when constant can be of different types.* +```diff + 'float', + \T_LNUMBER => 'int', + \T_CONSTANT_ENCAPSED_STRING => 'string', + CT::T_ARRAY_SQUARE_BRACE_CLOSE => 'array', + ]; + + public function getDefinition(): FixerDefinitionInterface + { + return new FixerDefinition( + 'Class constants must have a type.', + [ + new VersionSpecificCodeSample( + <<<'PHP' + isAllTokenKindsFound([\T_CLASS, \T_CONST]); + } + + public function isRisky(): bool + { + return true; + } + + public function fix(\SplFileInfo $file, Tokens $tokens): void + { + for ($index = $tokens->count() - 1; $index > 0; $index--) { + if (!$tokens[$index]->isGivenKind(\T_CLASS)) { + continue; + } + + $openParenthesisIndex = $tokens->getNextTokenOfKind($index, ['{']); + \assert(\is_int($openParenthesisIndex)); + + $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openParenthesisIndex); + + self::fixClass($tokens, $openParenthesisIndex, $closeParenthesisIndex); + } + } + + private static function fixClass(Tokens $tokens, int $openParenthesisIndex, int $closeParenthesisIndex): void + { + for ($index = $closeParenthesisIndex; $index > $openParenthesisIndex; $index--) { + if (!$tokens[$index]->isGivenKind(\T_CONST)) { + continue; + } + + $constantNameIndex = $tokens->getNextMeaningfulToken($index); + \assert(\is_int($constantNameIndex)); + + $assignmentIndex = $tokens->getNextMeaningfulToken($constantNameIndex); + \assert(\is_int($assignmentIndex)); + + if (!$tokens[$assignmentIndex]->equals('=')) { + continue; + } + + $type = self::getTypeOfExpression($tokens, $assignmentIndex); + + $tokens->insertAt( + $constantNameIndex, + [ + new Token([$type === 'array' ? CT::T_ARRAY_TYPEHINT : \T_STRING, $type]), + new Token([\T_WHITESPACE, ' ']), + ], + ); + } + } + + private static function getTypeOfExpression(Tokens $tokens, int $assignmentIndex): string + { + $semicolonIndex = $tokens->getNextTokenOfKind($assignmentIndex, [';']); + \assert(\is_int($semicolonIndex)); + + $beforeSemicolonIndex = $tokens->getPrevMeaningfulToken($semicolonIndex); + \assert(\is_int($beforeSemicolonIndex)); + + $tokenId = $tokens[$beforeSemicolonIndex]->getId(); + + if (isset(self::TOKEN_TO_TYPE_MAP[$tokenId])) { + return self::TOKEN_TO_TYPE_MAP[$tokenId]; + } + + if ($tokens[$beforeSemicolonIndex]->isGivenKind(\T_STRING)) { + $lowercasedContent = \strtolower($tokens[$beforeSemicolonIndex]->getContent()); + if (\in_array($lowercasedContent, ['false', 'true', 'null'], true)) { + return $lowercasedContent; + } + } + + if ($tokens[$beforeSemicolonIndex]->equals(')')) { + $openParenthesisIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $beforeSemicolonIndex); + + $arrayIndex = $tokens->getPrevMeaningfulToken($openParenthesisIndex); + \assert(\is_int($arrayIndex)); + + if ($tokens[$arrayIndex]->isGivenKind(\T_ARRAY)) { + return 'array'; + } + } + + return 'mixed'; + } +} diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php new file mode 100644 index 00000000..98745b1d --- /dev/null +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -0,0 +1,176 @@ += 8.3 + */ + public function testFix(string $expected, ?string $input = null): void + { + $this->doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFixCases(): iterable + { + yield 'non-class constants are ignored' => [' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + " [ + ' [ + ' [ + <<<'PHP' + [ + ' [ + <<<'PHP' + Date: Thu, 29 May 2025 09:06:25 +0200 Subject: [PATCH 02/20] Update --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 67 +++++++++++++++------ tests/Fixer/TypedClassConstantFixerTest.php | 57 ++++++++++++------ 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 7e1fb00e..d4002065 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3729-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3733-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 46f19d7e..1968e4e5 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -21,13 +21,6 @@ final class TypedClassConstantFixer extends AbstractFixer { - private const TOKEN_TO_TYPE_MAP = [ - \T_DNUMBER => 'float', - \T_LNUMBER => 'int', - \T_CONSTANT_ENCAPSED_STRING => 'string', - CT::T_ARRAY_SQUARE_BRACE_CLOSE => 'array', - ]; - public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( @@ -110,38 +103,72 @@ private static function fixClass(Tokens $tokens, int $openParenthesisIndex, int } } - private static function getTypeOfExpression(Tokens $tokens, int $assignmentIndex): string + private static function getTypeOfExpression(Tokens $tokens, int $index): string { - $semicolonIndex = $tokens->getNextTokenOfKind($assignmentIndex, [';']); + $semicolonIndex = $tokens->getNextTokenOfKind($index, [';']); \assert(\is_int($semicolonIndex)); $beforeSemicolonIndex = $tokens->getPrevMeaningfulToken($semicolonIndex); \assert(\is_int($beforeSemicolonIndex)); - $tokenId = $tokens[$beforeSemicolonIndex]->getId(); + $foundKinds = []; + + $index = $tokens->getNextMeaningfulToken($index); + \assert(\is_int($index)); - if (isset(self::TOKEN_TO_TYPE_MAP[$tokenId])) { - return self::TOKEN_TO_TYPE_MAP[$tokenId]; + if ($tokens[$index]->isGivenKind([\T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) { + return 'array'; } - if ($tokens[$beforeSemicolonIndex]->isGivenKind(\T_STRING)) { + do { + $foundKinds[] = $tokens[$index]->getId() ?? $tokens[$index]->getContent(); + + $index = $tokens->getNextMeaningfulToken($index); + \assert(\is_int($index)); + } while ($index < $semicolonIndex); + + if ($foundKinds === [\T_STRING]) { $lowercasedContent = \strtolower($tokens[$beforeSemicolonIndex]->getContent()); if (\in_array($lowercasedContent, ['false', 'true', 'null'], true)) { return $lowercasedContent; } } - if ($tokens[$beforeSemicolonIndex]->equals(')')) { - $openParenthesisIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $beforeSemicolonIndex); + return self::getTypeOfExpressionForTokenKinds($foundKinds); + } - $arrayIndex = $tokens->getPrevMeaningfulToken($openParenthesisIndex); - \assert(\is_int($arrayIndex)); + /** + * @param list $tokenKinds + */ + private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): string + { + if (self::hasExclusivelyKinds($tokenKinds, [\T_LNUMBER, '+', '-', '*', '(', ')'])) { + return 'int'; + } - if ($tokens[$arrayIndex]->isGivenKind(\T_ARRAY)) { - return 'array'; - } + if (self::hasExclusivelyKinds($tokenKinds, [\T_DNUMBER, \T_LNUMBER, '+', '-', '*', '/', '(', ')'])) { + return 'float'; + } + + if (self::hasExclusivelyKinds($tokenKinds, [\T_CONSTANT_ENCAPSED_STRING, '.', \T_LNUMBER, \T_DNUMBER])) { + return 'string'; } return 'mixed'; } + + /** + * @param list $tokenKinds + * @param list $expectedKinds + */ + private static function hasExclusivelyKinds(array $tokenKinds, array $expectedKinds): bool + { + foreach ($tokenKinds as $index => $tokenKind) { + if (\in_array($tokenKind, $expectedKinds, true)) { + unset($tokenKinds[$index]); + } + } + + return $tokenKinds === []; + } } diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 98745b1d..b9b2c9fa 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -50,6 +50,11 @@ public static function provideFixCases(): iterable ' [ + ' 2] + array(3 => 4) + [5 => 6]; }', + ' 2] + array(3 => 4) + [5 => 6]; }', + ]; + yield 'false' => [ ' [ - ' [ ' [ - ' [ + ' [ + ' [ + ' [ + ' [ @@ -95,14 +110,9 @@ public static function provideFixCases(): iterable " [ - ' [ - ' [ + ' [ @@ -136,9 +146,18 @@ class Bar { PHP, ]; - // if someone does these, they deserve to have their code broken + yield 'unknown other constant' => [ + ' [ + ' [ - ' Date: Thu, 29 May 2025 09:39:00 +0200 Subject: [PATCH 03/20] Not risky anymore --- README.md | 1 - src/Fixer/TypedClassConstantFixer.php | 4 +--- tests/Fixer/TypedClassConstantFixerTest.php | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d4002065..c9f373cd 100644 --- a/README.md +++ b/README.md @@ -726,7 +726,6 @@ The string key of an array or generator must be trimmed and have no double space #### TypedClassConstantFixer Class constants must have a type. - *Risky: when constant can be of different types.* ```diff Date: Thu, 29 May 2025 11:04:51 +0200 Subject: [PATCH 04/20] Add test for anonymous class --- README.md | 2 +- tests/Fixer/TypedClassConstantFixerTest.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c9f373cd..6bbbf910 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3733-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3734-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 3eb43e07..896bcc8a 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -146,6 +146,11 @@ class Bar { PHP, ]; + yield 'anonymous class' => [ + ' [ ' Date: Thu, 29 May 2025 22:19:52 +0200 Subject: [PATCH 05/20] Support shift operators --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 10 +++++++--- tests/Fixer/TypedClassConstantFixerTest.php | 10 ++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6bbbf910..6ec4d232 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3734-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3736-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 7e5b959d..b35df64f 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -21,6 +21,10 @@ final class TypedClassConstantFixer extends AbstractFixer { + private const INTEGER_KINDS = [\T_LNUMBER, '+', '-', '*', '(', ')', \T_SL, \T_SR]; + private const FLOAT_KINDS = [\T_DNUMBER, ...self::INTEGER_KINDS, '/']; + private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, '.', \T_LNUMBER, \T_DNUMBER]; + public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( @@ -140,15 +144,15 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string */ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): string { - if (self::hasExclusivelyKinds($tokenKinds, [\T_LNUMBER, '+', '-', '*', '(', ')'])) { + if (self::hasExclusivelyKinds($tokenKinds, self::INTEGER_KINDS)) { return 'int'; } - if (self::hasExclusivelyKinds($tokenKinds, [\T_DNUMBER, \T_LNUMBER, '+', '-', '*', '/', '(', ')'])) { + if (self::hasExclusivelyKinds($tokenKinds, self::FLOAT_KINDS)) { return 'float'; } - if (self::hasExclusivelyKinds($tokenKinds, [\T_CONSTANT_ENCAPSED_STRING, '.', \T_LNUMBER, \T_DNUMBER])) { + if (self::hasExclusivelyKinds($tokenKinds, self::STRING_KINDS)) { return 'string'; } diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 896bcc8a..a613c1fa 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -80,6 +80,16 @@ public static function provideFixCases(): iterable ' [ + ' [ + '> 1; }', + '> 1; }', + ]; + yield 'float' => [ ' Date: Thu, 29 May 2025 22:26:32 +0200 Subject: [PATCH 06/20] Support exponentiation operator --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 2 +- tests/Fixer/TypedClassConstantFixerTest.php | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6ec4d232..9bc7c704 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3736-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3737-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index b35df64f..5e49aabc 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -21,7 +21,7 @@ final class TypedClassConstantFixer extends AbstractFixer { - private const INTEGER_KINDS = [\T_LNUMBER, '+', '-', '*', '(', ')', \T_SL, \T_SR]; + private const INTEGER_KINDS = [\T_LNUMBER, '+', '-', '*', '(', ')', \T_POW, \T_SL, \T_SR]; private const FLOAT_KINDS = [\T_DNUMBER, ...self::INTEGER_KINDS, '/']; private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, '.', \T_LNUMBER, \T_DNUMBER]; diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index a613c1fa..4e650b76 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -80,12 +80,17 @@ public static function provideFixCases(): iterable ' [ + yield 'integer with exponentiation operator' => [ + ' [ ' [ + yield 'integer with shift right operator' => [ '> 1; }', '> 1; }', ]; From a92a80195c939e5f4adffdc0565f9f17639da21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Thu, 29 May 2025 22:42:06 +0200 Subject: [PATCH 07/20] Support more complex concatenations --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 23 ++++++++++++--------- tests/Fixer/TypedClassConstantFixerTest.php | 7 ++++++- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9bc7c704..d6462e55 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3737-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3738-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 5e49aabc..66ea02a5 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -23,7 +23,7 @@ final class TypedClassConstantFixer extends AbstractFixer { private const INTEGER_KINDS = [\T_LNUMBER, '+', '-', '*', '(', ')', \T_POW, \T_SL, \T_SR]; private const FLOAT_KINDS = [\T_DNUMBER, ...self::INTEGER_KINDS, '/']; - private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, '.', \T_LNUMBER, \T_DNUMBER]; + private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, \T_LNUMBER, \T_DNUMBER]; public function getDefinition(): FixerDefinitionInterface { @@ -144,15 +144,15 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string */ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): string { - if (self::hasExclusivelyKinds($tokenKinds, self::INTEGER_KINDS)) { + if (self::isOfTypeBasedOnKinds($tokenKinds, self::INTEGER_KINDS)) { return 'int'; } - if (self::hasExclusivelyKinds($tokenKinds, self::FLOAT_KINDS)) { + if (self::isOfTypeBasedOnKinds($tokenKinds, self::FLOAT_KINDS)) { return 'float'; } - if (self::hasExclusivelyKinds($tokenKinds, self::STRING_KINDS)) { + if (self::isOfTypeBasedOnKinds($tokenKinds, self::STRING_KINDS, '.')) { return 'string'; } @@ -160,17 +160,20 @@ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): str } /** - * @param list $tokenKinds + * @param list $expressionTokenKinds * @param list $expectedKinds */ - private static function hasExclusivelyKinds(array $tokenKinds, array $expectedKinds): bool + private static function isOfTypeBasedOnKinds(array $expressionTokenKinds, array $expectedKinds, ?string $instantWinner = null): bool { - foreach ($tokenKinds as $index => $tokenKind) { - if (\in_array($tokenKind, $expectedKinds, true)) { - unset($tokenKinds[$index]); + foreach ($expressionTokenKinds as $index => $expressionTokenKind) { + if ($expressionTokenKind === $instantWinner) { + return true; + } + if (\in_array($expressionTokenKind, $expectedKinds, true)) { + unset($expressionTokenKinds[$index]); } } - return $tokenKinds === []; + return $expressionTokenKinds === []; } } diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 4e650b76..3cacb9b1 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -125,11 +125,16 @@ public static function provideFixCases(): iterable " [ + yield 'string as result of concatenations' => [ ' [ + ' [ <<<'PHP' Date: Fri, 30 May 2025 06:02:26 +0200 Subject: [PATCH 08/20] Support complex arrays --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 23 +++++++++++++++------ tests/Fixer/TypedClassConstantFixerTest.php | 10 +++++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d6462e55..422650e2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3738-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3740-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 66ea02a5..d74c03ca 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -144,15 +144,19 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string */ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): string { - if (self::isOfTypeBasedOnKinds($tokenKinds, self::INTEGER_KINDS)) { + if (self::isOfTypeBasedOnKinds($tokenKinds, [], [\T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) { + return 'array'; + } + + if (self::isOfTypeBasedOnKinds($tokenKinds, self::INTEGER_KINDS, [])) { return 'int'; } - if (self::isOfTypeBasedOnKinds($tokenKinds, self::FLOAT_KINDS)) { + if (self::isOfTypeBasedOnKinds($tokenKinds, self::FLOAT_KINDS, [])) { return 'float'; } - if (self::isOfTypeBasedOnKinds($tokenKinds, self::STRING_KINDS, '.')) { + if (self::isOfTypeBasedOnKinds($tokenKinds, self::STRING_KINDS, ['.'])) { return 'string'; } @@ -162,11 +166,18 @@ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): str /** * @param list $expressionTokenKinds * @param list $expectedKinds + * @param list $instantWinners */ - private static function isOfTypeBasedOnKinds(array $expressionTokenKinds, array $expectedKinds, ?string $instantWinner = null): bool - { + private static function isOfTypeBasedOnKinds( + array $expressionTokenKinds, + array $expectedKinds, + array $instantWinners, + ): bool { foreach ($expressionTokenKinds as $index => $expressionTokenKind) { - if ($expressionTokenKind === $instantWinner) { + if ($expressionTokenKind === '?') { + return false; + } + if (\in_array($expressionTokenKind, $instantWinners, true)) { return true; } if (\in_array($expressionTokenKind, $expectedKinds, true)) { diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 3cacb9b1..28abefc9 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -55,6 +55,16 @@ public static function provideFixCases(): iterable ' 2] + array(3 => 4) + [5 => 6]; }', ]; + yield 'array as sum of long syntax array and constant' => [ + ' [ + ' [ ' Date: Fri, 30 May 2025 06:05:15 +0200 Subject: [PATCH 09/20] PHP 7.4 syntax --- src/Fixer/TypedClassConstantFixer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index d74c03ca..a291434c 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -171,7 +171,7 @@ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): str private static function isOfTypeBasedOnKinds( array $expressionTokenKinds, array $expectedKinds, - array $instantWinners, + array $instantWinners ): bool { foreach ($expressionTokenKinds as $index => $expressionTokenKind) { if ($expressionTokenKind === '?') { From ec05c6dd5f35656675542eb8201380adb714338e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Fri, 30 May 2025 08:43:30 +0200 Subject: [PATCH 10/20] Update --- src/Fixer/TypedClassConstantFixer.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index a291434c..b392452d 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -144,10 +144,6 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string */ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): string { - if (self::isOfTypeBasedOnKinds($tokenKinds, [], [\T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) { - return 'array'; - } - if (self::isOfTypeBasedOnKinds($tokenKinds, self::INTEGER_KINDS, [])) { return 'int'; } From f4ad6780a7a838337b6ce6feee213f8bee52f949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Fri, 30 May 2025 08:46:30 +0200 Subject: [PATCH 11/20] Fix --- src/Fixer/TypedClassConstantFixer.php | 8 ++++---- tests/Fixer/TypedClassConstantFixerTest.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index b392452d..319e32bd 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -118,10 +118,6 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string $index = $tokens->getNextMeaningfulToken($index); \assert(\is_int($index)); - if ($tokens[$index]->isGivenKind([\T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) { - return 'array'; - } - do { $foundKinds[] = $tokens[$index]->getId() ?? $tokens[$index]->getContent(); @@ -144,6 +140,10 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string */ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): string { + if (self::isOfTypeBasedOnKinds($tokenKinds, [], [\T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) { + return 'array'; + } + if (self::isOfTypeBasedOnKinds($tokenKinds, self::INTEGER_KINDS, [])) { return 'int'; } diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 28abefc9..a29f969e 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -192,8 +192,8 @@ class Bar { ]; yield 'constant that can be of different types' => [ - ' [ From 06fc0299dd1862ccb22b29c666db525963bbbacc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Fri, 30 May 2025 18:32:41 +0200 Subject: [PATCH 12/20] Support heredoc and nowdoc --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 2 +- tests/Fixer/TypedClassConstantFixerTest.php | 33 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 422650e2..1e5822e4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3740-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3742-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 319e32bd..5b322c16 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -23,7 +23,7 @@ final class TypedClassConstantFixer extends AbstractFixer { private const INTEGER_KINDS = [\T_LNUMBER, '+', '-', '*', '(', ')', \T_POW, \T_SL, \T_SR]; private const FLOAT_KINDS = [\T_DNUMBER, ...self::INTEGER_KINDS, '/']; - private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, \T_LNUMBER, \T_DNUMBER]; + private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, \T_START_HEREDOC, \T_ENCAPSED_AND_WHITESPACE, \T_END_HEREDOC, \T_LNUMBER, \T_DNUMBER]; public function getDefinition(): FixerDefinitionInterface { diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index a29f969e..4c01d11e 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -135,6 +135,39 @@ public static function provideFixCases(): iterable " [ + <<<'PHP' + [ + <<<'PHP' + [ ' Date: Fri, 30 May 2025 18:34:08 +0200 Subject: [PATCH 13/20] Update --- tests/Fixer/TypedClassConstantFixerTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 4c01d11e..7ae1197e 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -151,6 +151,7 @@ public static function provideFixCases(): iterable } PHP, ]; + yield 'string with nowdoc syntax' => [ <<<'PHP' Date: Fri, 30 May 2025 21:22:43 +0200 Subject: [PATCH 14/20] Support class constants --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 12 +++++++++++- tests/Fixer/TypedClassConstantFixerTest.php | 21 ++++++++++++++++++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1e5822e4..27cb904e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3742-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3743-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 5b322c16..3d267cd7 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -118,7 +118,17 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string $index = $tokens->getNextMeaningfulToken($index); \assert(\is_int($index)); + $questionMarkCount = 0; do { + if ($questionMarkCount > 1) { + return 'mixed'; + } + $kind = $tokens[$index]->getId() ?? $tokens[$index]->getContent(); + if ($kind === '?') { + $questionMarkCount++; + $foundKinds = []; + continue; + } $foundKinds[] = $tokens[$index]->getId() ?? $tokens[$index]->getContent(); $index = $tokens->getNextMeaningfulToken($index); @@ -152,7 +162,7 @@ private static function getTypeOfExpressionForTokenKinds(array $tokenKinds): str return 'float'; } - if (self::isOfTypeBasedOnKinds($tokenKinds, self::STRING_KINDS, ['.'])) { + if (self::isOfTypeBasedOnKinds($tokenKinds, self::STRING_KINDS, ['.', CT::T_CLASS_CONSTANT])) { return 'string'; } diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 7ae1197e..b68a21fa 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -169,9 +169,24 @@ public static function provideFixCases(): iterable PHP, ]; - yield 'string as result of concatenations' => [ - ' [ + <<<'PHP' + [ + ' [ From 001ca179c19321e70d3784fa5f522bb9ec593d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Fri, 30 May 2025 21:28:18 +0200 Subject: [PATCH 15/20] Update --- src/Fixer/TypedClassConstantFixer.php | 3 --- tests/Fixer/TypedClassConstantFixerTest.php | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 3d267cd7..907a6b6a 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -180,9 +180,6 @@ private static function isOfTypeBasedOnKinds( array $instantWinners ): bool { foreach ($expressionTokenKinds as $index => $expressionTokenKind) { - if ($expressionTokenKind === '?') { - return false; - } if (\in_array($expressionTokenKind, $instantWinners, true)) { return true; } diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index b68a21fa..20e6662a 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -240,9 +240,19 @@ class Bar { ' [ - ' [ + <<<'PHP' + [ From ea5d0bff20a7ae5c5e1b6c30b0be071689b2358c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Fri, 30 May 2025 21:42:01 +0200 Subject: [PATCH 16/20] Update --- src/Fixer/TypedClassConstantFixer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 907a6b6a..840c65ff 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -129,7 +129,7 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string $foundKinds = []; continue; } - $foundKinds[] = $tokens[$index]->getId() ?? $tokens[$index]->getContent(); + $foundKinds[] = $kind; $index = $tokens->getNextMeaningfulToken($index); \assert(\is_int($index)); From d00e26178418f37b242956ae7b87ca099f3640a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Sat, 31 May 2025 18:14:54 +0200 Subject: [PATCH 17/20] Support magic constants --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 4 +-- tests/Fixer/TypedClassConstantFixerTest.php | 29 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 27cb904e..da9868cd 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3743-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3744-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index 840c65ff..ed2a7617 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -21,9 +21,9 @@ final class TypedClassConstantFixer extends AbstractFixer { - private const INTEGER_KINDS = [\T_LNUMBER, '+', '-', '*', '(', ')', \T_POW, \T_SL, \T_SR]; + private const INTEGER_KINDS = [\T_LNUMBER, '+', '-', '*', '(', ')', \T_POW, \T_SL, \T_SR, \T_LINE]; private const FLOAT_KINDS = [\T_DNUMBER, ...self::INTEGER_KINDS, '/']; - private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, \T_START_HEREDOC, \T_ENCAPSED_AND_WHITESPACE, \T_END_HEREDOC, \T_LNUMBER, \T_DNUMBER]; + private const STRING_KINDS = [\T_CONSTANT_ENCAPSED_STRING, \T_START_HEREDOC, \T_ENCAPSED_AND_WHITESPACE, \T_END_HEREDOC, \T_LNUMBER, \T_DNUMBER, \T_CLASS_C, \T_DIR, \T_FILE, \T_FUNC_C, \T_METHOD_C, \T_NS_C, \T_TRAIT_C]; public function getDefinition(): FixerDefinitionInterface { diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 20e6662a..645c3d1a 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -184,6 +184,35 @@ public static function provideFixCases(): iterable PHP, ]; + yield 'string as magic constant' => [ + <<<'PHP' + [ ' Date: Sun, 1 Jun 2025 10:06:47 +0200 Subject: [PATCH 18/20] Handle multiple constants definition --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 3 +++ tests/Fixer/TypedClassConstantFixerTest.php | 5 +++++ ..._per_statement,Custom_typed_class_constant.test | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/priority_fixtures/single_class_element_per_statement,Custom_typed_class_constant.test diff --git a/README.md b/README.md index da9868cd..20715844 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3744-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3748-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index ed2a7617..f1cf7f1f 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -45,6 +45,9 @@ class Foo { ); } + /** + * Must run after SingleClassElementPerStatementFixer. + */ public function getPriority(): int { return 0; diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 645c3d1a..d72c6732 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -314,5 +314,10 @@ class HellCoreServiceManagerHelper } PHP, ]; + + yield 'make multiple constants definition mixed type' => [ + ' Date: Sun, 1 Jun 2025 10:17:34 +0200 Subject: [PATCH 19/20] Support values with a leading backslash --- README.md | 2 +- src/Fixer/TypedClassConstantFixer.php | 13 ++++++++---- tests/Fixer/TypedClassConstantFixerTest.php | 22 +++++++++++++++++++++ tests/PriorityTest.php | 2 +- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 20715844..bcf82d7f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3748-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3750-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![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) diff --git a/src/Fixer/TypedClassConstantFixer.php b/src/Fixer/TypedClassConstantFixer.php index f1cf7f1f..0776e859 100644 --- a/src/Fixer/TypedClassConstantFixer.php +++ b/src/Fixer/TypedClassConstantFixer.php @@ -96,7 +96,15 @@ private static function fixClass(Tokens $tokens, int $openParenthesisIndex, int continue; } - $type = self::getTypeOfExpression($tokens, $assignmentIndex); + $expressionStartIndex = $tokens->getNextMeaningfulToken($assignmentIndex); + \assert(\is_int($expressionStartIndex)); + + if ($tokens[$expressionStartIndex]->isGivenKind(\T_NS_SEPARATOR)) { + $expressionStartIndex = $tokens->getNextMeaningfulToken($expressionStartIndex); + \assert(\is_int($expressionStartIndex)); + } + + $type = self::getTypeOfExpression($tokens, $expressionStartIndex); $tokens->insertAt( $constantNameIndex, @@ -118,9 +126,6 @@ private static function getTypeOfExpression(Tokens $tokens, int $index): string $foundKinds = []; - $index = $tokens->getNextMeaningfulToken($index); - \assert(\is_int($index)); - $questionMarkCount = 0; do { if ($questionMarkCount > 1) { diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index d72c6732..8c739854 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -125,6 +125,23 @@ public static function provideFixCases(): iterable ' [ + <<<'PHP' + [ ' [ + ' [ <<<'PHP' = 8.1 + * @requires PHP >= 8.3 */ final class PriorityTest extends TestCase { From 5331d22a2a395dbc2f6ed211a4a3293981cbebd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Sun, 1 Jun 2025 10:26:10 +0200 Subject: [PATCH 20/20] Update test --- tests/Fixer/TypedClassConstantFixerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Fixer/TypedClassConstantFixerTest.php b/tests/Fixer/TypedClassConstantFixerTest.php index 8c739854..c1d85a9a 100644 --- a/tests/Fixer/TypedClassConstantFixerTest.php +++ b/tests/Fixer/TypedClassConstantFixerTest.php @@ -337,9 +337,9 @@ class HellCoreServiceManagerHelper PHP, ]; - yield 'make multiple constants definition mixed type' => [ - ' [ + '