Skip to content

Commit

Permalink
✨ New WordPress.WhiteSpace.ObjectOperatorSpacing sniff
Browse files Browse the repository at this point in the history
This sniff largely defers to the upstream `Squiz.WhiteSpace.ObjectOperatorSpacing` sniff, which was previously already included.

The only real difference between the two sniffs is that for class resolution using `ClassName::class`, new lines around the `::` object operator will not be ignored.

The WPCS sniff has the same default property settings as the upstream sniff and changes to the property values should be made in the ruleset.

Includes docs.
Includes unit tests covering the difference and safeguarding that the sniff doesn't overreach.
  • Loading branch information
jrfnl committed Oct 27, 2022
1 parent 6c575c1 commit 03b9b65
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 1 deletion.
2 changes: 1 addition & 1 deletion WordPress-Core/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@
<rule ref="Generic.Classes.OpeningBraceSameLine"/>

<!-- Object operators should not have whitespace around them unless they are multi-line. -->
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
<rule ref="WordPress.WhiteSpace.ObjectOperatorSpacing">
<properties>
<property name="ignoreNewlines" value="true"/>
</properties>
Expand Down
19 changes: 19 additions & 0 deletions WordPress/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<documentation title="Object Operator Spacing">
<standard>
<![CDATA[
The object operators (->, ?->, ::) should not have any spaces around them, though new lines are allowed except for use with the `::class` constant.
]]>
</standard>
<code_comparison>
<code title="Valid: No spaces around the object operator.">
<![CDATA[
$foo<em></em>-><em></em>bar();
]]>
</code>
<code title="Invalid: Whitespace surrounding the object operator.">
<![CDATA[
$foo<em> </em>?-><em> </em>bar();
]]>
</code>
</code_comparison>
</documentation>
65 changes: 65 additions & 0 deletions WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* WordPress Coding Standard.
*
* @package WPCS\WordPressCodingStandards
* @link https://github.com/WordPress/WordPress-Coding-Standards
* @license https://opensource.org/licenses/MIT MIT
*/

namespace WordPressCS\WordPress\Sniffs\WhiteSpace;

use PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ObjectOperatorSpacingSniff as Squiz_ObjectOperatorSpacingSniff;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;

/**
* Ensure there is no whitespace before/after an object operator.
*
* Difference with the upstream sniff:
* - When the `::` operator is used in `::class`, no new line(s) before or after the object operator are allowed.
*
* @package WPCS\WordPressCodingStandards
*
* @since 3.0.0
* @link https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php
*/
class ObjectOperatorSpacingSniff extends Squiz_ObjectOperatorSpacingSniff {

/**
* 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|int Optionally returns a stack pointer. The sniff will not be
* called again on the current file until the returned stack
* pointer is reached.
*/
public function process( File $phpcsFile, $stackPtr ) {
$tokens = $phpcsFile->getTokens();
$property_adjusted = false;

// Check for `::class` and don't ignore new lines in that case.
if ( true === $this->ignoreNewlines
&& \T_DOUBLE_COLON === $tokens[ $stackPtr ]['code']
) {
$next_non_empty = $phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );
if ( \T_STRING === $tokens[ $next_non_empty ]['code']
&& 'class' === strtolower( $tokens[ $next_non_empty ]['content'] )
) {
$property_adjusted = true;
$this->ignoreNewlines = false;
}
}

$return = parent::process( $phpcsFile, $stackPtr );

if ( true === $property_adjusted ) {
$this->ignoreNewlines = true;
}

return $return;
}
}
55 changes: 55 additions & 0 deletions WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/*
* This test file only safeguards the bit where the sniff may behave differently from the upstream sniff.
*/

echo ObjectName::$prop;
echo ObjectName::functionCall();
echo ObjectName::class;

echo ObjectName :: $prop; // Error x 2.
echo ObjectName :: functionCall(); // Error x 2.
echo ObjectName :: class; // Error x 2.

echo ObjectName
::
$prop; // Error x 2.
echo ObjectName
::
functionCall(); // Error x 2.
echo ObjectName
::
class; // Error x 2.

echo ObjectName // Comment
::
/* comment */
class; // Error x 2.

// phpcs:set WordPress.WhiteSpace.ObjectOperatorSpacing ignoreNewlines true

echo ObjectName::$prop;
echo ObjectName::functionCall();
echo ObjectName::class;

echo ObjectName :: $prop; // Error x 2.
echo ObjectName :: functionCall(); // Error x 2.
echo ObjectName :: class; // Error x 2.

echo ObjectName
::
$prop;
echo ObjectName
::
functionCall();
echo ObjectName
::
class; // Error x 2.

echo ObjectName // Comment
::
/* comment */
class; // Error x 2.

// phpcs:set WordPress.WhiteSpace.ObjectOperatorSpacing ignoreNewlines false
45 changes: 45 additions & 0 deletions WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.inc.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This test file only safeguards the bit where the sniff may behave differently from the upstream sniff.
*/

echo ObjectName::$prop;
echo ObjectName::functionCall();
echo ObjectName::class;

echo ObjectName::$prop; // Error x 2.
echo ObjectName::functionCall(); // Error x 2.
echo ObjectName::class; // Error x 2.

echo ObjectName::$prop; // Error x 2.
echo ObjectName::functionCall(); // Error x 2.
echo ObjectName::class; // Error x 2.

echo ObjectName // Comment
::/* comment */
class; // Error x 2.

// phpcs:set WordPress.WhiteSpace.ObjectOperatorSpacing ignoreNewlines true

echo ObjectName::$prop;
echo ObjectName::functionCall();
echo ObjectName::class;

echo ObjectName::$prop; // Error x 2.
echo ObjectName::functionCall(); // Error x 2.
echo ObjectName::class; // Error x 2.

echo ObjectName
::
$prop;
echo ObjectName
::
functionCall();
echo ObjectName::class; // Error x 2.

echo ObjectName // Comment
::/* comment */
class; // Error x 2.

// phpcs:set WordPress.WhiteSpace.ObjectOperatorSpacing ignoreNewlines false
59 changes: 59 additions & 0 deletions WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/**
* Unit test class for WordPress Coding Standard.
*
* @package WPCS\WordPressCodingStandards
* @link https://github.com/WordPress/WordPress-Coding-Standards
* @license https://opensource.org/licenses/MIT MIT
*/

namespace WordPressCS\WordPress\Tests\WhiteSpace;

use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;

/**
* Unit test class for the ObjectOperatorSpacing sniff.
*
* @package WPCS\WordPressCodingStandards
*
* @since 3.0.0
*/
class ObjectOperatorSpacingUnitTest extends AbstractSniffUnitTest {

/**
* Returns the lines where errors should occur.
*
* The key of the array should represent the line number and the value
* should represent the number of errors that should occur on that line.
*
* @return array<int, int>
*/
public function getErrorList() {
return array(
11 => 2,
12 => 2,
13 => 2,
16 => 2,
19 => 2,
22 => 2,
26 => 2,
36 => 2,
37 => 2,
38 => 2,
47 => 2,
51 => 2,
);
}

/**
* Returns the lines where warnings should occur.
*
* The key of the array should represent the line number and the value
* should represent the number of warnings that should occur on that line.
*
* @return array<int, int>
*/
public function getWarningList() {
return array();
}
}

0 comments on commit 03b9b65

Please sign in to comment.