diff --git a/HM/Sniffs/PHP/TernarySniff.php b/HM/Sniffs/PHP/TernarySniff.php new file mode 100644 index 00000000..ad881f09 --- /dev/null +++ b/HM/Sniffs/PHP/TernarySniff.php @@ -0,0 +1,70 @@ +getTokens(); + + $inline_then_token = $phpcsFile->findPrevious( T_INLINE_THEN, $stackPtr ); + + $value_if_true_tokens = $this->get_nonempty_tokens( $tokens, $inline_then_token + 1, $stackPtr - 1 ); + if ( count( $value_if_true_tokens ) !== 1 ) { + // No single value. + return; + } + + if ( ! $this->is_boolean_token( $value_if_true_tokens[0] ) ) { + // No Boolean value. + return; + } + + $ternary_end_token = $phpcsFile->findNext( array( T_CLOSE_CURLY_BRACKET, T_CLOSE_PARENTHESIS, T_COMMA, T_SEMICOLON ), $stackPtr + 1 ); + + $value_if_false_tokens = $this->get_nonempty_tokens( $tokens, $stackPtr + 1, $ternary_end_token - 1 ); + if ( count( $value_if_false_tokens ) !== 1 ) { + // No single value. + return; + } + + if ( ! $this->is_boolean_token( $value_if_false_tokens[0] ) ) { + // No Boolean value. + return; + } + + $warning = 'Unnecessary ternary found: Instead of "$expr ? %s : %s", use "%s"'; + $data = array( + $value_if_true_tokens[0]['content'], + $value_if_false_tokens[0]['content'], + $value_if_true_tokens[0]['content'] === 'true' ? '(bool) $expr' : '! $expr' + ); + $phpcsFile->addWarning( $warning, $stackPtr, 'UnnecessaryTernary', $data ); + } + + private function get_nonempty_tokens( array $tokens, $start, $end ) { + $tokens = array_slice( $tokens, $start, $end - $start + 1 ); + + return array_values( array_filter( + $tokens, + array( $this, 'is_nonempty_token' ) + ) ); + } + + private function is_boolean_token( array $token ) { + return in_array( $token['code'], array( T_FALSE, T_TRUE ), true ); + } + + private function is_nonempty_token( array $token ) { + return ! in_array( $token['code'], Tokens::$emptyTokens, true ); + } +} diff --git a/tests/FixtureTests.php b/tests/FixtureTests.php index bad88454..40e39151 100644 --- a/tests/FixtureTests.php +++ b/tests/FixtureTests.php @@ -106,6 +106,7 @@ public function setUp() { 'HM.Namespaces.NoLeadingSlashOnUse', 'HM.Performance.SlowMetaQuery', 'HM.Performance.SlowOrderBy', + 'HM.PHP.Ternary', 'HM.Security.EscapeOutput', 'HM.Security.NonceVerification', 'HM.Security.ValidatedSanitizedInput', diff --git a/tests/fixtures/fail/ternary.php b/tests/fixtures/fail/ternary.php new file mode 100644 index 00000000..0d753a1b --- /dev/null +++ b/tests/fixtures/fail/ternary.php @@ -0,0 +1,13 @@ +