Skip to content

Commit 5ab5201

Browse files
committed
Disallow named arguments on PHP < 8.0
1 parent b4e9e9e commit 5ab5201

File tree

8 files changed

+68
-4
lines changed

8 files changed

+68
-4
lines changed

src/Php/PhpVersion.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,9 @@ public function supportsUnsetCast(): bool
9191
return $this->versionId < 80000;
9292
}
9393

94+
public function supportsNamedArguments(): bool
95+
{
96+
return $this->versionId >= 80000;
97+
}
98+
9499
}

src/Rules/FunctionCallParametersCheck.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpParser\Node\Expr;
66
use PHPStan\Analyser\Scope;
7+
use PHPStan\Php\PhpVersion;
78
use PHPStan\Reflection\ParametersAcceptor;
89
use PHPStan\Type\ErrorType;
910
use PHPStan\Type\NeverType;
@@ -20,6 +21,8 @@ class FunctionCallParametersCheck
2021

2122
private NullsafeCheck $nullsafeCheck;
2223

24+
private PhpVersion $phpVersion;
25+
2326
private bool $checkArgumentTypes;
2427

2528
private bool $checkArgumentsPassedByReference;
@@ -31,6 +34,7 @@ class FunctionCallParametersCheck
3134
public function __construct(
3235
RuleLevelHelper $ruleLevelHelper,
3336
NullsafeCheck $nullsafeCheck,
37+
PhpVersion $phpVersion,
3438
bool $checkArgumentTypes,
3539
bool $checkArgumentsPassedByReference,
3640
bool $checkExtraArguments,
@@ -39,6 +43,7 @@ public function __construct(
3943
{
4044
$this->ruleLevelHelper = $ruleLevelHelper;
4145
$this->nullsafeCheck = $nullsafeCheck;
46+
$this->phpVersion = $phpVersion;
4247
$this->checkArgumentTypes = $checkArgumentTypes;
4348
$this->checkArgumentsPassedByReference = $checkArgumentsPassedByReference;
4449
$this->checkExtraArguments = $checkExtraArguments;
@@ -77,8 +82,12 @@ public function check(
7782
$arguments = [];
7883
/** @var array<int, \PhpParser\Node\Arg> $args */
7984
$args = $funcCall->args;
85+
$hasNamedArguments = false;
8086
foreach ($args as $i => $arg) {
8187
$type = $scope->getType($arg->value);
88+
if ($arg->name !== null) {
89+
$hasNamedArguments = true;
90+
}
8291
if ($arg->unpack) {
8392
$arrays = TypeUtils::getConstantArrays($type);
8493
if (count($arrays) > 0) {
@@ -121,6 +130,11 @@ public function check(
121130
}
122131

123132
$errors = [];
133+
134+
if ($hasNamedArguments && !$this->phpVersion->supportsNamedArguments()) {
135+
$errors[] = RuleErrorBuilder::message('Named arguments are supported only on PHP 8.0 and later.')->nonIgnorable()->build();
136+
}
137+
124138
$invokedParametersCount = count($arguments);
125139
foreach ($arguments as $i => [$argumentValue, $argumentValueType, $unpack]) {
126140
if ($unpack) {

tests/PHPStan/Rules/Classes/InstantiationRuleTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\Classes;
44

5+
use PHPStan\Php\PhpVersion;
56
use PHPStan\Rules\ClassCaseSensitivityCheck;
67
use PHPStan\Rules\FunctionCallParametersCheck;
78
use PHPStan\Rules\NullsafeCheck;
@@ -18,7 +19,7 @@ protected function getRule(): \PHPStan\Rules\Rule
1819
$broker = $this->createReflectionProvider();
1920
return new InstantiationRule(
2021
$broker,
21-
new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, false), new NullsafeCheck(), true, true, true, true),
22+
new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, false), new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), true, true, true, true),
2223
new ClassCaseSensitivityCheck($broker)
2324
);
2425
}

tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\Functions;
44

5+
use PHPStan\Php\PhpVersion;
56
use PHPStan\Rules\FunctionCallParametersCheck;
67
use PHPStan\Rules\NullsafeCheck;
78
use PHPStan\Rules\RuleLevelHelper;
@@ -19,6 +20,7 @@ protected function getRule(): \PHPStan\Rules\Rule
1920
new FunctionCallParametersCheck(
2021
$ruleLevelHelper,
2122
new NullsafeCheck(),
23+
new PhpVersion(PHP_VERSION_ID),
2224
true,
2325
true,
2426
true,

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\Functions;
44

5+
use PHPStan\Php\PhpVersion;
56
use PHPStan\Rules\FunctionCallParametersCheck;
67
use PHPStan\Rules\NullsafeCheck;
78
use PHPStan\Rules\RuleLevelHelper;
@@ -17,7 +18,7 @@ protected function getRule(): \PHPStan\Rules\Rule
1718
$broker = $this->createReflectionProvider();
1819
return new CallToFunctionParametersRule(
1920
$broker,
20-
new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, false), new NullsafeCheck(), true, true, true, true)
21+
new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, false), new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), true, true, true, true)
2122
);
2223
}
2324

tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\Methods;
44

5+
use PHPStan\Php\PhpVersion;
56
use PHPStan\Rules\FunctionCallParametersCheck;
67
use PHPStan\Rules\NullsafeCheck;
78
use PHPStan\Rules\Rule;
@@ -32,7 +33,7 @@ protected function getRule(): Rule
3233
$ruleLevelHelper = new RuleLevelHelper($broker, $this->checkNullables, $this->checkThisOnly, $this->checkUnionTypes, $this->checkExplicitMixed);
3334
return new CallMethodsRule(
3435
$broker,
35-
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), true, true, true, true),
36+
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), true, true, true, true),
3637
$ruleLevelHelper,
3738
true,
3839
true
@@ -1579,4 +1580,25 @@ public function testNullSafe(): void
15791580
]);
15801581
}
15811582

1583+
public function testDisallowNamedArguments(): void
1584+
{
1585+
if (PHP_VERSION_ID >= 80000) {
1586+
$this->markTestSkipped('Test requires PHP earlier than 8.0.');
1587+
}
1588+
if (!self::$useStaticReflectionProvider) {
1589+
$this->markTestSkipped('Test requires static reflection.');
1590+
}
1591+
1592+
$this->checkThisOnly = false;
1593+
$this->checkNullables = true;
1594+
$this->checkUnionTypes = true;
1595+
1596+
$this->analyse([__DIR__ . '/data/disallow-named-arguments.php'], [
1597+
[
1598+
'Named arguments are supported only on PHP 8.0 and later.',
1599+
10,
1600+
],
1601+
]);
1602+
}
1603+
15821604
}

tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\Methods;
44

5+
use PHPStan\Php\PhpVersion;
56
use PHPStan\Rules\ClassCaseSensitivityCheck;
67
use PHPStan\Rules\FunctionCallParametersCheck;
78
use PHPStan\Rules\NullsafeCheck;
@@ -22,7 +23,7 @@ protected function getRule(): \PHPStan\Rules\Rule
2223
$ruleLevelHelper = new RuleLevelHelper($broker, true, $this->checkThisOnly, true, false);
2324
return new CallStaticMethodsRule(
2425
$broker,
25-
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), true, true, true, true),
26+
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), true, true, true, true),
2627
$ruleLevelHelper,
2728
new ClassCaseSensitivityCheck($broker),
2829
true,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace DisallowNamedArguments;
4+
5+
class Foo
6+
{
7+
8+
public function doFoo(): void
9+
{
10+
$this->doBar(i: 1);
11+
}
12+
13+
public function doBar(int $i): void
14+
{
15+
16+
}
17+
18+
}

0 commit comments

Comments
 (0)