Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x

UselessSemicolonSniff.php

Namespace

SlevomatCodingStandard\Sniffs\PHP

File

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

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal