Skip to content

Commit b7b5f84

Browse files
committed
Handle new error inside processArguments
1 parent 579e874 commit b7b5f84

File tree

2 files changed

+23
-23
lines changed

2 files changed

+23
-23
lines changed

src/Rules/FunctionCallParametersCheck.php

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
use PHPStan\Type\VerbosityLevel;
2828
use function array_fill;
2929
use function array_key_exists;
30-
use function array_slice;
3130
use function count;
3231
use function implode;
3332
use function in_array;
@@ -82,22 +81,19 @@ public function check(
8281
{
8382
$functionParametersMinCount = 0;
8483
$functionParametersMaxCount = 0;
85-
$functionParameterNames = [];
8684
foreach ($parametersAcceptor->getParameters() as $parameter) {
8785
if (!$parameter->isOptional()) {
8886
$functionParametersMinCount++;
8987
}
9088

9189
$functionParametersMaxCount++;
92-
93-
$functionParameterNames[] = $parameter->getName();
9490
}
9591

9692
if ($parametersAcceptor->isVariadic()) {
9793
$functionParametersMaxCount = -1;
9894
}
9995

100-
/** @var array<int, array{Expr, Type|null, bool, string|null, int}> $arguments */
96+
/** @var array<int, array{Expr, Type|null, bool, string|null, int, bool}> $arguments */
10197
$arguments = [];
10298
/** @var array<int, Node\Arg> $args */
10399
$args = $funcCall->getArgs();
@@ -111,6 +107,8 @@ public function check(
111107
$argumentName = $arg->name->toString();
112108
}
113109

110+
$nonUnpackAfterUnpacked = false;
111+
114112
if ($hasNamedArguments && $arg->unpack) {
115113
$errors[] = RuleErrorBuilder::message('Named argument cannot be followed by an unpacked (...) argument.')
116114
->identifier('argument.unpackAfterNamed')
@@ -119,15 +117,9 @@ public function check(
119117
->build();
120118
}
121119
if ($hasUnpackedArgument && !$arg->unpack) {
122-
if ($argumentName !== null && $scope->getPhpVersion()->supportsNamedArgumentAfterUnpackedArgument()->yes()) {
123-
if (in_array($argumentName, array_slice($functionParameterNames, 0, count($arguments)), true)) {
124-
$errors[] = RuleErrorBuilder::message(sprintf('Named parameter cannot overwrite already unpacked argument $%s.', $argumentName))
125-
->identifier('argument.namedOverwriteAfterUnpacked')
126-
->line($arg->getStartLine())
127-
->nonIgnorable()
128-
->build();
129-
}
130-
} else {
120+
$nonUnpackAfterUnpacked = true;
121+
122+
if ($argumentName === null || !$scope->getPhpVersion()->supportsNamedArgumentAfterUnpackedArgument()->yes()) {
131123
$errors[] = RuleErrorBuilder::message('Unpacked argument (...) cannot be followed by a non-unpacked argument.')
132124
->identifier('argument.nonUnpackAfterUnpacked')
133125
->line($arg->getStartLine())
@@ -191,6 +183,7 @@ public function check(
191183
false,
192184
$keyArgumentName,
193185
$arg->getStartLine(),
186+
$nonUnpackAfterUnpacked,
194187
];
195188
}
196189
} else {
@@ -200,6 +193,7 @@ public function check(
200193
true,
201194
null,
202195
$arg->getStartLine(),
196+
$nonUnpackAfterUnpacked,
203197
];
204198
}
205199
continue;
@@ -211,6 +205,7 @@ public function check(
211205
false,
212206
$argumentName,
213207
$arg->getStartLine(),
208+
$nonUnpackAfterUnpacked,
214209
];
215210
}
216211

@@ -562,7 +557,7 @@ private function processArguments(
562557
$newArguments = [];
563558

564559
$namedArgumentAlreadyOccurred = false;
565-
foreach ($arguments as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine]) {
560+
foreach ($arguments as $i => [$argumentValue, $argumentValueType, $unpack, $argumentName, $argumentLine, $nonUnpackAfterUnpacked]) {
566561
if ($argumentName === null) {
567562
if (!isset($parameters[$i])) {
568563
if (!$parametersAcceptor->isVariadic() || count($parameters) === 0) {
@@ -622,10 +617,19 @@ private function processArguments(
622617
&& !$parameter->isVariadic()
623618
&& !array_key_exists($parameter->getName(), $unusedParametersByName)
624619
) {
625-
$errors[] = RuleErrorBuilder::message(sprintf('Argument for parameter $%s has already been passed.', $parameter->getName()))
626-
->identifier('argument.duplicate')
627-
->line($argumentLine)
628-
->build();
620+
if ($nonUnpackAfterUnpacked) {
621+
$errors[] = RuleErrorBuilder::message(sprintf('Named parameter cannot overwrite already unpacked argument $%s.', $argumentName))
622+
->identifier('argument.namedOverwriteAfterUnpacked')
623+
->line($argumentLine)
624+
->nonIgnorable()
625+
->build();
626+
} else {
627+
$errors[] = RuleErrorBuilder::message(sprintf('Argument for parameter $%s has already been passed.', $parameter->getName()))
628+
->identifier('argument.duplicate')
629+
->line($argumentLine)
630+
->build();
631+
}
632+
629633
continue;
630634
}
631635

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,10 +510,6 @@ public function testNamedArgumentsAfterUnpacking(): void
510510
'Named parameter cannot overwrite already unpacked argument $b.',
511511
14,
512512
],
513-
[
514-
'Argument for parameter $b has already been passed.',
515-
14,
516-
],
517513
]);
518514
}
519515

0 commit comments

Comments
 (0)