Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
tipuloidea
/
back
/
vendor
/
friendsofphp
/
php-cs-fixer
/
src
/
Fixer
/
FunctionNotation
:
MultilinePromotedPropertiesFixer.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php declare(strict_types=1); /* * This file is part of PHP CS Fixer. * * (c) Fabien Potencier <fabien@symfony.com> * Dariusz RumiĆski <dariusz.ruminski@gmail.com> * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Fixer\FunctionNotation; use PhpCsFixer\AbstractFixer; use PhpCsFixer\Fixer\ConfigurableFixerInterface; use PhpCsFixer\Fixer\ConfigurableFixerTrait; use PhpCsFixer\Fixer\ExperimentalFixerInterface; use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; use PhpCsFixer\FixerConfiguration\FixerOptionBuilder; use PhpCsFixer\FixerDefinition\FixerDefinition; use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; use PhpCsFixer\FixerDefinition\VersionSpecification; use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample; use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer; use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\Tokens; use PhpCsFixer\Tokenizer\TokensAnalyzer; /** * @phpstan-type _InputConfig array{keep_blank_lines?: bool, minimum_number_of_parameters?: int} * @phpstan-type _Config array{keep_blank_lines: bool, minimum_number_of_parameters: int} * @phpstan-type _AutogeneratedInputConfiguration array{ * keep_blank_lines?: bool, * minimum_number_of_parameters?: int, * } * @phpstan-type _AutogeneratedComputedConfiguration array{ * keep_blank_lines: bool, * minimum_number_of_parameters: int, * } * @phpstan-type _ConstructorAnalysis array{ * index?: int, * parameter_names: list<string>, * promotable_parameters: array<int, string>, * constructor_index?: int, * } * * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> * * @TODO align on default configuration and remove experimental flag - https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/8718 * * @no-named-arguments Parameter names are not covered by the backward compatibility promise. */ final class MultilinePromotedPropertiesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface, ExperimentalFixerInterface { /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */ use ConfigurableFixerTrait; public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( 'Promoted properties must be on separate lines.', [ new VersionSpecificCodeSample( <<<'PHP' <?php class Foo { public function __construct(private array $a, private bool $b, private int $i) {} } PHP, new VersionSpecification(80_000), ), new VersionSpecificCodeSample( <<<'PHP' <?php class Foo { public function __construct(private array $a, private bool $b, private int $i) {} } class Bar { public function __construct(private array $x) {} } PHP, new VersionSpecification(80_000), ['minimum_number_of_parameters' => 3], ), ], ); } /** * {@inheritdoc} * * Must run before BracesPositionFixer, TrailingCommaInMultilineFixer. */ public function getPriority(): int { return 1; } public function isCandidate(Tokens $tokens): bool { return $tokens->isAnyTokenKindsFound([ CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, ]); } protected function createConfigurationDefinition(): FixerConfigurationResolverInterface { return new FixerConfigurationResolver([ (new FixerOptionBuilder('keep_blank_lines', 'Whether to keep blank lines between properties.')) ->setAllowedTypes(['bool']) ->setDefault(false) ->getOption(), (new FixerOptionBuilder('minimum_number_of_parameters', 'Minimum number of parameters in the constructor to fix.')) ->setAllowedTypes(['int']) ->setDefault(1) ->getOption(), ]); } protected function applyFix(\SplFileInfo $file, Tokens $tokens): void { $tokensAnalyzer = new TokensAnalyzer($tokens); foreach ($tokensAnalyzer->getClassyElements() as $index => $element) { if ('method' !== $element['type']) { continue; } $openParenthesisIndex = $tokens->getNextTokenOfKind($index, ['(']); $closeParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesisIndex); if (!$this->shouldBeFixed($tokens, $openParenthesisIndex, $closeParenthesisIndex)) { continue; } $this->fixParameters($tokens, $openParenthesisIndex, $closeParenthesisIndex); } } private function shouldBeFixed(Tokens $tokens, int $openParenthesisIndex, int $closeParenthesisIndex): bool { $promotedParameterFound = false; $minimumNumberOfParameters = 0; for ($index = $openParenthesisIndex + 1; $index < $closeParenthesisIndex; ++$index) { if ($tokens[$index]->isGivenKind(\T_VARIABLE)) { ++$minimumNumberOfParameters; } if ( $tokens[$index]->isGivenKind([ CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, ]) ) { $promotedParameterFound = true; } } return $promotedParameterFound && $minimumNumberOfParameters >= $this->configuration['minimum_number_of_parameters']; } private function fixParameters(Tokens $tokens, int $openParenthesis, int $closeParenthesis): void { $indent = WhitespacesAnalyzer::detectIndent($tokens, $openParenthesis); $tokens->ensureWhitespaceAtIndex( $closeParenthesis - 1, 1, $this->whitespacesConfig->getLineEnding().$indent, ); $index = $tokens->getPrevMeaningfulToken($closeParenthesis); \assert(\is_int($index)); while ($index > $openParenthesis) { $index = $tokens->getPrevMeaningfulToken($index); \assert(\is_int($index)); $blockType = Tokens::detectBlockType($tokens[$index]); if (null !== $blockType && !$blockType['isStart']) { $index = $tokens->findBlockStart($blockType['type'], $index); continue; } if (!$tokens[$index]->equalsAny(['(', ','])) { continue; } $this->fixParameter($tokens, $index + 1, $indent); } } private function fixParameter(Tokens $tokens, int $index, string $indent): void { if ($this->configuration['keep_blank_lines'] && $tokens[$index]->isWhitespace() && str_contains($tokens[$index]->getContent(), "\n")) { return; } $tokens->ensureWhitespaceAtIndex( $index, 0, $this->whitespacesConfig->getLineEnding().$indent.$this->whitespacesConfig->getIndent(), ); } }