Skip to content
Merged
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
34 changes: 34 additions & 0 deletions PhpCollective/Sniffs/Operators/OperatorSpacingSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* MIT License
* For full license information, please view the LICENSE file that was distributed with this source code.
*/

namespace PhpCollective\Sniffs\Operators;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff as Psr12OperatorSpacingSniff;
use PhpCollective\Sniffs\WhiteSpace\CatchTypeSeparatorSpacingSniff;

/**
* Applies PSR12 operator spacing outside catch type lists.
*/
class OperatorSpacingSniff extends Psr12OperatorSpacingSniff
{
/**
* @param \PHP_CodeSniffer\Files\File $phpcsFile
* @param int $stackPtr
*
* @return int|null
*/
public function process(File $phpcsFile, int $stackPtr): ?int
{
if (CatchTypeSeparatorSpacingSniff::isCatchTypeSeparator($phpcsFile, $stackPtr)) {
return null;
}

// The parent returns a pointer to skip over declare() statements
return parent::process($phpcsFile, $stackPtr);
}
}
90 changes: 90 additions & 0 deletions PhpCollective/Sniffs/WhiteSpace/CatchTypeSeparatorSpacingSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

/**
* MIT License
* For full license information, please view the LICENSE file that was distributed with this source code.
*/

namespace PhpCollective\Sniffs\WhiteSpace;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
* Requires catch type separators to have no surrounding whitespace.
*/
class CatchTypeSeparatorSpacingSniff implements Sniff
{
public function register(): array
{
return [T_BITWISE_OR];
}

/**
* @param \PHP_CodeSniffer\Files\File $phpcsFile
* @param int $stackPtr
*
* @return void
*/
public function process(File $phpcsFile, int $stackPtr): void
{
if (!self::isCatchTypeSeparator($phpcsFile, $stackPtr)) {
return;
}

$tokens = $phpcsFile->getTokens();
$before = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true);
$after = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true);

if ($before === false || $after === false) {
return;
}

$newline = $tokens[$before]['line'] !== $tokens[$stackPtr]['line']
|| $tokens[$after]['line'] !== $tokens[$stackPtr]['line'];
$spacing = false;
for ($i = $before + 1; $i < $after; $i++) {
if ($tokens[$i]['code'] === T_WHITESPACE) {
$spacing = true;

break;
}
}
if (!$newline && !$spacing) {
return;
}

$message = 'Expected no whitespace around the catch type separator';
if ($newline) {
$phpcsFile->addError($message, $stackPtr, 'SpacesAround');

return;
}

$fix = $phpcsFile->addFixableError($message, $stackPtr, 'SpacesAround');
if ($fix) {
$phpcsFile->fixer->beginChangeset();
for ($i = $before + 1; $i < $after; $i++) {
if ($i !== $stackPtr && $tokens[$i]['code'] === T_WHITESPACE) {
$phpcsFile->fixer->replaceToken($i, '');
}
}
$phpcsFile->fixer->endChangeset();
}
}

public static function isCatchTypeSeparator(File $phpcsFile, int $stackPtr): bool
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$stackPtr]['code'] !== T_BITWISE_OR || empty($tokens[$stackPtr]['nested_parenthesis'])) {
return false;
}

$openers = array_keys($tokens[$stackPtr]['nested_parenthesis']);
$opener = end($openers);

return isset($tokens[$opener]['parenthesis_owner'])
&& $tokens[$tokens[$opener]['parenthesis_owner']]['code'] === T_CATCH;
}
}
1 change: 1 addition & 0 deletions PhpCollective/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@
<exclude name="PSR12.Files.OpenTag"/>
<!-- Long casts are covered by SlevomatCodingStandard.PHP.TypeCast, which catches more. -->
<exclude name="PSR12.Keywords.ShortFormTypeKeywords"/>
<exclude name="PSR12.Operators.OperatorSpacing"/>
</rule>

<!--
Expand Down
9 changes: 5 additions & 4 deletions docs/sniffs.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# PhpCollective Code Sniffer


The PhpCollectiveStrict standard contains 250 sniffs
The PhpCollectiveStrict standard contains 251 sniffs

Generic (27 sniffs)
-------------------
Expand Down Expand Up @@ -48,7 +48,7 @@ PEAR (4 sniffs)
- PEAR.Functions.ValidDefaultValue
- PEAR.NamingConventions.ValidClassName

