Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/Php/PhpVersions.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,51 @@ public function supportsNativeTypesInClassConstants(): TrinaryLogic
return IntegerRangeType::fromInterval(80300, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsConstantsInTraits(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80200, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsNeverReturnTypeInArrowFunction(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80200, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsArrayUnpackingWithStringKeys(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsPropertyHooks(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80400, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsFinalProperties(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80400, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsAsymmetricVisibilityForStaticProperties(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsOverrideAttributeOnProperty(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsAttributesOnGlobalConstants(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsUnsetCast(): TrinaryLogic
{
return IntegerRangeType::fromInterval(null, 79999)->isSuperTypeOf($this->phpVersions)->result;
}

public function supportsTrueAndFalseStandaloneType(): TrinaryLogic
{
return IntegerRangeType::fromInterval(80200, null)->isSuperTypeOf($this->phpVersions)->result;
Expand Down
5 changes: 2 additions & 3 deletions src/Rules/Arrays/ArrayUnpackingRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Node\Expr\NativeTypeExpr;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
Expand All @@ -23,7 +22,7 @@
final class ArrayUnpackingRule implements Rule
{

public function __construct(private PhpVersion $phpVersion, private RuleLevelHelper $ruleLevelHelper)
public function __construct(private RuleLevelHelper $ruleLevelHelper)
{
}

Expand All @@ -34,7 +33,7 @@ public function getNodeType(): string

public function processNode(Node $node, Scope $scope): array
{
if ($node->unpack === false || $this->phpVersion->supportsArrayUnpackingWithStringKeys()) {
if ($node->unpack === false || $scope->getPhpVersion()->supportsArrayUnpackingWithStringKeys()->yes()) {
return [];
}

Expand Down
7 changes: 1 addition & 6 deletions src/Rules/Cast/UnsetCastRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

Expand All @@ -16,18 +15,14 @@
final class UnsetCastRule implements Rule
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function getNodeType(): string
{
return Node\Expr\Cast\Unset_::class;
}

public function processNode(Node $node, Scope $scope): array
{
if ($this->phpVersion->supportsUnsetCast()) {
if ($scope->getPhpVersion()->supportsUnsetCast()->yes()) {
return [];
}

Expand Down
4 changes: 1 addition & 3 deletions src/Rules/Constants/ConstantAttributesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use PHPStan\Analyser\NodeCallbackInvoker;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\AttributesCheck;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
Expand All @@ -23,7 +22,6 @@ final class ConstantAttributesRule implements Rule

public function __construct(
private AttributesCheck $attributesCheck,
private PhpVersion $phpVersion,
)
{
}
Expand All @@ -39,7 +37,7 @@ public function processNode(Node $node, Scope&NodeCallbackInvoker&CollectedDataE
return [];
}

if (!$this->phpVersion->supportsAttributesOnGlobalConstants()) {
if (!$scope->getPhpVersion()->supportsAttributesOnGlobalConstants()->yes()) {
return [
RuleErrorBuilder::message('Attributes on global constants are supported only on PHP 8.5 and later.')
->identifier('constant.attributesNotSupported')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\FunctionDefinitionCheck;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
Expand All @@ -20,7 +19,7 @@
final class ExistingClassesInArrowFunctionTypehintsRule implements Rule
{

public function __construct(private FunctionDefinitionCheck $check, private PhpVersion $phpVersion)
public function __construct(private FunctionDefinitionCheck $check)
{
}

Expand All @@ -32,7 +31,7 @@ public function getNodeType(): string
public function processNode(Node $node, Scope $scope): array
{
$messages = [];
if ($node->returnType !== null && !$this->phpVersion->supportsNeverReturnTypeInArrowFunction()) {
if ($node->returnType !== null && !$scope->getPhpVersion()->supportsNeverReturnTypeInArrowFunction()->yes()) {
$returnType = ParserNodeTypeToPHPStanType::resolve($node->returnType, $scope->isInClass() ? $scope->getClassReflection() : null);
if ($returnType instanceof NonAcceptingNeverType) {
$messages[] = RuleErrorBuilder::message('Never return type in arrow function is supported only on PHP 8.2 and later.')
Expand Down
7 changes: 1 addition & 6 deletions src/Rules/Properties/PropertiesInInterfaceRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Node\ClassPropertyNode;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

Expand All @@ -17,10 +16,6 @@
final class PropertiesInInterfaceRule implements Rule
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function getNodeType(): string
{
return ClassPropertyNode::class;
Expand All @@ -32,7 +27,7 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

if (!$this->phpVersion->supportsPropertyHooks()) {
if (!$scope->getPhpVersion()->supportsPropertyHooks()->yes()) {
return [
RuleErrorBuilder::message('Interfaces can include properties only on PHP 8.4 and later.')
->nonIgnorable()
Expand Down
4 changes: 1 addition & 3 deletions src/Rules/Properties/PropertyAttributesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Node\ClassPropertyNode;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\AttributesCheck;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
Expand All @@ -24,7 +23,6 @@ final class PropertyAttributesRule implements Rule

public function __construct(
private AttributesCheck $attributesCheck,
private PhpVersion $phpVersion,
)
{
}
Expand All @@ -36,7 +34,7 @@ public function getNodeType(): string

public function processNode(Node $node, Scope&NodeCallbackInvoker&CollectedDataEmitter $scope): array
{
if (!$this->phpVersion->supportsOverrideAttributeOnProperty()) {
if (!$scope->getPhpVersion()->supportsOverrideAttributeOnProperty()->yes()) {
$propertyReflection = $node->getClassReflection()->getNativeProperty($node->getName());
if (count($propertyReflection->getNativeReflection()->getAttributes('Override')) > 0) {
return [
Expand Down
11 changes: 3 additions & 8 deletions src/Rules/Properties/PropertyInClassRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Node\ClassPropertyNode;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

Expand All @@ -17,10 +16,6 @@
final class PropertyInClassRule implements Rule
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function getNodeType(): string
{
return ClassPropertyNode::class;
Expand All @@ -36,7 +31,7 @@ public function processNode(Node $node, Scope $scope): array

if (
$node->isFinal()
&& !$this->phpVersion->supportsFinalProperties()
&& !$scope->getPhpVersion()->supportsFinalProperties()->yes()
) {
return [
RuleErrorBuilder::message('Final properties are supported only on PHP 8.4 and later.')
Expand Down Expand Up @@ -164,7 +159,7 @@ public function processNode(Node $node, Scope $scope): array
];
}
if (
!$this->phpVersion->supportsAsymmetricVisibilityForStaticProperties()
!$scope->getPhpVersion()->supportsAsymmetricVisibilityForStaticProperties()->yes()
&& (
$node->isPrivateSet()
|| $node->isProtectedSet()
Expand All @@ -191,7 +186,7 @@ public function processNode(Node $node, Scope $scope): array
}
}

if (!$this->phpVersion->supportsPropertyHooks()) {
if (!$scope->getPhpVersion()->supportsPropertyHooks()->yes()) {
if ($node->hasHooks()) {
return [
RuleErrorBuilder::message('Property hooks are supported only on PHP 8.4 and later.')
Expand Down
7 changes: 1 addition & 6 deletions src/Rules/Traits/ConstantsInTraitsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

Expand All @@ -16,10 +15,6 @@
final class ConstantsInTraitsRule implements Rule
{

public function __construct(private PhpVersion $phpVersion)
{
}

public function getNodeType(): string
{
return Node\Stmt\ClassConst::class;
Expand All @@ -30,7 +25,7 @@ public function getNodeType(): string
*/
public function processNode(Node $node, Scope $scope): array
{
if ($this->phpVersion->supportsConstantsInTraits()) {
if ($scope->getPhpVersion()->supportsConstantsInTraits()->yes()) {
return [];
}

Expand Down
23 changes: 21 additions & 2 deletions tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

namespace PHPStan\Rules\Arrays;

use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\RequiresPhp;
use const PHP_VERSION_ID;

/**
* @extends RuleTestCase<ArrayUnpackingRule>
Expand All @@ -22,7 +22,6 @@ class ArrayUnpackingRuleTest extends RuleTestCase
protected function getRule(): Rule
{
return new ArrayUnpackingRule(
self::getContainer()->getByType(PhpVersion::class),
new RuleLevelHelper(
self::createReflectionProvider(),
checkNullables: true,
Expand Down Expand Up @@ -117,6 +116,26 @@ public function testRuleDoNotCheckUnions(): void
]);
}

public function testPhpVersionNarrowedScope(): void
{
$this->checkUnions = true;

$errors = [
[
'Array unpacking cannot be used on an array with string keys: array<string, string>',
11,
],
];
if (PHP_VERSION_ID < 80100) {
$errors[] = [
'Array unpacking cannot be used on an array with string keys: array<string, string>',
18,
];
}

$this->analyse([__DIR__ . '/data/array-unpacking-php-versions.php'], $errors);
}

public static function dataRuleOnPHP81(): array
{
return [
Expand Down
19 changes: 19 additions & 0 deletions tests/PHPStan/Rules/Arrays/data/array-unpacking-php-versions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php // lint >= 8.1

namespace ArrayUnpackingPhpVersions;

/**
* @param array<string, string> $a
*/
function doFoo(array $a): void
{
if (PHP_VERSION_ID < 80100) {
$unsupportedInBranch = [...$a];
}

if (PHP_VERSION_ID >= 80100) {
$supportedInBranch = [...$a];
}

$always = [...$a];
}
40 changes: 40 additions & 0 deletions tests/PHPStan/Rules/Cast/UnsetCastRuleConfigPhpTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Cast;

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<UnsetCastRule>
*/
class UnsetCastRuleConfigPhpTest extends RuleTestCase
{

protected function getRule(): Rule
{
return new UnsetCastRule();
}

public function testRulePhpVersionRangeSpanning80(): void
{
$this->analyse([__DIR__ . '/data/unset-cast-php-versions.php'], [
[
'The (unset) cast is no longer supported in PHP 8.0 and later.',
11,
],
[
'The (unset) cast is no longer supported in PHP 8.0 and later.',
14,
],
]);
}

public static function getAdditionalConfigFiles(): array
{
return [
__DIR__ . '/data/unset-cast-php-version.neon',
];
}

}
Loading
Loading