Skip to content

Commit c8e1948

Browse files
authored
Merge pull request #7 from savinmikhail/codex/fix-issue-#3-on-github
Skip passing default arguments when adding named arguments
2 parents f49442c + 1bb15ba commit c8e1948

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

src/AddNamedArgumentsRector.php

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use InvalidArgumentException;
88
use PhpParser\Node;
9+
use PhpParser\ConstExprEvaluator;
10+
use PhpParser\Node\Arg;
911
use PhpParser\Node\Expr\FuncCall;
1012
use PhpParser\Node\Expr\MethodCall;
1113
use PhpParser\Node\Expr\New_;
@@ -37,11 +39,14 @@ final class AddNamedArgumentsRector extends AbstractRector implements MinPhpVers
3739

3840
private readonly Reflection $reflectionService;
3941

42+
private readonly ConstExprEvaluator $constExprEvaluator;
43+
4044
public function __construct(
4145
ReflectionProvider $reflectionProvider,
4246
NodeNameResolver $nodeNameResolver,
4347
NodeTypeResolver $nodeTypeResolver,
4448
?Reflection $reflectionService = null,
49+
?ConstExprEvaluator $constExprEvaluator = null,
4550
) {
4651
if ($reflectionService === null) {
4752
$reflectionService = new Reflection(
@@ -51,6 +56,13 @@ public function __construct(
5156
);
5257
}
5358
$this->reflectionService = $reflectionService;
59+
$this->constExprEvaluator = $constExprEvaluator ?? new ConstExprEvaluator(static function (string $name) {
60+
if (\defined($name)) {
61+
return \constant($name);
62+
}
63+
64+
throw new \RuntimeException("Undefined constant: {$name}");
65+
});
5466
}
5567

5668
public function getRuleDefinition(): RuleDefinition
@@ -90,14 +102,43 @@ private function addNamesToArgs(
90102
FuncCall|StaticCall|MethodCall|New_ $node,
91103
array $parameters,
92104
): void {
93-
$argNames = [];
105+
$namedArgs = [];
94106
foreach ($node->args as $index => $arg) {
95-
$argNames[$index] = new Identifier(name: $parameters[$index]->getName());
107+
$parameter = $parameters[$index] ?? null;
108+
if ($parameter === null) {
109+
$namedArgs[] = $arg;
110+
continue;
111+
}
112+
113+
if ($this->shouldSkipArg($arg, $parameter)) {
114+
continue;
115+
}
116+
117+
$arg->name = new Identifier(name: $parameter->getName());
118+
$namedArgs[] = $arg;
96119
}
97120

98-
foreach ($node->args as $index => $arg) {
99-
$arg->name = $argNames[$index];
121+
$node->args = $namedArgs;
122+
}
123+
124+
private function shouldSkipArg(Arg $arg, ExtendedParameterReflection $parameter): bool
125+
{
126+
try {
127+
$defaultValue = $parameter->getDefaultValue();
128+
} catch (\Throwable) {
129+
return false;
130+
}
131+
132+
try {
133+
$argValue = $this->constExprEvaluator->evaluateDirectly($arg->value);
134+
} catch (\Throwable) {
135+
return false;
136+
}
137+
138+
if ($defaultValue instanceof \PHPStan\Type\ConstantScalarType) {
139+
$defaultValue = $defaultValue->getValue();
100140
}
141+
return $argValue === $defaultValue;
101142
}
102143

103144
public function provideMinPhpVersion(): int

tests/DefaultStrategy/Fixture/construct.php.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ new DateTimeImmutable('now');
66
-----
77
<?php
88

9-
new DateTimeImmutable(datetime: 'now');
9+
new DateTimeImmutable();
1010

1111
?>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
preg_split('/,/', 'a,b', -1, PREG_SPLIT_NO_EMPTY);
4+
?>
5+
-----
6+
<?php
7+
8+
preg_split(pattern: '/,/', subject: 'a,b', flags: PREG_SPLIT_NO_EMPTY);
9+
?>

0 commit comments

Comments
 (0)