Skip to content

Commit 3211807

Browse files
committed
skip allow falsy arg
1 parent 339c6b3 commit 3211807

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeSubstrFalsyRector\Fixture;
4+
5+
class SkipAsFalsyArg
6+
{
7+
public function run()
8+
{
9+
return $this->execute(substr('a', 2));
10+
}
11+
12+
private function execute(false|string $value)
13+
{
14+
return $value;
15+
}
16+
}

rules/DowngradePhp80/Rector/FuncCall/DowngradeSubstrFalsyRector.php

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@
1010
use PhpParser\Node\Expr\BinaryOp\Concat;
1111
use PhpParser\Node\Expr\BinaryOp\Identical;
1212
use PhpParser\Node\Expr\BooleanNot;
13+
use PhpParser\Node\Expr\CallLike;
1314
use PhpParser\Node\Expr\Cast;
1415
use PhpParser\Node\Expr\Cast\String_;
1516
use PhpParser\Node\Expr\Empty_;
1617
use PhpParser\Node\Expr\FuncCall;
1718
use PhpParser\Node\Expr\Ternary;
19+
use PHPStan\Reflection\FunctionReflection;
20+
use PHPStan\Reflection\MethodReflection;
1821
use PHPStan\Type\Constant\ConstantIntegerType;
22+
use Rector\NodeTypeResolver\PHPStan\ParametersAcceptorSelectorVariantsWrapper;
1923
use Rector\PhpParser\Node\Value\ValueResolver;
24+
use Rector\PHPStan\ScopeFetcher;
2025
use Rector\Rector\AbstractRector;
26+
use Rector\Reflection\ReflectionResolver;
2127
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
2228
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2329

@@ -34,6 +40,7 @@ final class DowngradeSubstrFalsyRector extends AbstractRector
3440
private const IS_UNCASTABLE = 'is_uncastable';
3541

3642
public function __construct(
43+
private readonly ReflectionResolver $reflectionResolver,
3744
private readonly ValueResolver $valueResolver
3845
) {
3946

@@ -58,12 +65,13 @@ public function getNodeTypes(): array
5865
Ternary::class,
5966
Identical::class,
6067
Concat::class,
68+
CallLike::class,
6169
FuncCall::class,
6270
];
6371
}
6472

6573
/**
66-
* @param Cast|Empty_|BooleanNot|Ternary|Identical|Concat|FuncCall $node
74+
* @param Cast|Empty_|BooleanNot|Ternary|Identical|Concat|CallLike|FuncCall $node
6775
*/
6876
public function refactor(Node $node): ?Node
6977
{
@@ -98,6 +106,35 @@ public function refactor(Node $node): ?Node
98106
return null;
99107
}
100108

109+
if ($node instanceof CallLike) {
110+
if ($node->isFirstClassCallable()) {
111+
return null;
112+
}
113+
114+
$reflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($node);
115+
116+
if (! $reflection instanceof MethodReflection && ! $reflection instanceof FunctionReflection) {
117+
return null;
118+
}
119+
120+
$parameterAcceptor = ParametersAcceptorSelectorVariantsWrapper::select(
121+
$reflection,
122+
$node,
123+
ScopeFetcher::fetch($node)
124+
);
125+
126+
foreach ($parameterAcceptor->getParameters() as $position => $parameterReflection) {
127+
if ($parameterReflection->getType()->isFalse()->no()) {
128+
continue;
129+
}
130+
131+
$arg = $node->getArg($parameterReflection->getName(), $position);
132+
if ($arg instanceof Arg) {
133+
$arg->value->setAttribute(self::IS_UNCASTABLE, true);
134+
}
135+
}
136+
}
137+
101138
if (! $this->isName($node, 'substr')) {
102139
return null;
103140
}

0 commit comments

Comments
 (0)