Skip to content

Commit

Permalink
PEAR.Functions.FunctionCallSignature now adjusts the indent of functi…
Browse files Browse the repository at this point in the history
…on argument contents during auto-fixing (ref #2635)
  • Loading branch information
gsherwood committed Nov 18, 2019
1 parent 9604fe2 commit af6dcc1
Show file tree
Hide file tree
Showing 9 changed files with 290 additions and 8 deletions.
6 changes: 6 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,18 @@ http://pear.php.net/dtd/package-2.0.xsd">
-- The cache is now invalidated for a file when its permissions are changed
- File::getMethodParameters() now supports arrow functions
- File::getMethodProperties() now supports arrow functions
- Added Fixer::changeCodeBlockIndent() to change the indent of a code block while auto-fixing
-- Can be used to either increase or decrease the indent
-- Useful when moving the start position of something like a closure, where you want the content to also move
- Added Generic.Files.ExecutableFile sniff
-- Ensures that files are not executable
-- Thanks to Matthew Peveler for the contribution
- Generic.CodeAnalysis.EmptyPhpStatement now reports unnecessary semicolons after control structure closing braces
-- Thanks to Vincent Langlet for the patch
- Generic.WhiteSpace.ScopeIndent now supports static arrow functions
- PEAR.Functions.FunctionCallSignature now adjusts the indent of function argument contents during auto-fixing
-- Previously, only the first line of an argument was changed, leading to inconsistent indents
-- This change also applies to PSR2.Methods.FunctionCallSignature
- PSR2.ControlStructures.ControlStructureSpacing now checks whitespace before the closing parenthesis of multi-line control structures
-- Previously, it incorrectly applied the whitespace check for single-line definitions only
- PSR12.Traits.UseDeclaration now ensures all trait import statements are grouped together
Expand Down
73 changes: 69 additions & 4 deletions src/Fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,14 @@ public function beginChangeset()
}

if (PHP_CODESNIFFER_VERBOSITY > 1) {
$bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$sniff = $bt[1]['class'];
$line = $bt[0]['line'];
$bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
if ($bt[1]['class'] === __CLASS__) {
$sniff = 'Fixer';
} else {
$sniff = Util\Common::getSniffCode($bt[1]['class']);
}

$sniff = Util\Common::getSniffCode($sniff);
$line = $bt[0]['line'];

@ob_end_clean();
echo "\t=> Changeset started by $sniff:$line".PHP_EOL;
Expand Down Expand Up @@ -730,4 +733,66 @@ public function addContentBefore($stackPtr, $content)
}//end addContentBefore()


