Skip to content

Commit 19703d4

Browse files
committed
Named arguments - cannot use positional after named
1 parent 5ab5201 commit 19703d4

File tree

3 files changed

+57
-3
lines changed

3 files changed

+57
-3
lines changed

src/Rules/FunctionCallParametersCheck.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,12 @@ public function check(
8383
/** @var array<int, \PhpParser\Node\Arg> $args */
8484
$args = $funcCall->args;
8585
$hasNamedArguments = false;
86+
$errors = [];
8687
foreach ($args as $i => $arg) {
8788
$type = $scope->getType($arg->value);
89+
if ($hasNamedArguments && $arg->name === null) {
90+
$errors[] = RuleErrorBuilder::message('Named argument cannot be followed by a positional argument.')->line($arg->getLine())->nonIgnorable()->build();
91+
}
8892
if ($arg->name !== null) {
8993
$hasNamedArguments = true;
9094
}
@@ -129,8 +133,6 @@ public function check(
129133
];
130134
}
131135

132-
$errors = [];
133-
134136
if ($hasNamedArguments && !$this->phpVersion->supportsNamedArguments()) {
135137
$errors[] = RuleErrorBuilder::message('Named arguments are supported only on PHP 8.0 and later.')->nonIgnorable()->build();
136138
}

tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@ class CallMethodsRuleTest extends \PHPStan\Testing\RuleTestCase
2727
/** @var bool */
2828
private $checkExplicitMixed = false;
2929

30+
/** @var int */
31+
private $phpVersion = PHP_VERSION_ID;
32+
3033
protected function getRule(): Rule
3134
{
3235
$broker = $this->createReflectionProvider();
3336
$ruleLevelHelper = new RuleLevelHelper($broker, $this->checkNullables, $this->checkThisOnly, $this->checkUnionTypes, $this->checkExplicitMixed);
3437
return new CallMethodsRule(
3538
$broker,
36-
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), true, true, true, true),
39+
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion($this->phpVersion), true, true, true, true),
3740
$ruleLevelHelper,
3841
true,
3942
true
@@ -1601,4 +1604,27 @@ public function testDisallowNamedArguments(): void
16011604
]);
16021605
}
16031606

1607+
public function testNamedArguments(): void
1608+
{
1609+
if (PHP_VERSION_ID < 80000 && !self::$useStaticReflectionProvider) {
1610+
$this->markTestSkipped('Test requires PHP 8.0.');
1611+
}
1612+
1613+
$this->checkThisOnly = false;
1614+
$this->checkNullables = true;
1615+
$this->checkUnionTypes = true;
1616+
$this->phpVersion = 80000;
1617+
1618+
$this->analyse([__DIR__ . '/data/named-arguments.php'], [
1619+
[
1620+
'Named argument cannot be followed by a positional argument.',
1621+
21,
1622+
],
1623+
[
1624+
'Named argument cannot be followed by a positional argument.',
1625+
22,
1626+
],
1627+
]);
1628+
}
1629+
16041630
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace NamedArgumentsMethod;
4+
5+
class Foo
6+
{
7+
8+
public function doFoo(
9+
int $i,
10+
int $j,
11+
int $k
12+
)
13+
{
14+
15+
}
16+
17+
public function doBar(): void
18+
{
19+
$this->doFoo(
20+
i: 1,
21+
2,
22+
3
23+
);
24+
}
25+
26+
}

0 commit comments

Comments
 (0)