Skip to content

Commit ac40a6f

Browse files
VincentLangletphpstan-bot
authored andcommitted
Add regression test for readonly class property modification via clone()
- New test in tests/PHPStan/Rules/Properties/data/bug-14063.php covering readonly class with clone() property overrides - Tests AccessPropertiesInAssignRule correctly reports "Assign to protected(set) property" when modifying readonly class properties via clone() from outside the declaring class - Tests ReadOnlyPropertyAssignRule does not double-report (defers to AccessPropertiesInAssignRule) - The underlying fix was in BetterReflection 6.70 which correctly sets isProtectedSet() for properties in readonly classes Closes phpstan/phpstan#14063
1 parent b4c5164 commit ac40a6f

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,25 @@ public function testBug13123(): void
207207
$this->analyse([__DIR__ . '/data/bug-13123.php'], []);
208208
}
209209

210+
#[RequiresPhp('>= 8.5')]
211+
public function testBug14063(): void
212+
{
213+
$this->analyse([__DIR__ . '/data/bug-14063.php'], [
214+
[
215+
'Assign to protected(set) property Bug14063\Obj::$value.',
216+
31,
217+
],
218+
[
219+
'Assign to protected(set) property Bug14063\Obj::$value.',
220+
34,
221+
],
222+
[
223+
'Assign to protected(set) property Bug14063\Base::$value.',
224+
38,
225+
],
226+
]);
227+
}
228+
210229
#[RequiresPhp('>= 8.5')]
211230
public function testCloneWith(): void
212231
{

tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,12 @@ public function testCloneWith(): void
180180
$this->analyse([__DIR__ . '/data/readonly-property-assign-clone-with.php'], []);
181181
}
182182

183+
#[RequiresPhp('>= 8.5')]
184+
public function testBug14063(): void
185+
{
186+
// readonly class properties modified via clone() from outside the class
187+
// are reported by AccessPropertiesInAssignRule, not this rule
188+
$this->analyse([__DIR__ . '/data/bug-14063.php'], []);
189+
}
190+
183191
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php // lint >= 8.5
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug14063;
6+
7+
final readonly class Obj
8+
{
9+
public function __construct(public string $value) {}
10+
11+
public function withValue(string $newValue): self
12+
{
13+
return clone($this, ['value' => $newValue]);
14+
}
15+
}
16+
17+
readonly class Base
18+
{
19+
public function __construct(public string $value) {}
20+
}
21+
22+
class Child extends Base
23+
{
24+
public function withValue(string $newValue): self
25+
{
26+
return clone($this, ['value' => $newValue]);
27+
}
28+
}
29+
30+
$obj = new Obj('val');
31+
$newObj = clone($obj, ['value' => 'newVal']);
32+
33+
function test(Obj $obj): void {
34+
clone($obj, ['value' => 'newVal']);
35+
}
36+
37+
function testBase(Base $base): void {
38+
clone($base, ['value' => 'newVal']);
39+
}

0 commit comments

Comments
 (0)