-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ New Generic.WhiteSpace.SpreadOperatorSpacingAfter sniff
This introduces a new sniff which checks the whitespace between the spread operator and the variable/function call it applies to. This new sniff has two `public` properties: * `$spacing` which defaults to `0`, i.e. no space. * `$ignoreNewlines` which defaults to `false`. Includes unit tests. Includes fixers. Includes documentation. Note: PSR12 only specifies _There MUST NOT be a space between the variadic three dot operator and the argument name_ for **function declarations**. This sniff, however, checks the spacing for the spread operator in all circumstances in which it can be used, i.e.: * In function declarations (PHP 5.6). * In function calls (PHP 5.6). * In array declarations (PHP 7.4).
- Loading branch information
Showing
6 changed files
with
384 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
src/Standards/Generic/Docs/WhiteSpace/SpreadOperatorSpacingAfterStandard.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<documentation title="Spacing After Spread Operator"> | ||
<standard> | ||
<![CDATA[ | ||
There should be no space between the spread operator and the variable/function call it applies to. | ||
]]> | ||
</standard> | ||
<code_comparison> | ||
<code title="Valid: No space between the spread operator and the variable/function call it applies to."> | ||
<![CDATA[ | ||
function foo(<em>&...$spread</em>) { | ||
bar(<em>...$spread</em>); | ||
bar( | ||
[<em>...$foo</em>], | ||
<em>...array_values($keyedArray)</em> | ||
); | ||
} | ||
]]> | ||
</code> | ||
<code title="Invalid: space found between the spread operator and the variable/function call it applies to."> | ||
<![CDATA[ | ||
function bar(<em>... </em>$spread) { | ||
bar(<em>... | ||
</em>$spread | ||
); | ||
bar( | ||
[<em>... </em>$foo ],<em>.../*comment*/</em>array_values($keyedArray) | ||
); | ||
} | ||
]]> | ||
</code> | ||
</code_comparison> | ||
</documentation> |
146 changes: 146 additions & 0 deletions
146
src/Standards/Generic/Sniffs/WhiteSpace/SpreadOperatorSpacingAfterSniff.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
<?php | ||
/** | ||
* Verifies spacing between the spread operator and the variable/function call it applies to. | ||
* | ||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl> | ||
* @copyright 2019 Juliette Reinders Folmer. All rights reserved. | ||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence | ||
*/ | ||
|
||
namespace PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace; | ||
|
||
use PHP_CodeSniffer\Sniffs\Sniff; | ||
use PHP_CodeSniffer\Files\File; | ||
use PHP_CodeSniffer\Util\Tokens; | ||
|
||
class SpreadOperatorSpacingAfterSniff implements Sniff | ||
{ | ||
|
||
/** | ||
* The number of spaces desired after a spread token. | ||
* | ||
* @var integer | ||
*/ | ||
public $spacing = 0; | ||
|
||
/** | ||
* Allow newlines instead of spaces. | ||
* | ||
* @var boolean | ||
*/ | ||
public $ignoreNewlines = false; | ||
|
||
|
||
/** | ||
* Returns an array of tokens this test wants to listen for. | ||
* | ||
* @return array | ||
*/ | ||
public function register() | ||
{ | ||
return [T_ELLIPSIS]; | ||
|
||
}//end register() | ||
|
||
|
||
/** | ||
* Processes this test, when one of its tokens is encountered. | ||
* | ||
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. | ||
* @param int $stackPtr The position of the current token in | ||
* the stack passed in $tokens. | ||
* | ||
* @return void | ||
*/ | ||
public function process(File $phpcsFile, $stackPtr) | ||
{ | ||
$tokens = $phpcsFile->getTokens(); | ||
$this->spacing = (int) $this->spacing; | ||
|
||
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); | ||
if ($nextNonEmpty === false) { | ||
return; | ||
} | ||
|
||
if ($this->ignoreNewlines === true | ||
&& $tokens[$stackPtr]['line'] !== $tokens[$nextNonEmpty]['line'] | ||
) { | ||
$phpcsFile->recordMetric($stackPtr, 'Spacing after spread operator', 'newline'); | ||
return; | ||
} | ||
|
||
if ($this->spacing === 0 && $nextNonEmpty === ($stackPtr + 1)) { | ||
$phpcsFile->recordMetric($stackPtr, 'Spacing after spread operator', 0); | ||
return; | ||
} | ||
|
||
$nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); | ||
if ($nextNonEmpty !== $nextNonWhitespace) { | ||
$error = 'Expected %s space(s) after the spread operator; comment found'; | ||
$data = [$this->spacing]; | ||
$phpcsFile->addError($error, $stackPtr, 'CommentFound', $data); | ||
|
||
if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { | ||
$phpcsFile->recordMetric($stackPtr, 'Spacing after spread operator', $tokens[($stackPtr + 1)]['length']); | ||
} else { | ||
$phpcsFile->recordMetric($stackPtr, 'Spacing after spread operator', 0); | ||
} | ||
|
||
return; | ||
} | ||
|
||
$found = 0; | ||
if ($tokens[$stackPtr]['line'] !== $tokens[$nextNonEmpty]['line']) { | ||
$found = 'newline'; | ||
} else if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { | ||
$found = $tokens[($stackPtr + 1)]['length']; | ||
} | ||
|
||
$phpcsFile->recordMetric($stackPtr, 'Spacing after spread operator', $found); | ||
|
||
if ($found === $this->spacing) { | ||
return; | ||
} | ||
|
||
$error = 'Expected %s space(s) after the spread operator; %s found'; | ||
$data = [ | ||
$this->spacing, | ||
$found, | ||
]; | ||
|
||
$errorCode = 'TooMuchSpace'; | ||
if ($this->spacing !== 0) { | ||
if ($found === 0) { | ||
$errorCode = 'NoSpace'; | ||
} else if ($found !== 'newline' && $found < $this->spacing) { | ||
$errorCode = 'TooLittleSpace'; | ||
} | ||
} | ||
|
||
$fix = $phpcsFile->addFixableError($error, $stackPtr, $errorCode, $data); | ||
|
||
if ($fix === true) { | ||
$padding = str_repeat(' ', $this->spacing); | ||
if ($found === 0) { | ||
$phpcsFile->fixer->addContent($stackPtr, $padding); | ||
} else { | ||
$phpcsFile->fixer->beginChangeset(); | ||
$start = ($stackPtr + 1); | ||
|
||
if ($this->spacing > 0) { | ||
$phpcsFile->fixer->replaceToken($start, $padding); | ||
++$start; | ||
} | ||
|
||
for ($i = $start; $i < $nextNonWhitespace; $i++) { | ||
$phpcsFile->fixer->replaceToken($i, ''); | ||
} | ||
|
||
$phpcsFile->fixer->endChangeset(); | ||
} | ||
} | ||
|
||
}//end process() | ||
|
||
|
||
}//end class |
73 changes: 73 additions & 0 deletions
73
src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
function foo( &...$spread ) { | ||
bar( ...$spread ); | ||
|
||
bar( | ||
[ ...$foo ], | ||
...array_values($keyedArray) | ||
); | ||
} | ||
|
||
function bar( & ... $spread ) { | ||
bar(... | ||
|
||
|
||
$spread | ||
); | ||
|
||
bar( | ||
[... $foo ],.../*comment*/array_values($keyedArray) | ||
); | ||
} | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter ignoreNewlines true | ||
bar(... | ||
$spread | ||
); | ||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter ignoreNewlines false | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter spacing 1 | ||
function foo( &... $spread ) { | ||
bar( ... $spread ); | ||
|
||
bar( | ||
[ ... $foo ], | ||
... array_values($keyedArray) | ||
); | ||
} | ||
|
||
function bar( & ...$spread ) { | ||
bar(... | ||
$spread | ||
); | ||
|
||
bar( | ||
[... $foo ],.../*comment*/array_values($keyedArray) | ||
); | ||
} | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter spacing 2 | ||
function foo( &... $spread ) { | ||
bar( ... $spread ); | ||
|
||
bar( | ||
[ ... $foo ], | ||
... array_values($keyedArray) | ||
); | ||
} | ||
|
||
function bar( & ... $spread ) { | ||
bar(... | ||
$spread | ||
); | ||
|
||
bar( | ||
[... $foo ],.../*comment*/array_values($keyedArray) | ||
); | ||
} | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter spacing 0 | ||
|
||
// Intentional parse error. This has to be the last test in the file. | ||
function bar( ... |
68 changes: 68 additions & 0 deletions
68
src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc.fixed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
function foo( &...$spread ) { | ||
bar( ...$spread ); | ||
|
||
bar( | ||
[ ...$foo ], | ||
...array_values($keyedArray) | ||
); | ||
} | ||
|
||
function bar( & ...$spread ) { | ||
bar(...$spread | ||
); | ||
|
||
bar( | ||
[...$foo ],.../*comment*/array_values($keyedArray) | ||
); | ||
} | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter ignoreNewlines true | ||
bar(... | ||
$spread | ||
); | ||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter ignoreNewlines false | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter spacing 1 | ||
function foo( &... $spread ) { | ||
bar( ... $spread ); | ||
|
||
bar( | ||
[ ... $foo ], | ||
... array_values($keyedArray) | ||
); | ||
} | ||
|
||
function bar( & ... $spread ) { | ||
bar(... $spread | ||
); | ||
|
||
bar( | ||
[... $foo ],.../*comment*/array_values($keyedArray) | ||
); | ||
} | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter spacing 2 | ||
function foo( &... $spread ) { | ||
bar( ... $spread ); | ||
|
||
bar( | ||
[ ... $foo ], | ||
... array_values($keyedArray) | ||
); | ||
} | ||
|
||
function bar( & ... $spread ) { | ||
bar(... $spread | ||
); | ||
|
||
bar( | ||
[... $foo ],.../*comment*/array_values($keyedArray) | ||
); | ||
} | ||
|
||
// phpcs:set Generic.WhiteSpace.SpreadOperatorSpacingAfter spacing 0 | ||
|
||
// Intentional parse error. This has to be the last test in the file. | ||
function bar( ... |
Oops, something went wrong.