diff --git a/config/set/standalone-line.php b/config/set/standalone-line.php new file mode 100644 index 0000000000..487a7b32f4 --- /dev/null +++ b/config/set/standalone-line.php @@ -0,0 +1,18 @@ +rules([ + StandaloneLineSymfonyAttributeParamFixer::class, + StandaloneLinePromotedPropertyFixer::class, + StandaloneLinePlainConstructorParamFixer::class, + StandaloneLineRequiredParamFixer::class, + ]); +}; diff --git a/packages/coding-standard/src/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer.php b/packages/coding-standard/src/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer.php new file mode 100644 index 0000000000..29ed460bb1 --- /dev/null +++ b/packages/coding-standard/src/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer.php @@ -0,0 +1,126 @@ + $tokens + */ + public function isCandidate(Tokens $tokens): bool + { + return $tokens->isTokenKindFound(T_ATTRIBUTE); + } + + /** + * @param Tokens $tokens + */ + public function fix(SplFileInfo $fileInfo, Tokens $tokens): void + { + // from the bottom up, as adding tokens shifts every position after them + for ($position = count($tokens) - 1; $position >= 0; --$position) { + /** @var Token $token */ + $token = $tokens[$position]; + + if (! $token->isGivenKind(T_ATTRIBUTE)) { + continue; + } + + $attributeEndPosition = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $position); + + // attribute without arguments, e.g. #[Override]; the next "(" belongs to a later statement + $openBracketPosition = $tokens->getNextTokenOfKind($position, ['(']); + if ($openBracketPosition === null) { + continue; + } + + if ($openBracketPosition > $attributeEndPosition) { + continue; + } + + if (! $this->isSymfonyAttribute($tokens, $position, $openBracketPosition)) { + continue; + } + + $closeBracketPosition = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openBracketPosition); + if ($tokens->getNextMeaningfulToken($openBracketPosition) === $closeBracketPosition) { + // empty argument list, e.g. #[\Symfony\...\AsCommand()] + continue; + } + + $blockInfo = new BlockInfo($openBracketPosition, $closeBracketPosition); + $this->tokensNewliner->breakItems($blockInfo, $tokens, LineKind::CALLS); + } + } + + /** + * @param Tokens $tokens + */ + private function isSymfonyAttribute(Tokens $tokens, int $attributePosition, int $openBracketPosition): bool + { + for ($index = $attributePosition + 1; $index < $openBracketPosition; ++$index) { + /** @var Token $token */ + $token = $tokens[$index]; + + if ($token->isGivenKind(T_STRING) && $token->getContent() === self::SYMFONY_NAMESPACE_PART) { + return true; + } + } + + return false; + } +} diff --git a/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/Fixture/skip_no_arguments.php.inc b/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/Fixture/skip_no_arguments.php.inc new file mode 100644 index 0000000000..b0779c5408 --- /dev/null +++ b/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/Fixture/skip_no_arguments.php.inc @@ -0,0 +1,12 @@ + +----- + diff --git a/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/StandaloneLineSymfonyAttributeParamFixerTest.php b/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/StandaloneLineSymfonyAttributeParamFixerTest.php new file mode 100644 index 0000000000..2b123bba42 --- /dev/null +++ b/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/StandaloneLineSymfonyAttributeParamFixerTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFiles(__DIR__ . '/Fixture'); + } + + public function provideConfig(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/config/configured_rule.php b/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/config/configured_rule.php new file mode 100644 index 0000000000..330da5aeb6 --- /dev/null +++ b/packages/coding-standard/tests/Fixer/Spacing/StandaloneLineSymfonyAttributeParamFixer/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(StandaloneLineSymfonyAttributeParamFixer::class); +}; diff --git a/src/Config/Level/SpacesLevel.php b/src/Config/Level/SpacesLevel.php index c87066e140..6fa48e8b62 100644 --- a/src/Config/Level/SpacesLevel.php +++ b/src/Config/Level/SpacesLevel.php @@ -31,7 +31,6 @@ use PhpCsFixer\Fixer\Whitespace\TypesSpacesFixer; use Symplify\CodingStandard\Fixer\Spacing\MethodChainingNewlineFixer; use Symplify\CodingStandard\Fixer\Spacing\SpaceAfterCommaHereNowDocFixer; -use Symplify\CodingStandard\Fixer\Spacing\StandaloneLinePlainConstructorParamFixer; use Symplify\CodingStandard\Fixer\Spacing\StandaloneLinePromotedPropertyFixer; use Symplify\CodingStandard\Fixer\Spacing\StandaloneLineRequiredParamFixer; use Symplify\CodingStandard\Fixer\Strict\BlankLineAfterStrictTypesFixer; @@ -76,7 +75,6 @@ final class SpacesLevel // most invasive structural changes MethodChainingIndentationFixer::class, StandaloneLinePromotedPropertyFixer::class, - StandaloneLinePlainConstructorParamFixer::class, StandaloneLineRequiredParamFixer::class, MethodArgumentSpaceFixer::class, diff --git a/src/Configuration/ECSConfigBuilder.php b/src/Configuration/ECSConfigBuilder.php index 68a3cf1e17..702ccea2bc 100644 --- a/src/Configuration/ECSConfigBuilder.php +++ b/src/Configuration/ECSConfigBuilder.php @@ -260,6 +260,8 @@ public function withPreparedSets( bool $cleanup = false, /** @see SetList::CLEAN_CODE */ bool $cleanCode = false, + /** @see SetList::STANDALONE_LINE */ + bool $standaloneLine = false, ): self { if (func_get_args() === []) { throw new InitializationException( @@ -330,6 +332,10 @@ public function withPreparedSets( $this->sets[] = SetList::CLEAN_CODE; } + if ($standaloneLine) { + $this->sets[] = SetList::STANDALONE_LINE; + } + if ($symplify) { // soft-deprecated: rules moved to the "common" sets, still loaded for backward compatibility trigger_error( diff --git a/src/ValueObject/Set/SetList.php b/src/ValueObject/Set/SetList.php index 0b48b75329..c43957602a 100644 --- a/src/ValueObject/Set/SetList.php +++ b/src/ValueObject/Set/SetList.php @@ -79,4 +79,9 @@ final class SetList * @api */ public const string LARAVEL = __DIR__ . '/../../../config/set/laravel.php'; + + /** + * @api + */ + public const string STANDALONE_LINE = __DIR__ . '/../../../config/set/standalone-line.php'; }