/**
* Adjust the indent of a code block.
*
* @param int $start The position of the token in the token stack
* to start adjusting the indent from.
* @param int $end The position of the token in the token stack
* to end adjusting the indent.
* @param int $change The number of spaces to adjust the indent by
* (positive or negative).
*
* @return bool If the change was accepted.
*/
public function changeCodeBlockIndent($start, $end, $change)
{
$tokens = $this->currentFile->getTokens();

$baseIndent = '';
if ($change > 0) {
$baseIndent = str_repeat(' ', $change);
}

$useChangeset = false;
if ($this->inChangeset === false) {
$this->beginChangeset();
$useChangeset = true;
}

for ($i = $start; $i <= $end; $i++) {
if ($tokens[$i]['column'] !== 1
|| $tokens[($i + 1)]['line'] !== $tokens[$i]['line']
) {
continue;
}

$length = 0;
if ($tokens[$i]['code'] === T_WHITESPACE
|| $tokens[$i]['code'] === T_DOC_COMMENT_WHITESPACE
) {
$length = $tokens[$i]['length'];

$padding = ($length + $change);
if ($padding > 0) {
$padding = str_repeat(' ', $padding);
} else {
$padding = '';
}

$newContent = $padding.ltrim($tokens[$i]['content']);
} else {
$newContent = $baseIndent.$tokens[$i]['content'];
}

$this->replaceToken($i, $newContent);
}//end for

if ($useChangeset === true) {
$this->endChangeset();
}

}//end changeCodeBlockIndent()


}//end class
102 changes: 101 additions & 1 deletion src/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,8 @@ public function processMultiLineCall(File $phpcsFile, $stackPtr, $openBracket, $
}
}//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']
) {
Expand Down Expand Up @@ -548,18 +550,29 @@ public function processMultiLineCall(File $phpcsFile, $stackPtr, $openBracket, $

$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;
Expand Down Expand Up @@ -611,4 +624,91 @@ public function processMultiLineCall(File $phpcsFile, $stackPtr, $openBracket, $
}//end processMultiLineCall()


/**
* Processes this test, when one of its tokens is encountered.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile All the tokens found in the document.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param int $length The length of the new indent.
* @param int $change The difference in length between
* the old and new indent.
*
* @return bool
*/
protected function adjustIndent(File $phpcsFile, $stackPtr, $length, $change)
{
$tokens = $phpcsFile->getTokens();

// We don't adjust indents outside of PHP.
if ($tokens[$stackPtr]['code'] === T_INLINE_HTML) {
return false;
}

$padding = '';
if ($length > 0) {
if ($this->tabIndent === true) {
$numTabs = floor($length / $this->tabWidth);
if ($numTabs > 0) {
$numSpaces = ($length - ($numTabs * $this->tabWidth));
$padding = str_repeat("\t", $numTabs).str_repeat(' ', $numSpaces);
}
} else {
$padding = str_repeat(' ', $length);
}
}

if ($tokens[$stackPtr]['column'] === 1) {
$trimmed = ltrim($tokens[$stackPtr]['content']);
$accepted = $phpcsFile->fixer->replaceToken($stackPtr, $padding.$trimmed);
} else {
// Easier to just replace the entire indent.
$accepted = $phpcsFile->fixer->replaceToken(($stackPtr - 1), $padding);
}

if ($accepted === false) {
return false;
}

if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_OPEN_TAG) {
// We adjusted the start of a comment, so adjust the rest of it
// as well so the alignment remains correct.
for ($x = ($stackPtr + 1); $x < $tokens[$stackPtr]['comment_closer']; $x++) {
if ($tokens[$x]['column'] !== 1) {
continue;
}

$length = 0;
if ($tokens[$x]['code'] === T_DOC_COMMENT_WHITESPACE) {
$length = $tokens[$x]['length'];
}

$padding = ($length + $change);
if ($padding > 0) {
if ($this->tabIndent === true) {
$numTabs = floor($padding / $this->tabWidth);
$numSpaces = ($padding - ($numTabs * $this->tabWidth));
$padding = str_repeat("\t", $numTabs).str_repeat(' ', $numSpaces);
} else {
$padding = str_repeat(' ', $padding);
}
} else {
$padding = '';
}

$phpcsFile->fixer->replaceToken($x, $padding);
if ($this->debug === true) {
$length = strlen($padding);
$line = $tokens[$x]['line'];
$type = $tokens[$x]['type'];
echo "\t=> Indent adjusted to $length for $type on line $line".PHP_EOL;
}
}//end for
}//end if

return true;

}//end adjustIndent()


}//end class
Original file line number Diff line number Diff line change
Expand Up @@ -506,3 +506,19 @@ $salesOrderThresholdTransfer->fromArray($salesOrderThresholdEntity->toArray(), t
)->setStore(
(new StoreTransfer())->fromArray($salesOrderThresholdEntity->getStore()->toArray(), true)
);

return trim(preg_replace_callback(
// sprintf replaces IGNORED_CHARS multiple times: for %s as well as %1$s (argument numbering)
// /[%s]*([^%1$s]+)/ results in /[IGNORED_CHARS]*([^IGNORED_CHARS]+)/
sprintf('/[%s]*([^%1$s]+)/', self::IGNORED_CHARS),
function (array $term) use ($mode): string {
// query pieces have to bigger than one char, otherwise they are too expensive for the search
if (mb_strlen($term[1], 'UTF-8') > 1) {
// in boolean search mode '' (empty) means OR, '-' means NOT
return sprintf('%s%s ', $mode === 'AND' ? '+' : '', self::extractUmlauts($term[1]));
}

return '';
},
$search
));
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ array_map(

array_map(
function($x)
{
return trim($x);
},
{
return trim($x);
},
$array
);

Expand Down Expand Up @@ -516,3 +516,21 @@ $salesOrderThresholdTransfer->fromArray($salesOrderThresholdEntity->toArray(), t
)->setStore(
(new StoreTransfer())->fromArray($salesOrderThresholdEntity->getStore()->toArray(), true)
);

return trim(
preg_replace_callback(
// sprintf replaces IGNORED_CHARS multiple times: for %s as well as %1$s (argument numbering)
// /[%s]*([^%1$s]+)/ results in /[IGNORED_CHARS]*([^IGNORED_CHARS]+)/
sprintf('/[%s]*([^%1$s]+)/', self::IGNORED_CHARS),
function (array $term) use ($mode): string {
// query pieces have to bigger than one char, otherwise they are too expensive for the search
if (mb_strlen($term[1], 'UTF-8') > 1) {
// in boolean search mode '' (empty) means OR, '-' means NOT
return sprintf('%s%s ', $mode === 'AND' ? '+' : '', self::extractUmlauts($term[1]));
}

return '';
},
$search
)
);
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public function getErrorList($testFile='FunctionCallSignatureUnitTest.inc')
441 => 1,
442 => 1,
464 => 1,
510 => 1,
513 => 1,
514 => 1,
523 => 1,
524 => 3,
];

}//end getErrorList()
Expand Down
32 changes: 32 additions & 0 deletions src/Standards/PSR2/Tests/Methods/FunctionCallSignatureUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,35 @@ $obj->{$x}(1,
'a','b'
)('c',
'd');

