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

Breadcrumb

  1. Drupal Core 11.1.x
  2. FunctionCallSignatureSniff.php

function FunctionCallSignatureSniff::processMultiLineCall

Processes multi-line calls.

Parameters

\PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.:

int $stackPtr The position of the current token: in the stack passed in $tokens.

int $openBracket The position of the opening bracket: in the stack passed in $tokens.

array $tokens The stack of tokens that make up: the file.

Return value

void

1 call to FunctionCallSignatureSniff::processMultiLineCall()
FunctionCallSignatureSniff::process in vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php
Processes this test, when one of its tokens is encountered.

File

vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php, line 337

Class

FunctionCallSignatureSniff

Namespace

PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions

Code

public function processMultiLineCall(File $phpcsFile, $stackPtr, $openBracket, $tokens) {
    // We need to work out how far indented the function
    // call itself is, so we can work out how far to
    // indent the arguments.
    $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true);
    if ($first !== false && $tokens[$first]['code'] === T_CONSTANT_ENCAPSED_STRING && $tokens[$first - 1]['code'] === T_CONSTANT_ENCAPSED_STRING) {
        // We are in a multi-line string, so find the start and use
        // the indent from there.
        $prev = $phpcsFile->findPrevious(T_CONSTANT_ENCAPSED_STRING, $first - 2, null, true);
        $first = $phpcsFile->findFirstOnLine(Tokens::$emptyTokens, $prev, true);
        if ($first === false) {
            $first = $prev + 1;
        }
    }
    $foundFunctionIndent = 0;
    if ($first !== false) {
        if ($tokens[$first]['code'] === T_INLINE_HTML || $tokens[$first]['code'] === T_CONSTANT_ENCAPSED_STRING && $tokens[$first - 1]['code'] === T_CONSTANT_ENCAPSED_STRING) {
            $trimmed = ltrim($tokens[$first]['content']);
            if ($trimmed === '') {
                $foundFunctionIndent = strlen($tokens[$first]['content']);
            }
            else {
                $foundFunctionIndent = strlen($tokens[$first]['content']) - strlen($trimmed);
            }
        }
        else {
            $foundFunctionIndent = $tokens[$first]['column'] - 1;
        }
    }
    // Make sure the function indent is divisible by the indent size.
    // We round down here because this accounts for times when the
    // surrounding code is indented a little too far in, and not correctly
    // at a tab stop. Without this, the function will be indented a further
    // $indent spaces to the right.
    $functionIndent = (int) (floor($foundFunctionIndent / $this->indent) * $this->indent);
    $adjustment = 0;
    if ($foundFunctionIndent !== $functionIndent) {
        $error = 'Opening statement of multi-line function call not indented correctly; expected %s spaces but found %s';
        $data = [
            $functionIndent,
            $foundFunctionIndent,
        ];
        $fix = $phpcsFile->addFixableError($error, $first, 'OpeningIndent', $data);
        if ($fix === true) {
            // Set adjustment for use later to determine whether argument indentation is correct when fixing.
            $adjustment = $functionIndent - $foundFunctionIndent;
            $padding = str_repeat(' ', $functionIndent);
            if ($foundFunctionIndent === 0) {
                $phpcsFile->fixer
                    ->addContentBefore($first, $padding);
            }
            else {
                if ($tokens[$first]['code'] === T_INLINE_HTML) {
                    $newContent = $padding . ltrim($tokens[$first]['content']);
                    $phpcsFile->fixer
                        ->replaceToken($first, $newContent);
                }
                else {
                    $phpcsFile->fixer
                        ->replaceToken($first - 1, $padding);
                }
            }
        }
    }
    
    //end if
    $next = $phpcsFile->findNext(Tokens::$emptyTokens, $openBracket + 1, null, true);
    if ($tokens[$next]['line'] === $tokens[$openBracket]['line']) {
        $error = 'Opening parenthesis of a multi-line function call must be the last content on the line';
        $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentAfterOpenBracket');
        if ($fix === true) {
            $phpcsFile->fixer
                ->addContent($openBracket, $phpcsFile->eolChar . str_repeat(' ', $foundFunctionIndent + $this->indent));
        }
    }
    $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
    $prev = $phpcsFile->findPrevious(T_WHITESPACE, $closeBracket - 1, null, true);
    if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
        $error = 'Closing parenthesis of a multi-line function call must be on a line by itself';
        $fix = $phpcsFile->addFixableError($error, $closeBracket, 'CloseBracketLine');
        if ($fix === true) {
            $phpcsFile->fixer
                ->addContentBefore($closeBracket, $phpcsFile->eolChar . str_repeat(' ', $foundFunctionIndent + $this->indent));
        }
    }
    // Each line between the parenthesis should be indented n spaces.
    $lastLine = $tokens[$openBracket]['line'] - 1;
    $argStart = null;
    $argEnd = null;
    // Start processing at the first argument.
    $i = $phpcsFile->findNext(T_WHITESPACE, $openBracket + 1, null, true);
    if ($tokens[$i]['line'] > $tokens[$openBracket]['line'] + 1) {
        $error = 'The first argument in a multi-line function call must be on the line after the opening parenthesis';
        $fix = $phpcsFile->addFixableError($error, $i, 'FirstArgumentPosition');
        if ($fix === true) {
            $phpcsFile->fixer
                ->beginChangeset();
            for ($x = $openBracket + 1; $x < $i; $x++) {
                if ($tokens[$x]['line'] === $tokens[$openBracket]['line']) {
                    continue;
                }
                if ($tokens[$x]['line'] === $tokens[$i]['line']) {
                    break;
                }
                $phpcsFile->fixer
                    ->replaceToken($x, '');
            }
            $phpcsFile->fixer
                ->endChangeset();
        }
    }
    
    //end if
    $i = $phpcsFile->findNext(Tokens::$emptyTokens, $openBracket + 1, null, true);
    if ($tokens[$i - 1]['code'] === T_WHITESPACE && $tokens[$i - 1]['line'] === $tokens[$i]['line']) {
        // Make sure we check the indent.
        $i--;
    }
    for ($i; $i < $closeBracket; $i++) {
        if ($i > $argStart && $i < $argEnd) {
            $inArg = true;
        }
        else {
            $inArg = false;
        }
        if ($tokens[$i]['line'] !== $lastLine) {
            $lastLine = $tokens[$i]['line'];
            // Ignore heredoc indentation.
            if (isset(Tokens::$heredocTokens[$tokens[$i]['code']]) === true) {
                continue;
            }
            // Ignore multi-line string indentation.
            if (isset(Tokens::$stringTokens[$tokens[$i]['code']]) === true && $tokens[$i]['code'] === $tokens[$i - 1]['code']) {
                continue;
            }
            // Ignore inline HTML.
            if ($tokens[$i]['code'] === T_INLINE_HTML) {
                continue;
            }
            if ($tokens[$i]['line'] !== $tokens[$openBracket]['line']) {
                // We changed lines, so this should be a whitespace indent token, but first make
                // sure it isn't a blank line because we don't need to check indent unless there
                // is actually some code to indent.
                if ($tokens[$i]['code'] === T_WHITESPACE) {
                    $nextCode = $phpcsFile->findNext(T_WHITESPACE, $i + 1, $closeBracket + 1, true);
                    if ($tokens[$nextCode]['line'] !== $lastLine) {
                        if ($inArg === false) {
                            $error = 'Empty lines are not allowed in multi-line function calls';
                            $fix = $phpcsFile->addFixableError($error, $i, 'EmptyLine');
                            if ($fix === true) {
                                $phpcsFile->fixer
                                    ->replaceToken($i, '');
                            }
                        }
                        continue;
                    }
                }
                else {
                    $nextCode = $i;
                }
                if ($tokens[$nextCode]['line'] === $tokens[$closeBracket]['line']) {
                    // Closing brace needs to be indented to the same level
                    // as the function call.
                    $inArg = false;
                    $expectedIndent = $foundFunctionIndent + $adjustment;
                }
                else {
                    $expectedIndent = $foundFunctionIndent + $this->indent + $adjustment;
                }
                if ($tokens[$i]['code'] !== T_WHITESPACE && $tokens[$i]['code'] !== T_DOC_COMMENT_WHITESPACE) {
                    // Just check if it is a multi-line block comment. If so, we can
                    // calculate the indent from the whitespace before the content.
                    if ($tokens[$i]['code'] === T_COMMENT && $tokens[$i - 1]['code'] === T_COMMENT) {
                        $trimmedLength = strlen(ltrim($tokens[$i]['content']));
                        if ($trimmedLength === 0) {
                            // This is a blank comment line, so indenting it is
                            // pointless.
                            continue;
                        }
                        $foundIndent = strlen($tokens[$i]['content']) - $trimmedLength;
                    }
                    else {
                        $foundIndent = 0;
                    }
                }
                else {
                    $foundIndent = $tokens[$i]['length'];
                }
                if ($foundIndent < $expectedIndent || $inArg === false && $expectedIndent !== $foundIndent) {
                    $error = 'Multi-line function call not indented correctly; expected %s spaces but found %s';
                    $data = [
                        $expectedIndent,
                        $foundIndent,
                    ];
                    $fix = $phpcsFile->addFixableError($error, $i, 'Indent', $data);
                    if ($fix === true) {
                        $phpcsFile->fixer
                            ->beginChangeset();
                        $padding = str_repeat(' ', $expectedIndent);
                        if ($foundIndent === 0) {
                            $phpcsFile->fixer
                                ->addContentBefore($i, $padding);
                            if (isset($tokens[$i]['scope_opener']) === true) {
                                $phpcsFile->fixer
                                    ->changeCodeBlockIndent($i, $tokens[$i]['scope_closer'], $expectedIndent);
                            }
                        }
                        else {
                            if ($tokens[$i]['code'] === T_COMMENT) {
                                $comment = $padding . ltrim($tokens[$i]['content']);
                                $phpcsFile->fixer
                                    ->replaceToken($i, $comment);
                            }
                            else {
                                $phpcsFile->fixer
                                    ->replaceToken($i, $padding);
                            }
                            if (isset($tokens[$i + 1]['scope_opener']) === true) {
                                $phpcsFile->fixer
                                    ->changeCodeBlockIndent($i + 1, $tokens[$i + 1]['scope_closer'], $expectedIndent - $foundIndent);
                            }
                        }
                        $phpcsFile->fixer
                            ->endChangeset();
                    }
                    
                    //end if
                }
                
                //end if
            }
            else {
                $nextCode = $i;
            }
            
            //end if
            if ($inArg === false) {
                $argStart = $nextCode;
                $argEnd = $phpcsFile->findEndOfStatement($nextCode, [
                    T_COLON,
                ]);
            }
        }
        
        //end if
        // If we are within an argument we should be ignoring commas
        // as these are not signalling the end of an argument.
        if ($inArg === false && $tokens[$i]['code'] === T_COMMA) {
            $next = $phpcsFile->findNext(Tokens::$emptyTokens, $i + 1, $closeBracket, true);
            if ($next === false) {
                continue;
            }
            if ($this->allowMultipleArguments === false) {
                // Comma has to be the last token on the line.
                if ($tokens[$i]['line'] === $tokens[$next]['line']) {
                    $error = 'Only one argument is allowed per line in a multi-line function call';
                    $fix = $phpcsFile->addFixableError($error, $next, 'MultipleArguments');
                    if ($fix === true) {
                        $phpcsFile->fixer
                            ->beginChangeset();
                        for ($x = $next - 1; $x > $i; $x--) {
                            if ($tokens[$x]['code'] !== T_WHITESPACE) {
                                break;
                            }
                            $phpcsFile->fixer
                                ->replaceToken($x, '');
                        }
                        $phpcsFile->fixer
                            ->addContentBefore($next, $phpcsFile->eolChar . str_repeat(' ', $foundFunctionIndent + $this->indent));
                        $phpcsFile->fixer
                            ->endChangeset();
                    }
                }
            }
            
            //end if
            $argStart = $next;
            $argEnd = $phpcsFile->findEndOfStatement($next, [
                T_COLON,
            ]);
        }
        
        //end if
    }
    
    //end for
}
RSS feed
Powered by Drupal