File "ControlStructureBracesFixer.php"
Full Path: /var/www/html/back/vendor/friendsofphp/php-cs-fixer/src/Fixer/ControlStructure/ControlStructureBracesFixer.php
File size: 7.67 KB
MIME-type: text/x-php
Charset: utf-8
<?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\ControlStructure;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Analyzer\AlternativeSyntaxAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise.
*/
final class ControlStructureBracesFixer extends AbstractFixer
{
private const CONTROL_TOKENS = [
\T_DECLARE,
\T_DO,
\T_ELSE,
\T_ELSEIF,
\T_FINALLY,
\T_FOR,
\T_FOREACH,
\T_IF,
\T_WHILE,
\T_TRY,
\T_CATCH,
\T_SWITCH,
];
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'The body of each control structure MUST be enclosed within braces.',
[new CodeSample("<?php\nif (foo()) echo 'Hello!';\n")],
);
}
public function isCandidate(Tokens $tokens): bool
{
return true;
}
/**
* {@inheritdoc}
*
* Must run before BracesPositionFixer, ControlStructureContinuationPositionFixer, CurlyBracesPositionFixer, NoMultipleStatementsPerLineFixer.
*/
public function getPriority(): int
{
return 1;
}
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$alternativeSyntaxAnalyzer = new AlternativeSyntaxAnalyzer();
for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
$token = $tokens[$index];
if (!$token->isGivenKind(self::CONTROL_TOKENS)) {
continue;
}
if (
$token->isGivenKind(\T_ELSE)
&& $tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(\T_IF)
) {
continue;
}
$parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
$nextAfterParenthesisEndIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
$tokenAfterParenthesis = $tokens[$nextAfterParenthesisEndIndex];
if ($tokenAfterParenthesis->equalsAny([';', '{', ':', [\T_CLOSE_TAG]])) {
continue;
}
$statementEndIndex = null;
if ($tokenAfterParenthesis->isGivenKind([\T_IF, \T_FOR, \T_FOREACH, \T_SWITCH, \T_WHILE])) {
$tokenAfterParenthesisBlockEnd = $tokens->findBlockEnd( // go to ')'
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$tokens->getNextMeaningfulToken($nextAfterParenthesisEndIndex),
);
if ($tokens[$tokens->getNextMeaningfulToken($tokenAfterParenthesisBlockEnd)]->equals(':')) {
$statementEndIndex = $alternativeSyntaxAnalyzer->findAlternativeSyntaxBlockEnd($tokens, $nextAfterParenthesisEndIndex);
$tokenAfterStatementEndIndex = $tokens->getNextMeaningfulToken($statementEndIndex);
if ($tokens[$tokenAfterStatementEndIndex]->equals(';')) {
$statementEndIndex = $tokenAfterStatementEndIndex;
}
}
}
if (null === $statementEndIndex) {
$statementEndIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
}
$tokensToInsertAfterStatement = [
new Token([\T_WHITESPACE, ' ']),
new Token('}'),
];
if (!$tokens[$statementEndIndex]->equalsAny([';', '}'])) {
array_unshift($tokensToInsertAfterStatement, new Token(';'));
}
$tokens->insertSlices([$statementEndIndex + 1 => $tokensToInsertAfterStatement]);
// insert opening brace
$tokens->insertSlices([$parenthesisEndIndex + 1 => [
new Token([\T_WHITESPACE, ' ']),
new Token('{'),
]]);
}
}
private function findParenthesisEnd(Tokens $tokens, int $structureTokenIndex): int
{
$nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
$nextToken = $tokens[$nextIndex];
if (!$nextToken->equals('(')) {
return $structureTokenIndex;
}
return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
}
private function findStatementEnd(Tokens $tokens, int $parenthesisEndIndex): int
{
$nextIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
if (null === $nextIndex) {
return $parenthesisEndIndex;
}
$nextToken = $tokens[$nextIndex];
if ($nextToken->equals('{')) {
return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nextIndex);
}
if ($nextToken->isGivenKind(self::CONTROL_TOKENS)) {
$parenthesisEndIndex = $this->findParenthesisEnd($tokens, $nextIndex);
$endIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
if ($nextToken->isGivenKind([\T_IF, \T_TRY, \T_DO])) {
$openingTokenKind = $nextToken->getId();
while (true) {
$nextIndex = $tokens->getNextMeaningfulToken($endIndex);
if (null !== $nextIndex && $tokens[$nextIndex]->isGivenKind($this->getControlContinuationTokensForOpeningToken($openingTokenKind))) {
$parenthesisEndIndex = $this->findParenthesisEnd($tokens, $nextIndex);
$endIndex = $this->findStatementEnd($tokens, $parenthesisEndIndex);
if ($tokens[$nextIndex]->isGivenKind($this->getFinalControlContinuationTokensForOpeningToken($openingTokenKind))) {
return $endIndex;
}
} else {
break;
}
}
}
return $endIndex;
}
$index = $parenthesisEndIndex;
while (true) {
$token = $tokens[++$index];
// if there is some block in statement (eg lambda function) we need to skip it
if ($token->equals('{')) {
$index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
continue;
}
if ($token->equals(';')) {
return $index;
}
if ($token->isGivenKind(\T_CLOSE_TAG)) {
return $tokens->getPrevNonWhitespace($index);
}
}
}
/**
* @return list<int>
*/
private function getControlContinuationTokensForOpeningToken(int $openingTokenKind): array
{
if (\T_IF === $openingTokenKind) {
return [
\T_ELSE,
\T_ELSEIF,
];
}
if (\T_DO === $openingTokenKind) {
return [\T_WHILE];
}
if (\T_TRY === $openingTokenKind) {
return [
\T_CATCH,
\T_FINALLY,
];
}
return [];
}
/**
* @return list<int>
*/
private function getFinalControlContinuationTokensForOpeningToken(int $openingTokenKind): array
{
if (\T_IF === $openingTokenKind) {
return [\T_ELSE];
}
if (\T_TRY === $openingTokenKind) {
return [\T_FINALLY];
}
return [];
}
}