Search code examples
phpphpcodesnifferphpcs

Very simple simple custom phpcs (phpcbf) fixing sniff fails


I am attempting to write a little simple phpcs (phpcbf) sniff to remove whitespace within empty curly braces. I've written quite a few small fixers, and this seemed like it should be very easy.

Basically with the move to promoted parameters, we're ending up with various whitespace setups inside the empty curly braces following the construct like

public function __construct( protected string $cdnPath ) {
}
public function __construct( protected string $cdnPath ) { }
public function __construct( protected string $cdnPath ) {}

I just want to unify these on {}

The sniff as I have it so far

<?php

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;

class CurlyBraceInnerWhiteSpaceSniff implements Sniff {

    public function register() : array {
        return [
            T_OPEN_CURLY_BRACKET,
        ];
    }

    /**
     * @param int $stackPtr
     */
    public function process( File $phpcsFile, $stackPtr ) : void {
        $tokens = $phpcsFile->getTokens();
        if( $tokens[$stackPtr + 1]['code'] !== T_WHITESPACE ) {
            return;
        }

        $closePtr = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true);
        if( $tokens[$closePtr]['code'] !== T_CLOSE_CURLY_BRACKET ) {
            return;
        }

        $fix = $phpcsFile->addFixableError('There must be no whitespace inside empty curly braces', $stackPtr + 1, 'CurlyBraceInnerWhiteSpace');
        if( $fix ) {
            $phpcsFile->fixer->beginChangeset();
            for( $i = $stackPtr + 1; $i < $closePtr; $i++ ) {
                $phpcsFile->fixer->replaceToken($i, '');
            }
            $phpcsFile->fixer->endChangeset();
        }
    }
}

It takes a VERY long time before giving up

running phpcbf with the -v reveals many many entries like this with [made 50 passes]... ERROR

Processing TransformCommand.php [PHP => 636 tokens in 89 lines]... DONE in 11ms (1 fixable violations)
        => Fixing file: 1/1 violations remaining [made 50 passes]... ERROR in 585ms

I found in the documentation somewhere that adding return $phpcsFile->numTokens; to process could help, by preventing the sniff from running against the same file twice, but it has not seemed to help at all.


Solution

  • The problem was that I had another sniff from another collection fighting my sniff.

    It wants to replace {} with { }. Having the two sniffs fighting caused the back and forth which is why it would try 50 times before giving up.