%PDF- %PDF-
| Direktori : /home/vacivi36/code/vendor/friendsofphp/php-cs-fixer/src/Fixer/Semicolon/ |
| Current File : /home/vacivi36/code/vendor/friendsofphp/php-cs-fixer/src/Fixer/Semicolon/NoEmptyStatementFixer.php |
<?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\Semicolon;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;
/**
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
final class NoEmptyStatementFixer extends AbstractFixer
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Remove useless (semicolon) statements.',
[
new CodeSample("<?php \$a = 1;;\n"),
new CodeSample("<?php echo 1;2;\n"),
new CodeSample("<?php while(foo()){\n continue 1;\n}\n"),
]
);
}
/**
* {@inheritdoc}
*
* Must run before BracesFixer, CombineConsecutiveUnsetsFixer, EmptyLoopBodyFixer, MultilineWhitespaceBeforeSemicolonsFixer, NoExtraBlankLinesFixer, NoMultipleStatementsPerLineFixer, NoSinglelineWhitespaceBeforeSemicolonsFixer, NoTrailingWhitespaceFixer, NoUselessElseFixer, NoUselessReturnFixer, NoWhitespaceInBlankLineFixer, ReturnAssignmentFixer, SpaceAfterSemicolonFixer, SwitchCaseSemicolonToColonFixer.
* Must run after NoUselessSprintfFixer.
*/
public function getPriority(): int
{
return 40;
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(';');
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
if ($tokens[$index]->isGivenKind([T_BREAK, T_CONTINUE])) {
$index = $tokens->getNextMeaningfulToken($index);
if ($tokens[$index]->equals([T_LNUMBER, '1'])) {
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
}
continue;
}
// skip T_FOR parenthesis to ignore double `;` like `for ($i = 1; ; ++$i) {...}`
if ($tokens[$index]->isGivenKind(T_FOR)) {
$index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($index)) + 1;
continue;
}
if (!$tokens[$index]->equals(';')) {
continue;
}
$previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($index);
// A semicolon can always be removed if it follows a semicolon, '{' or opening tag.
if ($tokens[$previousMeaningfulIndex]->equalsAny(['{', ';', [T_OPEN_TAG]])) {
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
continue;
}
// A semicolon might be removed if it follows a '}' but only if the brace is part of certain structures.
if ($tokens[$previousMeaningfulIndex]->equals('}')) {
$this->fixSemicolonAfterCurlyBraceClose($tokens, $index, $previousMeaningfulIndex);
continue;
}
// A semicolon might be removed together with its noop statement, for example "<?php 1;"
$prePreviousMeaningfulIndex = $tokens->getPrevMeaningfulToken($previousMeaningfulIndex);
if (
$tokens[$prePreviousMeaningfulIndex]->equalsAny([';', '{', '}', [T_OPEN_TAG]])
&& $tokens[$previousMeaningfulIndex]->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_DNUMBER, T_LNUMBER, T_STRING, T_VARIABLE])
) {
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
$tokens->clearTokenAndMergeSurroundingWhitespace($previousMeaningfulIndex);
}
}
}
/**
* Fix semicolon after closing curly brace if needed.
*
* Test for the following cases
* - just '{' '}' block (following open tag or ';')
* - if, else, elseif
* - interface, trait, class (but not anonymous)
* - catch, finally (but not try)
* - for, foreach, while (but not 'do - while')
* - switch
* - function (declaration, but not lambda)
* - declare (with '{' '}')
* - namespace (with '{' '}')
*
* @param int $index Semicolon index
*/
private function fixSemicolonAfterCurlyBraceClose(Tokens $tokens, int $index, int $curlyCloseIndex): void
{
static $beforeCurlyOpeningKinds = null;
if (null === $beforeCurlyOpeningKinds) {
$beforeCurlyOpeningKinds = [T_ELSE, T_FINALLY, T_NAMESPACE, T_OPEN_TAG];
}
$curlyOpeningIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $curlyCloseIndex);
$beforeCurlyOpeningIndex = $tokens->getPrevMeaningfulToken($curlyOpeningIndex);
if ($tokens[$beforeCurlyOpeningIndex]->isGivenKind($beforeCurlyOpeningKinds) || $tokens[$beforeCurlyOpeningIndex]->equalsAny([';', '{', '}'])) {
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
return;
}
// check for namespaces and class, interface and trait definitions
if ($tokens[$beforeCurlyOpeningIndex]->isGivenKind(T_STRING)) {
$classyTestIndex = $tokens->getPrevMeaningfulToken($beforeCurlyOpeningIndex);
while ($tokens[$classyTestIndex]->equals(',') || $tokens[$classyTestIndex]->isGivenKind([T_STRING, T_NS_SEPARATOR, T_EXTENDS, T_IMPLEMENTS])) {
$classyTestIndex = $tokens->getPrevMeaningfulToken($classyTestIndex);
}
$tokensAnalyzer = new TokensAnalyzer($tokens);
if (
$tokens[$classyTestIndex]->isGivenKind(T_NAMESPACE)
|| ($tokens[$classyTestIndex]->isClassy() && !$tokensAnalyzer->isAnonymousClass($classyTestIndex))
) {
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
}
return;
}
// early return check, below only control structures with conditions are fixed
if (!$tokens[$beforeCurlyOpeningIndex]->equals(')')) {
return;
}
$openingBraceIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $beforeCurlyOpeningIndex);
$beforeOpeningBraceIndex = $tokens->getPrevMeaningfulToken($openingBraceIndex);
if ($tokens[$beforeOpeningBraceIndex]->isGivenKind([T_IF, T_ELSEIF, T_FOR, T_FOREACH, T_WHILE, T_SWITCH, T_CATCH, T_DECLARE])) {
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
return;
}
// check for function definition
if ($tokens[$beforeOpeningBraceIndex]->isGivenKind(T_STRING)) {
$beforeStringIndex = $tokens->getPrevMeaningfulToken($beforeOpeningBraceIndex);
if ($tokens[$beforeStringIndex]->isGivenKind(T_FUNCTION)) {
$tokens->clearTokenAndMergeSurroundingWhitespace($index); // implicit return
}
}
}
}