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

Breadcrumb

  1. Drupal Core 11.1.x

RequireSingleLineCallSniff.php

Namespace

SlevomatCodingStandard\Sniffs\Functions

File

vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireSingleLineCallSniff.php

View source
<?php

declare (strict_types=1);
namespace SlevomatCodingStandard\Sniffs\Functions;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;
use SlevomatCodingStandard\Helpers\FixerHelper;
use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
use SlevomatCodingStandard\Helpers\TokenHelper;
use function array_key_exists;
use function array_merge;
use function array_reverse;
use function in_array;
use function ltrim;
use function sprintf;
use function strlen;
use function strpos;
use const T_CLOSURE;
use const T_CONSTANT_ENCAPSED_STRING;
use const T_DOUBLE_COLON;
use const T_DOUBLE_QUOTED_STRING;
use const T_FN;
use const T_FUNCTION;
use const T_NEW;
use const T_OBJECT_OPERATOR;
use const T_OPEN_PARENTHESIS;
use const T_OPEN_SHORT_ARRAY;
use const T_STRING;
class RequireSingleLineCallSniff extends AbstractLineCall {
    public const CODE_REQUIRED_SINGLE_LINE_CALL = 'RequiredSingleLineCall';
    
    /** @var int */
    public $maxLineLength = 120;
    
    /** @var bool */
    public $ignoreWithComplexParameter = true;
    
    /**
     * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
     * @param int $stringPointer
     */
    public function process(File $phpcsFile, $stringPointer) : void {
        $this->maxLineLength = SniffSettingsHelper::normalizeInteger($this->maxLineLength);
        if (!$this->isCall($phpcsFile, $stringPointer)) {
            return;
        }
        if ($this->shouldBeSkipped($phpcsFile, $stringPointer)) {
            return;
        }
        $tokens = $phpcsFile->getTokens();
        $parenthesisOpenerPointer = TokenHelper::findNextEffective($phpcsFile, $stringPointer + 1);
        $parenthesisCloserPointer = $tokens[$parenthesisOpenerPointer]['parenthesis_closer'];
        if ($tokens[$parenthesisOpenerPointer]['line'] === $tokens[$parenthesisCloserPointer]['line']) {
            return;
        }
        if (TokenHelper::findNext($phpcsFile, array_merge(TokenHelper::$inlineCommentTokenCodes, Tokens::$heredocTokens), $parenthesisOpenerPointer + 1, $parenthesisCloserPointer) !== null) {
            return;
        }
        for ($i = $parenthesisOpenerPointer + 1; $i < $parenthesisCloserPointer; $i++) {
            if ($tokens[$i]['code'] !== T_CONSTANT_ENCAPSED_STRING && $tokens[$i]['code'] !== T_DOUBLE_QUOTED_STRING) {
                continue;
            }
            if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) !== false) {
                return;
            }
        }
        if ($this->ignoreWithComplexParameter) {
            if (TokenHelper::findNext($phpcsFile, [
                T_CLOSURE,
                T_FN,
                T_OPEN_SHORT_ARRAY,
            ], $parenthesisOpenerPointer + 1, $parenthesisCloserPointer) !== null) {
                return;
            }
            // Contains inner call
            $callSearchStartPointer = $parenthesisOpenerPointer + 1;
            $nameTokenCodes = TokenHelper::getOnlyNameTokenCodes();
            while (true) {
                $innerStringPointer = TokenHelper::findNext($phpcsFile, $nameTokenCodes, $callSearchStartPointer, $parenthesisCloserPointer);
                if ($innerStringPointer === null) {
                    break;
                }
                $pointerAfterInnerString = TokenHelper::findNextEffective($phpcsFile, $innerStringPointer + 1);
                if ($pointerAfterInnerString !== null && $tokens[$pointerAfterInnerString]['code'] === T_OPEN_PARENTHESIS) {
                    return;
                }
                $callSearchStartPointer = $innerStringPointer + 1;
            }
        }
        $lineStart = $this->getLineStart($phpcsFile, $parenthesisOpenerPointer);
        $call = $this->getCall($phpcsFile, $parenthesisOpenerPointer, $parenthesisCloserPointer);
        $lineEnd = $this->getLineEnd($phpcsFile, $parenthesisCloserPointer);
        $lineLength = strlen($lineStart . $call . $lineEnd);
        if (!$this->shouldReportError($lineLength)) {
            return;
        }
        $previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $stringPointer - 1);
        $name = ltrim($tokens[$stringPointer]['content'], '\\');
        if (in_array($tokens[$previousPointer]['code'], [
            T_OBJECT_OPERATOR,
            T_DOUBLE_COLON,
        ], true)) {
            $error = sprintf('Call of method %s() should be placed on a single line.', $name);
        }
        elseif ($tokens[$previousPointer]['code'] === T_NEW) {
            $error = 'Constructor call should be placed on a single line.';
        }
        else {
            $error = sprintf('Call of function %s() should be placed on a single line.', $name);
        }
        $fix = $phpcsFile->addFixableError($error, $stringPointer, self::CODE_REQUIRED_SINGLE_LINE_CALL);
        if (!$fix) {
            return;
        }
        $phpcsFile->fixer
            ->beginChangeset();
        $phpcsFile->fixer
            ->addContent($parenthesisOpenerPointer, $call);
        FixerHelper::removeBetween($phpcsFile, $parenthesisOpenerPointer, $parenthesisCloserPointer);
        $phpcsFile->fixer
            ->endChangeset();
    }
    private function shouldBeSkipped(File $phpcsFile, int $stringPointer) : bool {
        $tokens = $phpcsFile->getTokens();
        foreach (array_reverse(TokenHelper::findNextAll($phpcsFile, [
            T_OPEN_PARENTHESIS,
            T_FUNCTION,
        ], 0, $stringPointer)) as $pointer) {
            if ($tokens[$pointer]['code'] === T_FUNCTION) {
                if (array_key_exists('scope_closer', $tokens[$pointer]) && $tokens[$pointer]['scope_closer'] > $stringPointer) {
                    return false;
                }
                continue;
            }
            if ($tokens[$pointer]['parenthesis_closer'] < $stringPointer) {
                continue;
            }
            $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $pointer - 1);
            if ($pointerBeforeParenthesisOpener === null || $tokens[$pointerBeforeParenthesisOpener]['code'] !== T_STRING) {
                continue;
            }
            return true;
        }
        return false;
    }
    private function shouldReportError(int $lineLength) : bool {
        if ($this->maxLineLength === 0) {
            return true;
        }
        return $lineLength <= $this->maxLineLength;
    }

}

Classes

Title Deprecated Summary
RequireSingleLineCallSniff

API Navigation

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