Skip to content

Commit 5cb3ce4

Browse files
SanderMullerclaude
authored andcommitted
Test the constant condition and side effect checks of the ternary rule
The constant condition and float checks now read the constant values, and the object check uses isObject(), so a mutant of them changes the result. New test cases cover a constant condition and a function that can have side effects. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent aa05d36 commit 5cb3ce4

3 files changed

Lines changed: 40 additions & 11 deletions

File tree

‎src/Rules/Comparison/UnnecessaryTernaryOperatorRule.php‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PHPStan\Type\ObjectWithoutClassType;
2121
use PHPStan\Type\TypeCombinator;
2222
use function count;
23+
use function is_float;
2324
use function is_string;
2425
use function sprintf;
2526

@@ -77,7 +78,7 @@ private function check(Node\Expr\Ternary $node, Scope $scope): ?IdentifierRuleEr
7778
{
7879
// TernaryOperatorConstantConditionRule already reports these
7980
$conditionType = $this->helper->getBooleanType($scope, $node->cond);
80-
if ($conditionType->isTrue()->yes() || $conditionType->isFalse()->yes()) {
81+
if (count($conditionType->getConstantScalarValues()) === 1) {
8182
return null;
8283
}
8384

@@ -173,7 +174,13 @@ private function isAlwaysResult(Scope $branchScope, Expr $result, Scope $scope,
173174
}
174175

175176
// 0.0 === -0.0, so `$f ?: 0.0` turns -0.0 into 0.0
176-
return $otherType->isFloat()->no();
177+
foreach ($otherType->getConstantScalarValues() as $value) {
178+
if (is_float($value)) {
179+
return false;
180+
}
181+
}
182+
183+
return true;
177184
}
178185

179186
/**
@@ -197,12 +204,11 @@ private function isTruthinessNarrowedExactly(Expr $cond, Scope $scope, bool $nat
197204
}
198205

199206
$type = $native ? $scope->getNativeType($cond) : $scope->getType($cond);
200-
$objectType = new ObjectWithoutClassType();
201-
if ($objectType->isSuperTypeOf($type)->no()) {
207+
if ($type->isObject()->no()) {
202208
return true;
203209
}
204210

205-
return TypeCombinator::intersect($type, $objectType)->toBoolean()->isTrue()->yes();
211+
return TypeCombinator::intersect($type, new ObjectWithoutClassType())->toBoolean()->isTrue()->yes();
206212
}
207213

208214
private function containsCall(Expr $expr): bool

‎tests/PHPStan/Rules/Comparison/UnnecessaryTernaryOperatorRuleTest.php‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,15 @@ public function testRule(): void
8787
],
8888
[
8989
'Short ternary operator ?: is unnecessary because it always results in $foo.',
90-
151,
90+
162,
9191
],
9292
[
9393
'Ternary operator is unnecessary because it always results in $s.',
94-
190,
94+
201,
9595
],
9696
[
9797
'Ternary operator is unnecessary because it always results in $foo.',
98-
195,
98+
206,
9999
],
100100
]);
101101
}
@@ -143,15 +143,15 @@ public function testRuleWithoutTreatingPhpDocTypesAsCertain(): void
143143
],
144144
[
145145
'Short ternary operator ?: is unnecessary because it always results in $foo.',
146-
151,
146+
162,
147147
],
148148
[
149149
'Ternary operator is unnecessary because it always results in $s.',
150-
190,
150+
201,
151151
],
152152
[
153153
'Ternary operator is unnecessary because it always results in $foo.',
154-
195,
154+
206,
155155
],
156156
]);
157157
}

‎tests/PHPStan/Rules/Comparison/data/unnecessary-ternary.php‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,17 @@ function strlenOfString(string|false $blob): int
143143
return $blob !== false ? strlen($blob) : 0;
144144
}
145145

146+
/** @return null */
147+
function maybeSideEffects()
148+
{
149+
return null;
150+
}
151+
152+
function callWithMaybeSideEffects(?Foo $foo): ?Foo
153+
{
154+
return $foo ?: maybeSideEffects();
155+
}
156+
146157
trait FooTrait
147158
{
148159

@@ -219,3 +230,15 @@ public function simpleXmlNot(?\SimpleXMLElement $xml): ?\SimpleXMLElement
219230
}
220231

221232
}
233+
234+
class ConstantCondition
235+
{
236+
237+
public function alwaysFalse(): int
238+
{
239+
// TernaryOperatorConstantConditionRule reports this
240+
$i = 0;
241+
return $i ?: 0;
242+
}
243+
244+
}

0 commit comments

Comments
 (0)