Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions Universal/Docs/WhiteSpace/FirstClassCallableSpacingStandard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0"?>
<documentation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://phpcsstandards.github.io/PHPCSDevTools/phpcsdocs.xsd"
title="First Class Callable Spacing"
>
<standard>
<![CDATA[
There should be no space around the ellipsis when used in a first class callable.
]]>
</standard>
<code_comparison>
<code title="Valid: No space around the ellipsis in a first class callable.">
<![CDATA[
$callback = foo(<em>...</em>);
array_map(
$this->method(<em>...</em>),
$array
);
]]>
</code>
<code title="Invalid: Space found around the ellipsis in a first class callable.">
<![CDATA[
$callback = foo(<em> </em>...<em> </em>);
array_map(
$this->method(<em>
</em>...<em>
</em>),
$array
);
]]>
</code>
</code_comparison>
</documentation>
101 changes: 101 additions & 0 deletions Universal/Sniffs/WhiteSpace/FirstClassCallableSpacingSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php
/**
* PHPCSExtra, a collection of sniffs and standards for use with PHP_CodeSniffer.
*
* @package PHPCSExtra
* @copyright 2020 PHPCSExtra Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSExtra
*/

namespace PHPCSExtra\Universal\Sniffs\WhiteSpace;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Fixers\SpacesFixer;

/**
* Checks the spacing around the ellipses for first class callables.
*
* @since 1.5.0
*/
final class FirstClassCallableSpacingSniff implements Sniff
{

/**
* The number of spaces to demand before and after the ellipsis for a first class callable.
*
* @since 1.5.0
*
* @var int
*/
public $spacing = 0;

/**
* Returns an array of tokens this test wants to listen for.
*
* @since 1.5.0
*
* @return array<int|string>
*/
public function register()
{
return [\T_ELLIPSIS];
}

/**
* Processes this test, when one of its tokens is encountered.
*
* @since 1.5.0
*
* @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();

// Verify this is an ellipsis for a first class callable.
$previousNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);
if ($tokens[$previousNonEmpty]['code'] !== \T_OPEN_PARENTHESIS) {
return;
}

$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] !== \T_CLOSE_PARENTHESIS) {
return;
}

$spacing = (int) $this->spacing;

// Check spacing before the ellipsis.
SpacesFixer::checkAndFix(
$phpcsFile,
$previousNonEmpty,
$stackPtr,
$spacing,
'Incorrect spacing between first class callable open parentheses and ellipsis. Expected: %s, found: %s.',
'SpacingBefore',
'error',
0,
'First class callables: space before ellipsis'
);

// Check spacing after the ellipsis.
SpacesFixer::checkAndFix(
$phpcsFile,
$stackPtr,
$nextNonEmpty,
$spacing,
'Incorrect spacing between first class callable ellipsis and close parentheses. Expected: %s, found: %s.',
'SpacingAfter',
'error',
0,
'First class callables: space after ellipsis'
);
}
}
49 changes: 49 additions & 0 deletions Universal/Tests/WhiteSpace/FirstClassCallableSpacingUnitTest.1.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

// Not our target...
function foo(...$args) {}
callMe($foo, ...$args);
$array = [$a, ...$b, $c];

// First class callables.
callMe(...); // OK.
callMe( ...);
callMe(... );
callMe( ... );
callMe( ... );
callMe(

...

);
callMe( /*comment*/ ... );

// phpcs:set Universal.WhiteSpace.FirstClassCallableSpacing spacing 1
callMe( ... ); // OK.
callMe(... );
callMe( ...);
callMe(...);
callMe( ... );
callMe(


...
);
callMe(... /*comment*/ );

// phpcs:set Universal.WhiteSpace.FirstClassCallableSpacing spacing 2
callMe( ... ); // OK.
callMe(... );
callMe( ...);
callMe(...);
callMe( ... );
callMe( ... );
callMe(
...


);
callMe(... /*comment*/ );

// Reset the property to its default value.
// phpcs:set Universal.WhiteSpace.FirstClassCallableSpacing spacing 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

// Not our target...
function foo(...$args) {}
callMe($foo, ...$args);
$array = [$a, ...$b, $c];

// First class callables.
callMe(...); // OK.
callMe(...);
callMe(...);
callMe(...);
callMe(...);
callMe(...);
callMe( /*comment*/ ...);

// phpcs:set Universal.WhiteSpace.FirstClassCallableSpacing spacing 1
callMe( ... ); // OK.
callMe( ... );
callMe( ... );
callMe( ... );
callMe( ... );
callMe( ... );
callMe( ... /*comment*/ );

// phpcs:set Universal.WhiteSpace.FirstClassCallableSpacing spacing 2
callMe( ... ); // OK.
callMe( ... );
callMe( ... );
callMe( ... );
callMe( ... );
callMe( ... );
callMe( ... );
callMe( ... /*comment*/ );

// Reset the property to its default value.
// phpcs:set Universal.WhiteSpace.FirstClassCallableSpacing spacing 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

// Intentional parse error.
// This must be the only test in the file.
// This code sniff should **not** be flagged as we cannot determine for certain whether this is a first class callable or not.
callable( ...
77 changes: 77 additions & 0 deletions Universal/Tests/WhiteSpace/FirstClassCallableSpacingUnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
/**
* PHPCSExtra, a collection of sniffs and standards for use with PHP_CodeSniffer.
*
* @package PHPCSExtra
* @copyright 2020 PHPCSExtra Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSExtra
*/

namespace PHPCSExtra\Universal\Tests\WhiteSpace;

use PHP_CodeSniffer\Tests\Standards\AbstractSniffTestCase;

/**
* Unit test class for the FirstClassCallableSpacing sniff.
*
* @covers PHPCSExtra\Universal\Sniffs\WhiteSpace\FirstClassCallableSpacingSniff
*
* @since 1.5.0
*/
final class FirstClassCallableSpacingUnitTest extends AbstractSniffTestCase
{

/**
* Returns the lines where errors should occur.
*
* @param string $testFile The name of the file being tested.
*
* @return array<int, int> Key is the line number, value is the number of expected errors.
*/
public function getErrorList($testFile = '')
{
switch ($testFile) {
case 'FirstClassCallableSpacingUnitTest.1.inc':
return [
10 => 1,
11 => 1,
12 => 2,
13 => 2,
14 => 1,
16 => 1,
19 => 2,

23 => 1,
24 => 1,
25 => 2,
26 => 2,
27 => 1,
30 => 1,
32 => 1,

36 => 1,
37 => 1,
38 => 2,
39 => 2,
40 => 2,
41 => 1,
42 => 1,
46 => 2,
];

default:
return [];
}
}

/**
* Returns the lines where warnings should occur.
*
* @return array<int, int> Key is the line number, value is the number of expected warnings.
*/
public function getWarningList()
{
return [];
}
}