Skip to content

Commit 2366e02

Browse files
Khartirkukulich
authored andcommitted
prevent ternary sniff from introducing logic errors
1 parent 7fb35c4 commit 2366e02

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

SlevomatCodingStandard/Sniffs/ControlStructures/RequireTernaryOperatorSniff.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
use const T_EQUAL;
1515
use const T_IF;
1616
use const T_INLINE_THEN;
17+
use const T_LOGICAL_AND;
18+
use const T_LOGICAL_OR;
19+
use const T_LOGICAL_XOR;
1720
use const T_RETURN;
1821
use const T_SEMICOLON;
1922
use const T_WHITESPACE;
@@ -84,14 +87,15 @@ private function checkIfWithReturns(File $phpcsFile, int $ifPointer, int $elsePo
8487
{
8588
$ifContainsComment = $this->containsComment($phpcsFile, $ifPointer);
8689
$elseContainsComment = $this->containsComment($phpcsFile, $elsePointer);
90+
$conditionContainsLogicalOperators = $this->containsLogicalOperators($phpcsFile, $ifPointer);
8791

8892
$errorParameters = [
8993
'Use ternary operator.',
9094
$ifPointer,
9195
self::CODE_TERNARY_OPERATOR_NOT_USED,
9296
];
9397

94-
if ($ifContainsComment || $elseContainsComment) {
98+
if ($ifContainsComment || $elseContainsComment || $conditionContainsLogicalOperators) {
9599
$phpcsFile->addError(...$errorParameters);
96100
return;
97101
}
@@ -174,14 +178,15 @@ private function checkIfWithAssignments(
174178

175179
$ifContainsComment = $this->containsComment($phpcsFile, $ifPointer);
176180
$elseContainsComment = $this->containsComment($phpcsFile, $elsePointer);
181+
$conditionContainsLogicalOperators = $this->containsLogicalOperators($phpcsFile, $ifPointer);
177182

178183
$errorParameters = [
179184
'Use ternary operator.',
180185
$ifPointer,
181186
self::CODE_TERNARY_OPERATOR_NOT_USED,
182187
];
183188

184-
if ($ifContainsComment || $elseContainsComment) {
189+
if ($ifContainsComment || $elseContainsComment || $conditionContainsLogicalOperators) {
185190
$phpcsFile->addError(...$errorParameters);
186191
return;
187192
}
@@ -253,4 +258,15 @@ private function containsComment(File $phpcsFile, int $scopeOwnerPointer): bool
253258
) !== null;
254259
}
255260

261+
private function containsLogicalOperators(File $phpcsFile, int $scopeOwnerPointer): bool
262+
{
263+
$tokens = $phpcsFile->getTokens();
264+
return TokenHelper::findNext(
265+
$phpcsFile,
266+
[T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR],
267+
$tokens[$scopeOwnerPointer]['parenthesis_opener'] + 1,
268+
$tokens[$scopeOwnerPointer]['parenthesis_closer']
269+
) !== null;
270+
}
271+
256272
}

tests/Sniffs/ControlStructures/RequireTernaryOperatorSniffTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function testErrors(): void
1616
{
1717
$report = self::checkFile(__DIR__ . '/data/requireTernaryOperatorErrors.php');
1818

19-
self::assertSame(8, $report->getErrorCount());
19+
self::assertSame(10, $report->getErrorCount());
2020

2121
self::assertSniffError($report, 4, RequireTernaryOperatorSniff::CODE_TERNARY_OPERATOR_NOT_USED);
2222
self::assertSniffError($report, 12, RequireTernaryOperatorSniff::CODE_TERNARY_OPERATOR_NOT_USED);
@@ -26,6 +26,8 @@ public function testErrors(): void
2626
self::assertSniffError($report, 42, RequireTernaryOperatorSniff::CODE_TERNARY_OPERATOR_NOT_USED);
2727
self::assertSniffError($report, 54, RequireTernaryOperatorSniff::CODE_TERNARY_OPERATOR_NOT_USED);
2828
self::assertSniffError($report, 63, RequireTernaryOperatorSniff::CODE_TERNARY_OPERATOR_NOT_USED);
29+
self::assertSniffError($report, 75, RequireTernaryOperatorSniff::CODE_TERNARY_OPERATOR_NOT_USED);
30+
self::assertSniffError($report, 82, RequireTernaryOperatorSniff::CODE_TERNARY_OPERATOR_NOT_USED);
2931

3032
self::assertAllFixedInFile($report);
3133
}

tests/Sniffs/ControlStructures/data/requireTernaryOperatorErrors.fixed.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,17 @@ public function __construct()
5555
&& $association->getInversedBy()
5656
&& $association instanceof OneToOneAssociationMetadata
5757
? 'a' : 'aa';
58+
59+
if (doAnything() and doNothing()) {
60+
$a = 'a';
61+
} else {
62+
$a = 'aa';
63+
}
64+
65+
function () {
66+
if (doAnything() and doNothing()) {
67+
return 'a';
68+
} else {
69+
return 'aa';
70+
}
71+
};

tests/Sniffs/ControlStructures/data/requireTernaryOperatorErrors.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,17 @@ public function __construct()
7171
} else {
7272
$a = 'aa';
7373
}
74+
75+
if (doAnything() and doNothing()) {
76+
$a = 'a';
77+
} else {
78+
$a = 'aa';
79+
}
80+
81+
function () {
82+
if (doAnything() and doNothing()) {
83+
return 'a';
84+
} else {
85+
return 'aa';
86+
}
87+
};

0 commit comments

Comments
 (0)