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
21 changes: 21 additions & 0 deletions src/Standards/PSR12/Docs/Operators/OperatorSpacingStandard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,27 @@ if ($a===$b) {
$foo=$bar??$a??$b;
} elseif ($a>$b) {
$variable=$foo?'foo':'bar';
}
]]>
</code>
</code_comparison>
<standard>
<![CDATA[
When the "perCompatible" property is set to "3.0" or higher, the requirement for spaces around the single pipe operator in a multi-catch block is changed to a requirement of "no spaces".
]]>
</standard>
<code_comparison>
<code title="Valid: no spaces around the '|' operator in a multi-catch with 'perCompatible=3.0' (or higher).">
<![CDATA[
try {
} catch (Exception|RuntimeException $e) {
}
]]>
</code>
<code title="Invalid: spaces around the '|' operator in a multi-catch with 'perCompatible=3.0' (or higher).">
<![CDATA[
try {
} catch (Exception | RuntimeException $e) {
}
]]>
</code>
Expand Down
60 changes: 60 additions & 0 deletions src/Standards/PSR12/Sniffs/Operators/OperatorSpacingSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
class OperatorSpacingSniff extends SquizOperatorSpacingSniff
{

/**
* The PER version to be compatible with. For backwards compatibility this is set to 1.0 by default.
*
* @var string
*/
public $perCompatible = '1.0';


/**
* Returns an array of tokens this test wants to listen for.
Expand Down Expand Up @@ -75,6 +82,59 @@ public function process(File $phpcsFile, int $stackPtr)

$operator = $tokens[$stackPtr]['content'];

// PER-CS 3.0: Exception to the rule for pipe operators in multi-catch blocks where no space is required.
// As union types didn't exist when PSR-12 was created, the pipe in catch statements
// was originally treated as a bitwise operator. This check changes the spacing requirement
// for that specific case when opting in to PER-CS 3.0 or higher.
if ($tokens[$stackPtr]['code'] === T_BITWISE_OR
&& isset($tokens[$stackPtr]['nested_parenthesis']) === true
&& version_compare($this->perCompatible, '3.0', '>=') === true
) {
// Calling array_keys() on a nested sub-array can have memory leaks, assign to a variable first.
// See https://github.com/squizlabs/PHP_CodeSniffer/pull/2273 .
$parenthesis = $tokens[$stackPtr]['nested_parenthesis'];
$parenthesisKeys = array_keys($parenthesis);
$bracket = array_pop($parenthesisKeys);
if (isset($tokens[$bracket]['parenthesis_owner']) === true
&& $tokens[$tokens[$bracket]['parenthesis_owner']]['code'] === T_CATCH
) {
if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE
&& strpos($tokens[($stackPtr - 1)]['content'], $phpcsFile->eolChar) === false
&& $tokens[($stackPtr - 1)]['column'] !== 1
) {
$error = 'Expected 0 spaces before "%s" in multi-catch statement; %s found';
$data = [
$operator,
$tokens[($stackPtr - 1)]['length'],
];

$fix = $phpcsFile->addFixableError($error, $stackPtr, 'MultiCatchSpaceBefore', $data);
if ($fix === true) {
$phpcsFile->fixer->replaceToken(($stackPtr - 1), '');
}
}

if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE
&& strpos($tokens[($stackPtr + 1)]['content'], $phpcsFile->eolChar) === false
) {
$error = 'Expected 0 spaces after "%s" in multi-catch statement; %s found';
$data = [
$operator,
$tokens[($stackPtr + 1)]['length'],
];

$fix = $phpcsFile->addFixableError($error, $stackPtr, 'MultiCatchSpaceAfter', $data);
if ($fix === true) {
$phpcsFile->fixer->replaceToken(($stackPtr + 1), '');
}
}

// Now that this special case is handled, we can return early as we don't need to do
// further checks.
return;
}
}

$checkBefore = true;
$checkAfter = true;

Expand Down
88 changes: 88 additions & 0 deletions src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,91 @@ function setDefault(#[ImportValue(
}

declare(strict_types=1);

// Valid.
try {
// nothing
} catch (Exception | RuntimeException $e) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception
| RuntimeException
| KlausiException
| AnotherException
| ItNeverEndsException $e
) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception |
RuntimeException |
KlausiException |
AnotherException |
ItNeverEndsException $e
) {
}

// Valid because PSR 12 allows more than one space around operators.
try {
// nothing
} catch (Exception | RuntimeException $e) {
}

// phpcs:set PSR12.Operators.OperatorSpacing perCompatible 3.0

// Valid.
try {
// nothing
} catch (Exception|RuntimeException $e) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception
|RuntimeException
|KlausiException
|AnotherException
|ItNeverEndsException $e
) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception|
RuntimeException|
KlausiException|
AnotherException|
ItNeverEndsException $e
) {
}

// Invalid because of one space.
try {
// nothing
} catch (Exception | RuntimeException $e) {
}

// Invalid because of multiple spaces.
try {
// nothing
} catch (Exception | RuntimeException $e) {
}

// Testing that it works with future versions as well.
// phpcs:set PSR12.Operators.OperatorSpacing perCompatible 4.0

try {
// nothing
} catch (Exception | RuntimeException $e) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,91 @@ function setDefault(#[ImportValue(
}

declare(strict_types=1);

// Valid.
try {
// nothing
} catch (Exception | RuntimeException $e) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception
| RuntimeException
| KlausiException
| AnotherException
| ItNeverEndsException $e
) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception |
RuntimeException |
KlausiException |
AnotherException |
ItNeverEndsException $e
) {
}

// Valid because PSR 12 allows more than one space around operators.
try {
// nothing
} catch (Exception | RuntimeException $e) {
}

// phpcs:set PSR12.Operators.OperatorSpacing perCompatible 3.0

// Valid.
try {
// nothing
} catch (Exception|RuntimeException $e) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception
|RuntimeException
|KlausiException
|AnotherException
|ItNeverEndsException $e
) {
}

// Valid because multiline formatting is undefined.
try {
// nothing
} catch (
Exception|
RuntimeException|
KlausiException|
AnotherException|
ItNeverEndsException $e
) {
}

// Invalid because of one space.
try {
// nothing
} catch (Exception|RuntimeException $e) {
}

// Invalid because of multiple spaces.
try {
// nothing
} catch (Exception|RuntimeException $e) {
}

// Testing that it works with future versions as well.
// phpcs:set PSR12.Operators.OperatorSpacing perCompatible 4.0

try {
// nothing
} catch (Exception|RuntimeException $e) {
}
43 changes: 23 additions & 20 deletions src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,29 @@ public function getErrorList($testFile = '')
switch ($testFile) {
case 'OperatorSpacingUnitTest.1.inc':
return [
2 => 1,
3 => 2,
4 => 1,
5 => 2,
6 => 4,
9 => 3,
10 => 2,
11 => 3,
13 => 3,
14 => 2,
18 => 1,
20 => 1,
22 => 2,
23 => 2,
26 => 1,
37 => 4,
39 => 1,
40 => 1,
44 => 2,
47 => 2,
2 => 1,
3 => 2,
4 => 1,
5 => 2,
6 => 4,
9 => 3,
10 => 2,
11 => 3,
13 => 3,
14 => 2,
18 => 1,
20 => 1,
22 => 2,
23 => 2,
26 => 1,
37 => 4,
39 => 1,
40 => 1,
44 => 2,
47 => 2,
152 => 2,
158 => 2,
166 => 2,
];
default:
return [];
Expand Down