Skip to content

Commit 986cbdf

Browse files
committed
Detect mismatch between readonly/non-readonly class parent
1 parent 795a560 commit 986cbdf

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

src/Rules/Classes/ExistingClassInClassExtendsRule.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,24 @@ public function processNode(Node $node, Scope $scope): array
8181
$reflection->getDisplayName(),
8282
))->build();
8383
}
84+
85+
if ($reflection->isClass()) {
86+
if ($node->isReadonly()) {
87+
if (!$reflection->isReadOnly()) {
88+
$messages[] = RuleErrorBuilder::message(sprintf(
89+
'%s extends non-readonly class %s.',
90+
$currentClassName !== null ? sprintf('Readonly class %s', $currentClassName) : 'Anonymous readonly class',
91+
$reflection->getDisplayName(),
92+
))->nonIgnorable()->build();
93+
}
94+
} elseif ($reflection->isReadOnly()) {
95+
$messages[] = RuleErrorBuilder::message(sprintf(
96+
'%s extends readonly class %s.',
97+
$currentClassName !== null ? sprintf('Non-readonly class %s', $currentClassName) : 'Anonymous non-readonly class',
98+
$reflection->getDisplayName(),
99+
))->nonIgnorable()->build();
100+
}
101+
}
84102
}
85103

86104
return $messages;

tests/PHPStan/Rules/Classes/ExistingClassInClassExtendsRuleTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,30 @@ public function testPhpstanInternalClass(): void
119119
]);
120120
}
121121

122+
public function testReadonly(): void
123+
{
124+
if (PHP_VERSION_ID < 80200) {
125+
$this->markTestSkipped('This test needs PHP 8.2');
126+
}
127+
128+
$this->analyse([__DIR__ . '/data/extends-readonly-class.php'], [
129+
[
130+
'Readonly class ExtendsReadOnlyClass\Foo extends non-readonly class ExtendsReadOnlyClass\Nonreadonly.',
131+
25,
132+
],
133+
[
134+
'Non-readonly class ExtendsReadOnlyClass\Bar extends readonly class ExtendsReadOnlyClass\ReadonlyClass.',
135+
30,
136+
],
137+
[
138+
'Anonymous non-readonly class extends readonly class ExtendsReadOnlyClass\ReadonlyClass.',
139+
35,
140+
],
141+
[
142+
'Anonymous readonly class extends non-readonly class ExtendsReadOnlyClass\Nonreadonly.',
143+
39,
144+
],
145+
]);
146+
}
147+
122148
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php // lint >= 8.2
2+
3+
namespace ExtendsReadOnlyClass;
4+
5+
class Nonreadonly
6+
{
7+
8+
}
9+
10+
readonly class ReadonlyClass
11+
{
12+
13+
}
14+
15+
class Lorem extends Nonreadonly // ok
16+
{
17+
18+
}
19+
20+
readonly class Ipsum extends ReadonlyClass // ok
21+
{
22+
23+
}
24+
25+
readonly class Foo extends Nonreadonly // not ok
26+
{
27+
28+
}
29+
30+
class Bar extends ReadonlyClass // not ok
31+
{
32+
33+
}
34+
35+
new class extends ReadonlyClass { // not ok
36+
37+
};
38+
39+
new readonly class extends Nonreadonly { // not ok
40+
41+
};

0 commit comments

Comments
 (0)