New sniff to prefer ! empty ternaries#2863
Conversation
📝 WalkthroughWalkthroughThis PR systematically refactors ternary conditional expressions across multiple helper classes, widgets, and Stripe integration files from the Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/PreferNotEmptyTernarySniff.php`:
- Around line 209-244: The method findTernaryEnd() currently treats
T_INLINE_THEN and T_INLINE_ELSE as immediate terminators and thus fails on
nested ternaries; add a ternary nesting counter (e.g. $ternaryDepth = 0) and
update the loop to increment it when encountering T_INLINE_THEN and decrement it
when encountering T_INLINE_ELSE, and only treat those tokens as terminators when
$ternaryDepth is zero; update any existing checks that return $end on
T_INLINE_THEN/T_INLINE_ELSE to instead respect the $ternaryDepth (mirroring the
nesting logic used in findTernaryColon()) so nested ternary branches are skipped
correctly.
🧹 Nitpick comments (1)
phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/PreferNotEmptyTernarySniff.php (1)
131-139: Drop unused$closeParenand$tokensto avoid lint noise.
PHPMD flags both as unused; removing them keeps the sniff clean.♻️ Suggested cleanup
- $this->applyFix( - $phpcsFile, - $stackPtr, - $closeParen, - $ternaryOperator, - $colonOperator, - $ternaryEnd, - $emptyContent, - $thenContent - ); + $this->applyFix( + $phpcsFile, + $stackPtr, + $ternaryOperator, + $colonOperator, + $ternaryEnd, + $emptyContent, + $thenContent + ); @@ - private function applyFix( File $phpcsFile, $emptyToken, $closeParen, $ternaryOperator, $colonOperator, $ternaryEnd, $emptyContent, $thenContent ) { - $tokens = $phpcsFile->getTokens(); + private function applyFix( File $phpcsFile, $emptyToken, $ternaryOperator, $colonOperator, $ternaryEnd, $emptyContent, $thenContent ) { $fixer = $phpcsFile->fixer;Also applies to: 307-310
| private function findTernaryEnd( File $phpcsFile, $start ) { | ||
| $tokens = $phpcsFile->getTokens(); | ||
| $parenDepth = 0; | ||
| $end = false; | ||
|
|
||
| for ( $i = $start; $i < count( $tokens ); $i++ ) { | ||
| $code = $tokens[ $i ]['code']; | ||
|
|
||
| // Track parentheses. | ||
| if ( $code === T_OPEN_PARENTHESIS ) { | ||
| ++$parenDepth; | ||
| continue; | ||
| } | ||
|
|
||
| if ( $code === T_CLOSE_PARENTHESIS ) { | ||
| if ( $parenDepth > 0 ) { | ||
| --$parenDepth; | ||
| continue; | ||
| } | ||
|
|
||
| // This closes the containing expression. | ||
| return $end; | ||
| } | ||
|
|
||
| // Only process at the same parenthesis level. | ||
| if ( $parenDepth > 0 ) { | ||
| if ( $tokens[ $i ]['code'] !== T_WHITESPACE ) { | ||
| $end = $i; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| // Stop at statement terminators or operators that end the ternary. | ||
| if ( in_array( $code, array( T_SEMICOLON, T_CLOSE_TAG, T_COMMA, T_INLINE_THEN, T_INLINE_ELSE ), true ) ) { | ||
| return $end; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "*PreferNotEmpty*" -type fRepository: Strategy11/formidable-forms
Length of output: 147
🏁 Script executed:
cat -n phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/PreferNotEmptyTernarySniff.phpRepository: Strategy11/formidable-forms
Length of output: 11353
Guard against nested ternaries in the else branch to prevent incorrect auto-fixes. The findTernaryEnd() method stops at the first T_INLINE_THEN or T_INLINE_ELSE without tracking nested ternary depth. For example, empty($a) ? $b : $a ? $c : $d would incorrectly have $a identified as the end of the else expression, causing the fixer to rewrite the expression with wrong semantics. Unlike findTernaryColon() which properly tracks nesting, findTernaryEnd() needs to track ternary depth to skip over nested ternary operators.
🔧 Suggested fix
private function findTernaryEnd( File $phpcsFile, $start ) {
$tokens = $phpcsFile->getTokens();
$parenDepth = 0;
+ $ternaryDepth = 0;
$end = false;
for ( $i = $start; $i < count( $tokens ); $i++ ) {
$code = $tokens[ $i ]['code'];
@@
// Only process at the same parenthesis level.
if ( $parenDepth > 0 ) {
if ( $tokens[ $i ]['code'] !== T_WHITESPACE ) {
$end = $i;
}
continue;
}
- // Stop at statement terminators or operators that end the ternary.
- if ( in_array( $code, array( T_SEMICOLON, T_CLOSE_TAG, T_COMMA, T_INLINE_THEN, T_INLINE_ELSE ), true ) ) {
- return $end;
- }
+ // Track nested ternaries.
+ if ( $code === T_INLINE_THEN ) {
+ ++$ternaryDepth;
+ continue;
+ }
+ if ( $code === T_INLINE_ELSE ) {
+ if ( $ternaryDepth > 0 ) {
+ --$ternaryDepth;
+ continue;
+ }
+ return $end;
+ }
+
+ // Stop at statement terminators once we are out of nested ternaries.
+ if ( 0 === $ternaryDepth && in_array( $code, array( T_SEMICOLON, T_CLOSE_TAG, T_COMMA ), true ) ) {
+ return $end;
+ }🤖 Prompt for AI Agents
In `@phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/PreferNotEmptyTernarySniff.php`
around lines 209 - 244, The method findTernaryEnd() currently treats
T_INLINE_THEN and T_INLINE_ELSE as immediate terminators and thus fails on
nested ternaries; add a ternary nesting counter (e.g. $ternaryDepth = 0) and
update the loop to increment it when encountering T_INLINE_THEN and decrement it
when encountering T_INLINE_ELSE, and only treat those tokens as terminators when
$ternaryDepth is zero; update any existing checks that return $end on
T_INLINE_THEN/T_INLINE_ELSE to instead respect the $ternaryDepth (mirroring the
nesting logic used in findTernaryColon()) so nested ternary branches are skipped
correctly.
…y_ternaries New sniff to prefer ! empty ternaries
This update prefers
! empty( A ) ? A : Boverempty( A ) ? B : Awhich feels backwards sinceA ? A : Breads a lot better and! emptyis really a double negative / positive check.Summary by CodeRabbit
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.