PhpCollective (85 sniffs)
PhpCollective (87 sniffs)
-------------------------
- PhpCollective.Arrays.ArrayBracketSpacing
- PhpCollective.Arrays.DisallowImplicitArrayCreation
Expand Down Expand Up @@ -107,6 +107,7 @@ PhpCollective (85 sniffs)
- PhpCollective.Namespaces.FunctionNamespace
- PhpCollective.Namespaces.UseStatement
- PhpCollective.Namespaces.UseWithAliasing
- PhpCollective.Operators.OperatorSpacing
- PhpCollective.PHP.DeclareStrictTypes
- PhpCollective.PHP.DisallowFunctions
- PhpCollective.PHP.DisallowTrailingCommaInSingleLine
Expand All @@ -122,6 +123,7 @@ PhpCollective (85 sniffs)
- PhpCollective.Testing.AssertPrimitives
- PhpCollective.Testing.ExpectException
- PhpCollective.Testing.Mock
- PhpCollective.WhiteSpace.CatchTypeSeparatorSpacing
- PhpCollective.WhiteSpace.ConcatenationSpacing
- PhpCollective.WhiteSpace.ConsistentIndent
- PhpCollective.WhiteSpace.DocBlockSpacing
Expand Down Expand Up @@ -163,7 +165,7 @@ PSR2 (12 sniffs)
- PSR2.Namespaces.NamespaceDeclaration
- PSR2.Namespaces.UseDeclaration

PSR12 (13 sniffs)
PSR12 (12 sniffs)
-----------------
- PSR12.Classes.AnonClassDeclaration
- PSR12.Classes.ClassInstantiation
Expand All @@ -175,7 +177,6 @@ PSR12 (13 sniffs)
- PSR12.Functions.NullableTypeDeclaration
- PSR12.Functions.ReturnTypeDeclaration
- PSR12.Namespaces.CompoundNamespaceDepth
- PSR12.Operators.OperatorSpacing
- PSR12.Properties.ConstantVisibility
- PSR12.Traits.UseDeclaration

Expand Down
26 changes: 26 additions & 0 deletions tests/PhpCollective/Sniffs/Operators/OperatorSpacingSniffTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/**
* MIT License
* For full license information, please view the LICENSE file that was distributed with this source code.
*/

namespace PhpCollective\Test\PhpCollective\Sniffs\Operators;

use PhpCollective\Sniffs\Operators\OperatorSpacingSniff;
use PhpCollective\Test\TestCase;

class OperatorSpacingSniffTest extends TestCase
{
public function testBitwiseOperator(): void
{
$errors = $this->assertSnifferFindsFixableErrors(new OperatorSpacingSniff(), 2, 2);
$sources = array_merge(...array_map(static function (array $line): array {
return array_merge(...array_map(static function (array $column): array {
return array_column($column, 'source');
}, $line));
}, $errors));
$this->assertContains('PhpCollective.Operators.OperatorSpacing.NoSpaceBefore', $sources);
$this->assertContains('PhpCollective.Operators.OperatorSpacing.NoSpaceAfter', $sources);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/**
* MIT License
* For full license information, please view the LICENSE file that was distributed with this source code.
*/

namespace PhpCollective\Test\PhpCollective\Sniffs\WhiteSpace;

use PhpCollective\Sniffs\WhiteSpace\CatchTypeSeparatorSpacingSniff;
use PhpCollective\Test\TestCase;

class CatchTypeSeparatorSpacingSniffTest extends TestCase
{
public function testSpacing(): void
{
$this->assertSnifferFindsFixableErrors(new CatchTypeSeparatorSpacingSniff(), 7, 5);
}

public function testFixer(): void
{
$this->assertSnifferCanFixErrors(new CatchTypeSeparatorSpacingSniff(), 5);
}
}
17 changes: 17 additions & 0 deletions tests/_data/CatchTypeSeparatorSpacing/after.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

try {
risky();
} catch (A|B $e) {
} catch (A|B|C) {
} catch (A|B $e) {
} catch (\Example\A|\Example\B $e) {
} catch (A/* note */|B $e) {
} catch (A/* note */|B $e) {
} catch (A
| B $e) {
} catch (A |
B $e) {
}

$value = $a|$b;
17 changes: 17 additions & 0 deletions tests/_data/CatchTypeSeparatorSpacing/before.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

try {
risky();
} catch (A | B $e) {
} catch (A | B | C) {
} catch (A|B $e) {
} catch (\Example\A | \Example\B $e) {
} catch (A /* note */ | B $e) {
} catch (A/* note */|B $e) {
} catch (A
| B $e) {
} catch (A |
B $e) {
}

$value = $a|$b;
10 changes: 10 additions & 0 deletions tests/_data/OperatorSpacing/before.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

try {
risky();
} catch (A|B $e) {
}

$value = $a|$b;
Loading