Skip to content

Commit c8009bd

Browse files
committed
detect override of deprecated property
1 parent e7fe22b commit c8009bd

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed

rules.neon

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ services:
1515
class: PHPStan\Rules\Deprecations\DefaultDeprecatedScopeResolver
1616
tags:
1717
- phpstan.deprecations.deprecatedScopeResolver
18+
-
19+
class: PHPStan\Rules\Deprecations\OverrideDeprecatedPropertyRule
1820

1921
rules:
2022
- PHPStan\Rules\Deprecations\AccessDeprecatedPropertyRule
@@ -33,3 +35,7 @@ rules:
3335
- PHPStan\Rules\Deprecations\TypeHintDeprecatedInFunctionSignatureRule
3436
- PHPStan\Rules\Deprecations\UsageOfDeprecatedCastRule
3537
- PHPStan\Rules\Deprecations\UsageOfDeprecatedTraitRule
38+
39+
conditionalTags:
40+
PHPStan\Rules\Deprecations\OverrideDeprecatedPropertyRule:
41+
phpstan.rules.rule: %featureToggles.bleedingEdge%
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Deprecations;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Stmt\Property;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Rules\RuleErrorBuilder;
10+
use function sprintf;
11+
12+
/**
13+
* @implements Rule<Property>
14+
*/
15+
class OverrideDeprecatedPropertyRule implements Rule
16+
{
17+
18+
/** @var DeprecatedScopeHelper */
19+
private $deprecatedScopeHelper;
20+
21+
public function __construct(DeprecatedScopeHelper $deprecatedScopeHelper)
22+
{
23+
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
24+
}
25+
26+
public function getNodeType(): string
27+
{
28+
return Property::class;
29+
}
30+
31+
public function processNode(Node $node, Scope $scope): array
32+
{
33+
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
34+
return [];
35+
}
36+
37+
if (!$scope->isInClass()) {
38+
return [];
39+
}
40+
41+
if ($node->isPrivate()) {
42+
return [];
43+
}
44+
45+
$class = $scope->getClassReflection();
46+
47+
$parents = $class->getParents();
48+
49+
$propertyName = (string) $node->props[0]->name;
50+
51+
$property = $class->getProperty($propertyName, $scope);
52+
53+
if ($property->isDeprecated()->no()) {
54+
return [];
55+
}
56+
57+
foreach ($parents as $parent) {
58+
if (!$parent->hasProperty($propertyName)) {
59+
continue;
60+
}
61+
62+
$parentProperty = $parent->getProperty($propertyName, $scope);
63+
64+
if (!$parentProperty->isDeprecated()->yes()) {
65+
return [];
66+
}
67+
68+
return [RuleErrorBuilder::message(sprintf(
69+
'Class %s overrides deprecated property %s of class %s.',
70+
$class->getName(),
71+
$propertyName,
72+
$parent->getName()
73+
))->identifier('property.deprecated')->build()];
74+
}
75+
76+
return [];
77+
}
78+
79+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Deprecations;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Testing\RuleTestCase;
7+
8+
/**
9+
* @extends RuleTestCase<OverrideDeprecatedPropertyRule>
10+
*/
11+
class OverrideDeprecatedPropertyRuleTest extends RuleTestCase
12+
{
13+
14+
protected function getRule(): Rule
15+
{
16+
return new OverrideDeprecatedPropertyRule(new DeprecatedScopeHelper([new DefaultDeprecatedScopeResolver()]));
17+
}
18+
19+
public function testDeprecatedPropertyOverride(): void
20+
{
21+
$this->analyse(
22+
[__DIR__ . '/data/override-deprecated-property.php'],
23+
[
24+
[
25+
'Class OverrideDeprecatedProperty\Child overrides deprecated property deprecatedProperty of class OverrideDeprecatedProperty\Ancestor.',
26+
25,
27+
],
28+
]
29+
);
30+
}
31+
32+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace OverrideDeprecatedProperty;
4+
5+
class Ancestor
6+
{
7+
/**
8+
* @deprecated
9+
*/
10+
public $deprecatedProperty;
11+
12+
/**
13+
* @deprecated
14+
*/
15+
private $privateDeprecatedProperty;
16+
17+
/**
18+
* @deprecated
19+
*/
20+
public $explicitlyNotDeprecated;
21+
}
22+
23+
class Child extends Ancestor
24+
{
25+
public $deprecatedProperty;
26+
27+
private $privateDeprecatedProperty;
28+
29+
/**
30+
* @not-deprecated
31+
*/
32+
public $explicitlyNotDeprecated;
33+
}
34+
35+
class GrandChild extends Child
36+
{
37+
public $explicitlyNotDeprecated;
38+
}

0 commit comments

Comments
 (0)