Skip to content

Commit 9286141

Browse files
committed
PEAR.Functions.FunctionCallSignature now throws an error if the opening statement is not indented correctly (ref #1759)
If the opening statement is not indented to an exact tab stop, it can throw out the indent of the closing parenthesis, which can end up conflicting with the scope indent sniff.
1 parent b4c960e commit 9286141

File tree

5 files changed

+82
-36
lines changed

5 files changed

+82
-36
lines changed

package.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ http://pear.php.net/dtd/package-2.0.xsd">
9898
-- Override the 'requiredSpacesBeforeColon' setting in a ruleset.xml file to change
9999
-- Default remains at 1
100100
-- Thanks to Nikola Kovacs for the patch
101-
- PEAR.Functions.FunctionCallSignature now requires the function keyword to be indented to an exact tab stop
101+
- PEAR.Functions.FunctionCallSignature now requires the function name to be indented to an exact tab stop
102+
-- If the function name is not the start of the statement, the opening statement must be indented correctly instead
103+
-- Added a new fixable error code PEAR.Functions.FunctionCallSignature.OpeningIndent for this error
102104
- The Squiz standard now ensures array keys are indented 4 spaces from the main statement
103105
-- Previously, this standard aligned keys 1 space from the start of the array keyword
104106
- The Squiz standard now ensures array end braces are aligned with the main statement

src/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -338,40 +338,53 @@ public function processMultiLineCall(File $phpcsFile, $stackPtr, $openBracket, $
338338
// We need to work out how far indented the function
339339
// call itself is, so we can work out how far to
340340
// indent the arguments.
341-
$start = $phpcsFile->findStartOfStatement($stackPtr);
342-
foreach (['stackPtr', 'start'] as $checkToken) {
343-
$x = $$checkToken;
344-
for ($i = ($x - 1); $i >= 0; $i--) {
345-
if ($tokens[$i]['line'] !== $tokens[$x]['line']) {
346-
$i++;
347-
break;
348-
}
349-
}
341+
$first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true);
342+
if ($tokens[$first]['code'] === T_CONSTANT_ENCAPSED_STRING
343+
&& $tokens[($first - 1)]['code'] === T_CONSTANT_ENCAPSED_STRING
344+
) {
345+
// We are in a multi-line string, so find the start and use
346+
// the indent from there.
347+
$prev = $phpcsFile->findPrevious(T_CONSTANT_ENCAPSED_STRING, ($first - 2), null, true);
348+
$first = $phpcsFile->findFirstOnLine(Tokens::$emptyTokens, $prev, true);
349+
}
350350

351-
if ($i <= 0) {
352-
$functionIndent = 0;
353-
} else if ($tokens[$i]['code'] === T_WHITESPACE) {
354-
$functionIndent = strlen($tokens[$i]['content']);
355-
} else if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING) {
356-
$functionIndent = 0;
357-
} else {
358-
$trimmed = ltrim($tokens[$i]['content']);
351+
$foundIndent = 0;
352+
if ($first !== false) {
353+
if ($tokens[$first]['code'] === T_INLINE_HTML) {
354+
$trimmed = ltrim($tokens[$first]['content']);
359355
if ($trimmed === '') {
360-
if ($tokens[$i]['code'] === T_INLINE_HTML) {
361-
$functionIndent = strlen($tokens[$i]['content']);
362-
} else {
363-
$functionIndent = ($tokens[$i]['column'] - 1);
364-
}
356+
$foundIndent = strlen($tokens[$first]['content']);
365357
} else {
366-
$functionIndent = (strlen($tokens[$i]['content']) - strlen($trimmed));
358+
$foundIndent = (strlen($tokens[$first]['content']) - strlen($trimmed));
367359
}
360+
} else {
361+
$foundIndent = ($tokens[$first]['column'] - 1);
368362
}
363+
}
369364

370-
$varName = $checkToken.'Indent';
371-
$$varName = $functionIndent;
372-
}//end foreach
365+
// Make sure the function indent is divisible by the indent size.
366+
// We round down here because this accounts for times when the
367+
// surrounding code is indented a little too far in, and not correctly
368+
// at a tab stop. Without this, the function will be indented a further
369+
// $indent spaces to the right.
370+
$functionIndent = (int) (floor($foundIndent / $this->indent) * $this->indent);
371+
if ($foundIndent !== $functionIndent) {
372+
$error = 'Opening statement of multi-line function call not indented correctly; expected %s spaces but found %s';
373+
$data = [
374+
$functionIndent,
375+
$foundIndent,
376+
];
373377

374-
$functionIndent = max($startIndent, $stackPtrIndent);
378+
$fix = $phpcsFile->addFixableError($error, $first, 'OpeningIndent', $data);
379+
if ($fix === true) {
380+
$padding = str_repeat(' ', $functionIndent);
381+
if ($foundIndent === 0) {
382+
$phpcsFile->fixer->addContentBefore($first, $padding);
383+
} else {
384+
$phpcsFile->fixer->replaceToken(($first - 1), $padding);
385+
}
386+
}
387+
}
375388

376389
$next = $phpcsFile->findNext(Tokens::$emptyTokens, ($openBracket + 1), null, true);
377390
if ($tokens[$next]['line'] === $tokens[$openBracket]['line']) {
@@ -470,13 +483,6 @@ public function processMultiLineCall(File $phpcsFile, $stackPtr, $openBracket, $
470483
$expectedIndent = ($functionIndent + $this->indent);
471484
}
472485

473-
// Make sure the expected indent is divisible by the indent size.
474-
// We round down here because this accounts for times when the
475-
// surrounding code is indented a little too far in, and not correctly
476-
// at a tab stop. Without this, the function will be indented a further
477-
// $indent spaces to the right.
478-
$expectedIndent = (int) (floor($expectedIndent / $this->indent) * $this->indent);
479-
480486
if ($tokens[$i]['code'] !== T_WHITESPACE
481487
&& $tokens[$i]['code'] !== T_DOC_COMMENT_WHITESPACE
482488
) {

src/Standards/PEAR/Tests/Functions/FunctionCallSignatureUnitTest.inc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,19 @@ function foo()
379379
}
380380
);
381381
}
382+
383+
$deprecated_functions = [
384+
'the_category_ID'
385+
=> function_call( // 7 spaces, not 8. This is the problem line.
386+
$a,
387+
$b
388+
),
389+
];
390+
391+
$deprecated_functions = [
392+
'the_category_ID'
393+
=> function_call( // 7 spaces, not 8. This is the problem line.
394+
$a,
395+
$b
396+
),
397+
];

src/Standards/PEAR/Tests/Functions/FunctionCallSignatureUnitTest.inc.fixed

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,24 @@ class Foo
387387

388388
function foo()
389389
{
390-
Bar(
390+
Bar(
391391
function () {
392392
}
393393
);
394394
}
395+
396+
$deprecated_functions = [
397+
'the_category_ID'
398+
=> function_call( // 7 spaces, not 8. This is the problem line.
399+
$a,
400+
$b
401+
),
402+
];
403+
404+
$deprecated_functions = [
405+
'the_category_ID'
406+
=> function_call( // 7 spaces, not 8. This is the problem line.
407+
$a,
408+
$b
409+
),
410+
];

src/Standards/PEAR/Tests/Functions/FunctionCallSignatureUnitTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ public function getErrorList($testFile='FunctionCallSignatureUnitTest.inc')
9999
353 => 1,
100100
354 => 1,
101101
355 => 2,
102+
377 => 1,
103+
385 => 1,
104+
393 => 1,
105+
394 => 1,
106+
395 => 1,
107+
396 => 1,
102108
];
103109

104110
}//end getErrorList()

0 commit comments

Comments
 (0)