return trim(preg_replace_callback(
// sprintf replaces IGNORED_CHARS multiple times: for %s as well as %1$s (argument numbering)
// /[%s]*([^%1$s]+)/ results in /[IGNORED_CHARS]*([^IGNORED_CHARS]+)/
sprintf('/[%s]*([^%1$s]+)/', self::IGNORED_CHARS),
function (array $term) use ($mode): string {
// query pieces have to bigger than one char, otherwise they are too expensive for the search
if (mb_strlen($term[1], 'UTF-8') > 1) {
// in boolean search mode '' (empty) means OR, '-' means NOT
return sprintf('%s%s ', $mode === 'AND' ? '+' : '', self::extractUmlauts($term[1]));
}

return '';
},
$search
));

return trim(preg_replace_callback(
// sprintf replaces IGNORED_CHARS multiple times: for %s as well as %1$s (argument numbering)
// /[%s]*([^%1$s]+)/ results in /[IGNORED_CHARS]*([^IGNORED_CHARS]+)/
sprintf('/[%s]*([^%1$s]+)/', self::IGNORED_CHARS),
function (array $term) use ($mode): string {
// query pieces have to bigger than one char, otherwise they are too expensive for the search
if (mb_strlen($term[1], 'UTF-8') > 1) {
// in boolean search mode '' (empty) means OR, '-' means NOT
return sprintf('%s%s ', $mode === 'AND' ? '+' : '', self::extractUmlauts($term[1]));
}

return '';
},
$search
));
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,35 @@ $obj->{$x}(
'c',
'd'
);

return trim(preg_replace_callback(
// sprintf replaces IGNORED_CHARS multiple times: for %s as well as %1$s (argument numbering)
// /[%s]*([^%1$s]+)/ results in /[IGNORED_CHARS]*([^IGNORED_CHARS]+)/
sprintf('/[%s]*([^%1$s]+)/', self::IGNORED_CHARS),
function (array $term) use ($mode): string {
// query pieces have to bigger than one char, otherwise they are too expensive for the search
if (mb_strlen($term[1], 'UTF-8') > 1) {
// in boolean search mode '' (empty) means OR, '-' means NOT
return sprintf('%s%s ', $mode === 'AND' ? '+' : '', self::extractUmlauts($term[1]));
}

return '';
},
$search
));

return trim(preg_replace_callback(
// sprintf replaces IGNORED_CHARS multiple times: for %s as well as %1$s (argument numbering)
// /[%s]*([^%1$s]+)/ results in /[IGNORED_CHARS]*([^IGNORED_CHARS]+)/
sprintf('/[%s]*([^%1$s]+)/', self::IGNORED_CHARS),
function (array $term) use ($mode): string {
// query pieces have to bigger than one char, otherwise they are too expensive for the search
if (mb_strlen($term[1], 'UTF-8') > 1) {
// in boolean search mode '' (empty) means OR, '-' means NOT
return sprintf('%s%s ', $mode === 'AND' ? '+' : '', self::extractUmlauts($term[1]));
}

return '';
},
$search
));
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ public function getErrorList()
210 => 2,
211 => 1,
212 => 2,
217 => 1,
218 => 1,
227 => 1,
228 => 1,
233 => 1,
234 => 1,
242 => 1,
243 => 1,
];

}//end getErrorList()
Expand Down

0 comments on commit af6dcc1

Please sign in to comment.