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
/
Whitespace
:
SpacesInsideParenthesesFixer.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\Whitespace; use PhpCsFixer\AbstractFixer; use PhpCsFixer\Fixer\ConfigurableFixerInterface; use PhpCsFixer\Fixer\ConfigurableFixerTrait; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; use PhpCsFixer\FixerConfiguration\FixerOptionBuilder; use PhpCsFixer\FixerDefinition\CodeSample; use PhpCsFixer\FixerDefinition\FixerDefinition; use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; /** * Fixer for rules defined in PSR2 ¶4.3, ¶4.6, ¶5. * * @phpstan-type _AutogeneratedInputConfiguration array{ * space?: 'none'|'single', * } * @phpstan-type _AutogeneratedComputedConfiguration array{ * space: 'none'|'single', * } * * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> * * @author Marc Aubé * @author Dariusz Rumiński <dariusz.ruminski@gmail.com> * * @no-named-arguments Parameter names are not covered by the backward compatibility promise. */ final class SpacesInsideParenthesesFixer extends AbstractFixer implements ConfigurableFixerInterface { /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */ use ConfigurableFixerTrait; public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( 'Parentheses must be declared using the configured whitespace.', [ new CodeSample( <<<'PHP' <?php if ( $a ) { foo( ); } PHP, ), new CodeSample( <<<'PHP' <?php function foo( $bar, $baz ) { } PHP, ['space' => 'none'], ), new CodeSample( <<<'PHP' <?php if ($a) { foo( ); } PHP, ['space' => 'single'], ), new CodeSample( <<<'PHP' <?php function foo($bar, $baz) { } PHP, ['space' => 'single'], ), ], 'By default there are not any additional spaces inside parentheses, however with `space=single` configuration option whitespace inside parentheses will be unified to single space.', ); } /** * {@inheritdoc} * * Must run before FunctionToConstantFixer, GetClassToClassKeywordFixer, StringLengthToEmptyFixer. * Must run after CombineConsecutiveIssetsFixer, CombineNestedDirnameFixer, IncrementStyleFixer, LambdaNotUsedImportFixer, ModernizeStrposFixer, NoUselessSprintfFixer, PowToExponentiationFixer. */ public function getPriority(): int { return 3; } public function isCandidate(Tokens $tokens): bool { return $tokens->isAnyTokenKindsFound(['(', CT::T_BRACE_CLASS_INSTANTIATION_OPEN]); } protected function applyFix(\SplFileInfo $file, Tokens $tokens): void { if ('none' === $this->configuration['space']) { foreach ($tokens as $index => $token) { if (!$token->equalsAny(['(', [CT::T_BRACE_CLASS_INSTANTIATION_OPEN]])) { continue; } $prevIndex = $tokens->getPrevMeaningfulToken($index); // ignore parenthesis for T_ARRAY if (null !== $prevIndex && $tokens[$prevIndex]->isGivenKind(\T_ARRAY)) { continue; } $blockType = Tokens::detectBlockType($token); $endIndex = $tokens->findBlockEnd($blockType['type'], $index); // remove space after opening `(` if (!$tokens[$tokens->getNextNonWhitespace($index)]->isComment()) { $this->removeSpaceAroundToken($tokens, $index + 1); } // remove space before closing `)` if it is not `list($a, $b, )` case if (!$tokens[$tokens->getPrevMeaningfulToken($endIndex)]->equals(',')) { $this->removeSpaceAroundToken($tokens, $endIndex - 1); } } } if ('single' === $this->configuration['space']) { foreach ($tokens as $index => $token) { if (!$token->equalsAny(['(', [CT::T_BRACE_CLASS_INSTANTIATION_OPEN]])) { continue; } $blockType = Tokens::detectBlockType($token); $endParenthesisIndex = $tokens->findBlockEnd($blockType['type'], $index); // if not other content than spaces in block remove spaces $blockContent = $this->getBlockContent($index, $endParenthesisIndex, $tokens); if (1 === \count($blockContent) && \in_array(' ', $blockContent, true)) { $this->removeSpaceAroundToken($tokens, $index + 1); continue; } // don't process if the next token is `)` $nextMeaningfulTokenIndex = $tokens->getNextMeaningfulToken($index); if (')' === $tokens[$nextMeaningfulTokenIndex]->getContent()) { continue; } $afterParenthesisIndex = $tokens->getNextNonWhitespace($endParenthesisIndex); $afterParenthesisToken = $tokens[$afterParenthesisIndex]; if ($afterParenthesisToken->isGivenKind(CT::T_USE_LAMBDA)) { $useStartParenthesisIndex = $tokens->getNextTokenOfKind($afterParenthesisIndex, ['(']); $useEndParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $useStartParenthesisIndex); // add single-line edge whitespaces inside use parentheses $this->fixParenthesisInnerEdge($tokens, $useStartParenthesisIndex, $useEndParenthesisIndex); } // add single-line edge whitespaces inside parameters list parentheses $this->fixParenthesisInnerEdge($tokens, $index, $endParenthesisIndex); } } } protected function createConfigurationDefinition(): FixerConfigurationResolverInterface { return new FixerConfigurationResolver([ (new FixerOptionBuilder('space', 'Whether to have `single` or `none` space inside parentheses.')) ->setAllowedValues(['none', 'single']) ->setDefault('none') ->getOption(), ]); } /** * Remove spaces from token at a given index. */ private function removeSpaceAroundToken(Tokens $tokens, int $index): void { $token = $tokens[$index]; if ($token->isWhitespace() && !str_contains($token->getContent(), "\n")) { $tokens->clearAt($index); } } private function fixParenthesisInnerEdge(Tokens $tokens, int $start, int $end): void { // fix white space before ')' if ($tokens[$end - 1]->isWhitespace()) { $content = $tokens[$end - 1]->getContent(); if (' ' !== $content && !str_contains($content, "\n") && !$tokens[$tokens->getPrevNonWhitespace($end - 1)]->isComment()) { $tokens[$end - 1] = new Token([\T_WHITESPACE, ' ']); } } else { $tokens->insertAt($end, new Token([\T_WHITESPACE, ' '])); } // fix white space after '(' if ($tokens[$start + 1]->isWhitespace()) { $content = $tokens[$start + 1]->getContent(); if (' ' !== $content && !str_contains($content, "\n") && !$tokens[$tokens->getNextNonWhitespace($start + 1)]->isComment()) { $tokens[$start + 1] = new Token([\T_WHITESPACE, ' ']); } } else { $tokens->insertAt($start + 1, new Token([\T_WHITESPACE, ' '])); } } /** * @return list<string> */ private function getBlockContent(int $startIndex, int $endIndex, Tokens $tokens): array { // + 1 for ( $contents = []; for ($i = ($startIndex + 1); $i < $endIndex; ++$i) { $contents[] = $tokens[$i]->getContent(); } return $contents; } }