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
Namespace
PHP_CodeSniffer\Standards\PEAR\Sniffs\FunctionsCode
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
}