Skip to content

Commit 8fd217a

Browse files
authored
Named argument detection is scope-PHP version dependent
1 parent 202dd81 commit 8fd217a

22 files changed

+119
-56
lines changed

src/Analyser/MutatingScope.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -3139,7 +3139,7 @@ private function enterFunctionLike(
31393139

31403140
$paramExprString = '$' . $parameter->getName();
31413141
if ($parameter->isVariadic()) {
3142-
if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()->yes()) {
3142+
if (!$this->getPhpVersion()->supportsNamedArguments()->no() && $functionReflection->acceptsNamedArguments()->yes()) {
31433143
$parameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $parameterType);
31443144
} else {
31453145
$parameterType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $parameterType), new AccessoryArrayListType());
@@ -3154,7 +3154,7 @@ private function enterFunctionLike(
31543154

31553155
$nativeParameterType = $parameter->getNativeType();
31563156
if ($parameter->isVariadic()) {
3157-
if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()->yes()) {
3157+
if (!$this->getPhpVersion()->supportsNamedArguments()->no() && $functionReflection->acceptsNamedArguments()->yes()) {
31583158
$nativeParameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $nativeParameterType);
31593159
} else {
31603160
$nativeParameterType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $nativeParameterType), new AccessoryArrayListType());
@@ -3629,7 +3629,7 @@ public function getFunctionType($type, bool $isNullable, bool $isVariadic): Type
36293629
);
36303630
}
36313631
if ($isVariadic) {
3632-
if ($this->phpVersion->supportsNamedArguments()) {
3632+
if (!$this->getPhpVersion()->supportsNamedArguments()->no()) {
36333633
return new ArrayType(new UnionType([new IntegerType(), new StringType()]), $this->getFunctionType(
36343634
$type,
36353635
false,

src/Php/PhpVersions.php

+5
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,9 @@ public function producesWarningForFinalPrivateMethods(): TrinaryLogic
2828
return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result;
2929
}
3030

31+
public function supportsNamedArguments(): TrinaryLogic
32+
{
33+
return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result;
34+
}
35+
3136
}

src/Rules/FunctionCallParametersCheck.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use PhpParser\Node\Expr;
77
use PHPStan\Analyser\MutatingScope;
88
use PHPStan\Analyser\Scope;
9-
use PHPStan\Php\PhpVersion;
109
use PHPStan\Reflection\ExtendedParameterReflection;
1110
use PHPStan\Reflection\ParameterReflection;
1211
use PHPStan\Reflection\ParametersAcceptor;
@@ -42,7 +41,6 @@ final class FunctionCallParametersCheck
4241
public function __construct(
4342
private RuleLevelHelper $ruleLevelHelper,
4443
private NullsafeCheck $nullsafeCheck,
45-
private PhpVersion $phpVersion,
4644
private UnresolvableTypeHelper $unresolvableTypeHelper,
4745
private PropertyReflectionFinder $propertyReflectionFinder,
4846
private bool $checkArgumentTypes,
@@ -201,7 +199,7 @@ public function check(
201199
];
202200
}
203201

204-
if ($hasNamedArguments && !$this->phpVersion->supportsNamedArguments() && !(bool) $funcCall->getAttribute('isAttribute', false)) {
202+
if ($hasNamedArguments && !$scope->getPhpVersion()->supportsNamedArguments()->yes() && !(bool) $funcCall->getAttribute('isAttribute', false)) {
205203
$errors[] = RuleErrorBuilder::message('Named arguments are supported only on PHP 8.0 and later.')
206204
->identifier('argument.namedNotSupported')
207205
->line($funcCall->getStartLine())

tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Analyser;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\FunctionCallParametersCheck;
76
use PHPStan\Rules\Methods\CallMethodsRule;
87
use PHPStan\Rules\Methods\MethodCallCheck;
@@ -12,7 +11,6 @@
1211
use PHPStan\Rules\Rule;
1312
use PHPStan\Rules\RuleLevelHelper;
1413
use PHPStan\Testing\RuleTestCase;
15-
use const PHP_VERSION_ID;
1614

1715
/**
1816
* @extends RuleTestCase<CallMethodsRule>
@@ -26,7 +24,7 @@ protected function getRule(): Rule
2624
$ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false);
2725
return new CallMethodsRule(
2826
new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true),
29-
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
27+
new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
3028
);
3129
}
3230

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php // lint > 7.4
2+
3+
namespace Bug2600PhpVersionScope;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
if (PHP_VERSION_ID >= 80000) {
8+
class Foo8 {
9+
/**
10+
* @param mixed $x
11+
*/
12+
public function doBaz(...$x) {
13+
assertType('array<int|string, mixed>', $x);
14+
}
15+
}
16+
} else {
17+
class Foo9 {
18+
/**
19+
* @param mixed $x
20+
*/
21+
public function doBaz(...$x) {
22+
assertType('list<mixed>', $x);
23+
}
24+
}
25+
26+
}

tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Classes;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\AttributesCheck;
76
use PHPStan\Rules\ClassCaseSensitivityCheck;
87
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -35,7 +34,6 @@ protected function getRule(): Rule
3534
new FunctionCallParametersCheck(
3635
new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false),
3736
new NullsafeCheck(),
38-
new PhpVersion(80000),
3937
new UnresolvableTypeHelper(),
4038
new PropertyReflectionFinder(),
4139
true,

tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Classes;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\AttributesCheck;
76
use PHPStan\Rules\ClassCaseSensitivityCheck;
87
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -30,7 +29,6 @@ protected function getRule(): Rule
3029
new FunctionCallParametersCheck(
3130
new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false),
3231
new NullsafeCheck(),
33-
new PhpVersion(80000),
3432
new UnresolvableTypeHelper(),
3533
new PropertyReflectionFinder(),
3634
true,

tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Classes;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\ClassCaseSensitivityCheck;
76
use PHPStan\Rules\ClassForbiddenNameCheck;
87
use PHPStan\Rules\ClassNameCheck;
@@ -26,7 +25,7 @@ protected function getRule(): Rule
2625
$reflectionProvider = $this->createReflectionProvider();
2726
return new InstantiationRule(
2827
$reflectionProvider,
29-
new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
28+
new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
3029
new ClassNameCheck(
3130
new ClassCaseSensitivityCheck($reflectionProvider, true),
3231
new ClassForbiddenNameCheck(self::getContainer()),

tests/PHPStan/Rules/Classes/InstantiationRuleTest.php

+9-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Classes;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\ClassCaseSensitivityCheck;
76
use PHPStan\Rules\ClassForbiddenNameCheck;
87
use PHPStan\Rules\ClassNameCheck;
@@ -26,7 +25,7 @@ protected function getRule(): Rule
2625
$reflectionProvider = $this->createReflectionProvider();
2726
return new InstantiationRule(
2827
$reflectionProvider,
29-
new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
28+
new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
3029
new ClassNameCheck(
3130
new ClassCaseSensitivityCheck($reflectionProvider, true),
3231
new ClassForbiddenNameCheck(self::getContainer()),
@@ -290,6 +289,10 @@ public function testBug4056(): void
290289

291290
public function testNamedArguments(): void
292291
{
292+
if (PHP_VERSION_ID < 80000) {
293+
$this->markTestSkipped('Test requires PHP 8.0');
294+
}
295+
293296
$this->analyse([__DIR__ . '/data/instantiation-named-arguments.php'], [
294297
[
295298
'Missing parameter $j (int) in call to InstantiationNamedArguments\Foo constructor.',
@@ -501,6 +504,10 @@ public function testBug10248(): void
501504

502505
public function testBug11815(): void
503506
{
507+
if (PHP_VERSION_ID < 80000) {
508+
$this->markTestSkipped('Test requires PHP 8.0');
509+
}
510+
504511
$this->analyse([__DIR__ . '/data/bug-11815.php'], []);
505512
}
506513

tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\EnumCases;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\AttributesCheck;
76
use PHPStan\Rules\ClassCaseSensitivityCheck;
87
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -30,7 +29,6 @@ protected function getRule(): Rule
3029
new FunctionCallParametersCheck(
3130
new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false),
3231
new NullsafeCheck(),
33-
new PhpVersion(80100),
3432
new UnresolvableTypeHelper(),
3533
new PropertyReflectionFinder(),
3634
true,

tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Functions;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\AttributesCheck;
76
use PHPStan\Rules\ClassCaseSensitivityCheck;
87
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -30,7 +29,6 @@ protected function getRule(): Rule
3029
new FunctionCallParametersCheck(
3130
new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false),
3231
new NullsafeCheck(),
33-
new PhpVersion(80000),
3432
new UnresolvableTypeHelper(),
3533
new PropertyReflectionFinder(),
3634
true,

tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Functions;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\FunctionCallParametersCheck;
76
use PHPStan\Rules\NullsafeCheck;
87
use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper;
@@ -27,7 +26,6 @@ protected function getRule(): Rule
2726
new FunctionCallParametersCheck(
2827
$ruleLevelHelper,
2928
new NullsafeCheck(),
30-
new PhpVersion(80000),
3129
new UnresolvableTypeHelper(),
3230
new PropertyReflectionFinder(),
3331
true,
@@ -158,6 +156,10 @@ public function testRule(): void
158156

159157
public function testNamedArguments(): void
160158
{
159+
if (PHP_VERSION_ID < 80000) {
160+
$this->markTestSkipped('Test requires PHP 8.0');
161+
}
162+
161163
$this->analyse([__DIR__ . '/data/callables-named-arguments.php'], [
162164
[
163165
'Missing parameter $j (int) in call to closure.',

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

+5-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Functions;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\FunctionCallParametersCheck;
76
use PHPStan\Rules\NullsafeCheck;
87
use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper;
@@ -28,7 +27,7 @@ protected function getRule(): Rule
2827
$broker = $this->createReflectionProvider();
2928
return new CallToFunctionParametersRule(
3029
$broker,
31-
new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
30+
new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true),
3231
);
3332
}
3433

@@ -477,6 +476,10 @@ public function testGenericFunction(): void
477476

478477
public function testNamedArguments(): void
479478
{
479+
if (PHP_VERSION_ID < 80000) {
480+
$this->markTestSkipped('Test requires PHP 8.0');
481+
}
482+
480483
$errors = [
481484
[
482485
'Missing parameter $j (int) in call to function FunctionNamedArguments\foo.',
@@ -491,12 +494,6 @@ public function testNamedArguments(): void
491494
14,
492495
],
493496
];
494-
if (PHP_VERSION_ID < 80000) {
495-
$errors[] = [
496-
'Missing parameter $arr1 (array) in call to function array_merge.',
497-
14,
498-
];
499-
}
500497

501498
require_once __DIR__ . '/data/named-arguments-define.php';
502499
$this->analyse([__DIR__ . '/data/named-arguments.php'], $errors);

tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Functions;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\FunctionCallParametersCheck;
76
use PHPStan\Rules\NullsafeCheck;
87
use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper;
@@ -21,7 +20,7 @@ class CallUserFuncRuleTest extends RuleTestCase
2120
protected function getRule(): Rule
2221
{
2322
$reflectionProvider = $this->createReflectionProvider();
24-
return new CallUserFuncRule($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true));
23+
return new CallUserFuncRule($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true));
2524
}
2625

2726
public function testRule(): void

tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Functions;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\AttributesCheck;
76
use PHPStan\Rules\ClassCaseSensitivityCheck;
87
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -30,7 +29,6 @@ protected function getRule(): Rule
3029
new FunctionCallParametersCheck(
3130
new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false),
3231
new NullsafeCheck(),
33-
new PhpVersion(80000),
3432
new UnresolvableTypeHelper(),
3533
new PropertyReflectionFinder(),
3634
true,

tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Functions;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\AttributesCheck;
76
use PHPStan\Rules\ClassCaseSensitivityCheck;
87
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -30,7 +29,6 @@ protected function getRule(): Rule
3029
new FunctionCallParametersCheck(
3130
new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false),
3231
new NullsafeCheck(),
33-
new PhpVersion(80000),
3432
new UnresolvableTypeHelper(),
3533
new PropertyReflectionFinder(),
3634
true,

tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace PHPStan\Rules\Functions;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\AttributesCheck;
76
use PHPStan\Rules\ClassCaseSensitivityCheck;
87
use PHPStan\Rules\ClassForbiddenNameCheck;
@@ -30,7 +29,6 @@ protected function getRule(): Rule
3029
new FunctionCallParametersCheck(
3130
new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false),
3231
new NullsafeCheck(),
33-
new PhpVersion(80000),
3432
new UnresolvableTypeHelper(),
3533
new PropertyReflectionFinder(),
3634
true,

0 commit comments

Comments
 (0)