UselessSemicolonSniff.php
Namespace
SlevomatCodingStandard\Sniffs\PHPFile
-
vendor/
slevomat/ coding-standard/ SlevomatCodingStandard/ Sniffs/ PHP/ UselessSemicolonSniff.php
View source
<?php
declare (strict_types=1);
namespace SlevomatCodingStandard\Sniffs\PHP;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use SlevomatCodingStandard\Helpers\FixerHelper;
use SlevomatCodingStandard\Helpers\TokenHelper;
use function array_key_exists;
use function count;
use function in_array;
use const T_ANON_CLASS;
use const T_CLOSE_CURLY_BRACKET;
use const T_CLOSE_PARENTHESIS;
use const T_CLOSURE;
use const T_FN;
use const T_FOR;
use const T_MATCH;
use const T_OPEN_CURLY_BRACKET;
use const T_OPEN_TAG;
use const T_SEMICOLON;
use const T_WHITESPACE;
class UselessSemicolonSniff implements Sniff {
public const CODE_USELESS_SEMICOLON = 'UselessSemicolon';
/**
* @return array<int, (int|string)>
*/
public function register() : array {
return [
T_SEMICOLON,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $semicolonPointer
*/
public function process(File $phpcsFile, $semicolonPointer) : void {
$this->checkMultipleSemicolons($phpcsFile, $semicolonPointer);
$this->checkSemicolonAtTheBeginningOfScope($phpcsFile, $semicolonPointer);
$this->checkSemicolonAfterScope($phpcsFile, $semicolonPointer);
}
private function checkMultipleSemicolons(File $phpcsFile, int $semicolonPointer) : void {
$tokens = $phpcsFile->getTokens();
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $semicolonPointer - 1);
if ($tokens[$previousPointer]['code'] !== T_SEMICOLON) {
return;
}
$possibleEndScopePointer = TokenHelper::findNextLocal($phpcsFile, T_CLOSE_PARENTHESIS, $semicolonPointer + 1);
if ($possibleEndScopePointer !== null && $tokens[$possibleEndScopePointer]['parenthesis_opener'] < $semicolonPointer && array_key_exists('parenthesis_owner', $tokens[$possibleEndScopePointer]) && $tokens[$tokens[$possibleEndScopePointer]['parenthesis_owner']]['code'] === T_FOR) {
return;
}
$fix = $phpcsFile->addFixableError('Useless semicolon.', $semicolonPointer, self::CODE_USELESS_SEMICOLON);
if (!$fix) {
return;
}
$this->removeUselessSemicolon($phpcsFile, $semicolonPointer);
}
private function checkSemicolonAtTheBeginningOfScope(File $phpcsFile, int $semicolonPointer) : void {
$tokens = $phpcsFile->getTokens();
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $semicolonPointer - 1);
if (!in_array($tokens[$previousPointer]['code'], [
T_OPEN_TAG,
T_OPEN_CURLY_BRACKET,
], true)) {
return;
}
$fix = $phpcsFile->addFixableError('Useless semicolon.', $semicolonPointer, self::CODE_USELESS_SEMICOLON);
if (!$fix) {
return;
}
$this->removeUselessSemicolon($phpcsFile, $semicolonPointer);
}
private function checkSemicolonAfterScope(File $phpcsFile, int $semicolonPointer) : void {
$tokens = $phpcsFile->getTokens();
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $semicolonPointer - 1);
if ($tokens[$previousPointer]['code'] !== T_CLOSE_CURLY_BRACKET) {
return;
}
if (!array_key_exists('scope_condition', $tokens[$previousPointer])) {
return;
}
$scopeOpenerPointer = $tokens[$previousPointer]['scope_condition'];
if (in_array($tokens[$scopeOpenerPointer]['code'], [
T_CLOSURE,
T_FN,
T_ANON_CLASS,
T_MATCH,
], true)) {
return;
}
$fix = $phpcsFile->addFixableError('Useless semicolon.', $semicolonPointer, self::CODE_USELESS_SEMICOLON);
if (!$fix) {
return;
}
$this->removeUselessSemicolon($phpcsFile, $semicolonPointer);
}
private function removeUselessSemicolon(File $phpcsFile, int $semicolonPointer) : void {
$tokens = $phpcsFile->getTokens();
$fixStartPointer = $semicolonPointer;
do {
if ($tokens[$fixStartPointer - 1]['code'] !== T_WHITESPACE) {
break;
}
$fixStartPointer--;
if ($tokens[$fixStartPointer]['content'] === $phpcsFile->eolChar) {
break;
}
} while (true);
$fixEndPointer = $semicolonPointer;
while ($fixEndPointer < count($tokens) - 1) {
if ($tokens[$fixEndPointer + 1]['code'] !== T_WHITESPACE) {
break;
}
if ($tokens[$fixEndPointer + 1]['content'] === $phpcsFile->eolChar) {
break;
}
$fixEndPointer++;
}
$phpcsFile->fixer
->beginChangeset();
FixerHelper::removeBetweenIncluding($phpcsFile, $fixStartPointer, $fixEndPointer);
$phpcsFile->fixer
->endChangeset();
}
}
Classes
Title | Deprecated | Summary |
---|---|---|
UselessSemicolonSniff |