Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New unneeded ternary sniff #1771

Closed
wants to merge 1 commit into from
Closed
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
19 changes: 19 additions & 0 deletions WordPress/Docs/PHP/NoUnneededTernaryStandard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<documentation title="Discourage the usage of the unneeded ternary operator">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should just be a title, not a description.

<standard>
<![CDATA[
When storing a boolean value to a variable, a ternary check is not needed.
]]>
</standard>
<code_comparison>
<code title="Valid: simple test in the assignment.">
<![CDATA[
$true_variable = $var === 42;
]]>
</code>
<code title="Invalid: ternary usage with boolean in the assignment.">
<![CDATA[
$true_variable = $var === 42 ? <em>true</em> : <em>false</em>;
]]>
</code>
</code_comparison>
</documentation>
77 changes: 77 additions & 0 deletions WordPress/Sniffs/PHP/NoUnneededTernarySniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?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\PHP;

use WordPressCS\WordPress\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
* Discourage the usage of the unneeded ternary operator.
*
* This sniff is influenced by the same rule set in the ESLint rules.
* When we want to store a boolean value in a variable, using a ternary operator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this sniff also cover return ... ? true : false;?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the point of the sniff. Wherever there is an unneeded ternary detected, it can be removed. This includes conditionals, return statements or assignment to a variable 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yet, there are no unit tests which shows that return statements are covered by this sniff.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add those when I update the sniff 👍

* is not needed, because a test will return a boolean value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* is not needed, because a test will return a boolean value.
* This sniff is influenced by the same rule as found in the ESLint rules.
* When we want to store the boolean result of a comparison in a variable, using
* a ternary operator with `? true : false` is not needed, because the comparison
* will return a boolean value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll rephrase this description so that it's not only limited to variable assignments (as is the initial intention of the sniff) 👍

*
* @link https://eslint.org/docs/rules/no-unneeded-ternary
*
* @package WPCS\WordPressCodingStandards
*
* @since 2.2.0
*/
class NoUnneededTernarySniff extends Sniff {

/**
* Boolean tokens array.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Boolean tokens array.
* Tokens which represent booleans.

*
* @since 2.2.0
*
* @var array
*/
private $boolean_tokens = array(
'T_TRUE' => true,
'T_FALSE' => true,
);

/**
* Returns an array of tokens this test wants to listen for.
*
* @since 2.2.0
*
* @return array
*/
public function register() {
return array( \T_INLINE_THEN );
}

/**
* Processes this test, when one of its tokens is encountered.
*
* @since 2.2.0
*
* @param int $stackPtr The position of the current token in the stack.
*/
public function process_token( $stackPtr ) {
$first_token = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );
$end_of_statement = $this->phpcsFile->findNext( array( \T_SEMICOLON, \T_CLOSE_TAG ), $stackPtr );
$last_token = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $end_of_statement - 1 ), null, true );

$first_token_type = $this->tokens[ $first_token ]['type'];
$last_token_type = $this->tokens[ $last_token ]['type'];

if ( isset( $this->boolean_tokens[ $first_token_type ] ) && isset( $this->boolean_tokens[ $last_token_type ] ) ) {
$this->phpcsFile->addError(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this warrants a hard error which breaks build. A soft warning should be enough.

Suggested change
$this->phpcsFile->addError(
$this->phpcsFile->addWarning(

'Don\'t use ternary epression to store a boolean value in a variable.',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not happy with this phrase as IMO it's still unclear.

Suggested change
'Don\'t use ternary epression to store a boolean value in a variable.',
'Don\'t use a ternary expression to store the boolean result of a comparison in a variable.',

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ESLint will throw Unnecessary use of boolean literals in conditional expression, can we use this instead of the proposed message, or make something better?

$stackPtr,
'Detected'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default error code is Found, which works perfectly well here. Why use something else here and make the error code less predictable ?

Suggested change
'Detected'
'Found'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't aware of the Found vs Detected. I guess I saw the error message of some other sniff having Detected so I used it. Will fix this 👍

);
}
}

}
30 changes: 30 additions & 0 deletions WordPress/Tests/PHP/NoUnneededTernaryUnitTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

$var = 'a';
$trueVariable = $var === 'a' ? true : false; // Bad.
// Can be written as.
$trueVariable = $var === 'a'; // Ok.

$test_var = $boolean ? true : false; // Bad.

$test = $var === 'a' ? // Bad.
true :
false;

$test = $var === 'a'
? true // Bad.
: false;

$isTrue = $var === 4 ? false : true; // Bad.

$isTrue = $var === 4 ? 'Yes' : 'No'; // Ok.

$isTrue = $var === 4 ? true : 'No'; // Ok.

$isTrue = $var === 4 ? 'True' : false; // Ok.

$isTrue = $var === 4 ? false : 'True'; // Ok.

$isTrue = $var === 4 ? 'False' : true; // Ok.

$notFalse = $var !== false; // Ok.
47 changes: 47 additions & 0 deletions WordPress/Tests/PHP/NoUnneededTernaryUnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?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\PHP;

use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;

/**
* Unit test class for the PHP_NoUnneededTernary sniff.
*
* @package WPCS\WordPressCodingStandards
*
* @since 2.2.0
*/
class NoUnneededTernaryUnitTest extends AbstractSniffUnitTest {

/**
* Returns the lines where errors should occur.
*
* @return array <int line number> => <int number of errors>
*/
public function getErrorList() {
return array(
4 => 1,
8 => 1,
10 => 1,
15 => 1,
18 => 1,
);
}

/**
* Returns the lines where warnings should occur.
*
* @return array <int line number> => <int number of warnings>
*/
public function getWarningList() {
return array();
}

}