Skip to content

Commit 0aefb7e

Browse files
committed
[fix] wrap ternary in parenthese on string casting, if only cond is casted
1 parent b1ab1d9 commit 0aefb7e

File tree

3 files changed

+98
-3
lines changed

3 files changed

+98
-3
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector\Fixture;
6+
7+
final class SkipStringCasted
8+
{
9+
public function run($value)
10+
{
11+
explode(
12+
',',
13+
(string) $value ? $_SERVER['REMOTE_ADDR'] : $_SERVER['HTTP_X_FORWARDED_FOR'] ?? ''
14+
);
15+
}
16+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector\Fixture;
6+
7+
final class TernaryWithInts
8+
{
9+
public function run($value)
10+
{
11+
explode(
12+
',',
13+
(string) $value ? 100 : 500
14+
);
15+
}
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
declare(strict_types=1);
23+
24+
namespace Rector\Tests\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector\Fixture;
25+
26+
final class TernaryWithInts
27+
{
28+
public function run($value)
29+
{
30+
explode(
31+
',',
32+
(string) ((string) $value ? 100 : 500)
33+
);
34+
}
35+
}
36+
37+
?>

rules/Php81/NodeManipulator/NullToStrictStringIntConverter.php

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use PHPStan\Type\Type;
2525
use PHPStan\Type\UnionType;
2626
use Rector\NodeAnalyzer\PropertyFetchAnalyzer;
27+
use Rector\NodeTypeResolver\Node\AttributeKey;
2728
use Rector\NodeTypeResolver\NodeTypeResolver;
2829
use Rector\PhpParser\Node\Value\ValueResolver;
2930

@@ -53,12 +54,18 @@ public function convertIfNull(
5354
}
5455

5556
$argValue = $args[$position]->value;
57+
5658
if ($this->valueResolver->isNull($argValue)) {
5759
$args[$position]->value = $targetType === 'string' ? new String_('') : new Int_(0);
5860
$funcCall->args = $args;
5961
return $funcCall;
6062
}
6163

64+
// skip (string) ternary conditions with both values
65+
if ($this->isStringCastedTernaryOfMixedTypes($argValue, $scope)) {
66+
return null;
67+
}
68+
6269
if ($this->shouldSkipValue($argValue, $scope, $isTrait, $targetType)) {
6370
return null;
6471
}
@@ -72,6 +79,7 @@ public function convertIfNull(
7279
}
7380

7481
if ($argValue instanceof Ternary && ! $this->shouldSkipValue($argValue->else, $scope, $isTrait, $targetType)) {
82+
7583
if ($this->valueResolver->isNull($argValue->else)) {
7684
$argValue->else = $targetType === 'string' ? new String_('') : new Int_(0);
7785
} else {
@@ -81,12 +89,27 @@ public function convertIfNull(
8189
}
8290

8391
$args[$position]->value = $argValue;
84-
$funcCall->args = $args;
92+
8593
return $funcCall;
8694
}
8795

88-
$args[$position]->value = $targetType === 'string' ? new CastString_($argValue) : new CastInt_($argValue);
89-
$funcCall->args = $args;
96+
$wrapInParentheses = false;
97+
if ($argValue instanceof Ternary && $argValue->cond instanceof CastString_) {
98+
$wrapInParentheses = true;
99+
}
100+
101+
if ($targetType === 'string') {
102+
$castedType = new CastString_($argValue);
103+
} else {
104+
$castedType = new CastInt_($argValue);
105+
}
106+
107+
if ($wrapInParentheses) {
108+
$argValue->setAttribute(AttributeKey::WRAPPED_IN_PARENTHESES, true);
109+
}
110+
111+
$args[$position]->value = $castedType;
112+
90113
return $funcCall;
91114
}
92115

@@ -221,4 +244,23 @@ private function isPossibleArrayVariableName(Type $passedType, Type $reflectionP
221244

222245
return false;
223246
}
247+
248+
private function isStringCastedTernaryOfMixedTypes(Expr $expr, Scope $scope): bool
249+
{
250+
if (! $expr instanceof Ternary) {
251+
return false;
252+
}
253+
254+
if (! $expr->cond instanceof CastString_) {
255+
return false;
256+
}
257+
258+
if (! $expr->if instanceof Expr) {
259+
return false;
260+
}
261+
262+
$ifType = $scope->getType($expr->if);
263+
$elseType = $scope->getType($expr->else);
264+
return $ifType instanceof MixedType || $elseType instanceof MixedType;
265+
}
224266
}

0 commit comments

Comments
 (0)