Skip to content

Commit a5dcb3a

Browse files
committed
@immutable class cannot be passed by-ref
1 parent da73771 commit a5dcb3a

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

src/Rules/FunctionCallParametersCheck.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,21 @@ public function check(
409409
if ($nativePropertyReflection === null) {
410410
continue;
411411
}
412-
if (!$nativePropertyReflection->isReadOnly()) {
413-
continue;
414-
}
415412

416-
if ($nativePropertyReflection->isStatic()) {
417-
$propertyDescription = sprintf('static readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName());
413+
if ($nativePropertyReflection->isReadOnly()) {
414+
if ($nativePropertyReflection->isStatic()) {
415+
$propertyDescription = sprintf('static readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName());
416+
} else {
417+
$propertyDescription = sprintf('readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName());
418+
}
419+
} elseif ($nativePropertyReflection->isReadOnlyByPhpDoc()) {
420+
if ($nativePropertyReflection->isStatic()) {
421+
$propertyDescription = sprintf('static @readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName());
422+
} else {
423+
$propertyDescription = sprintf('@readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName());
424+
}
418425
} else {
419-
$propertyDescription = sprintf('readonly property %s::$%s', $propertyReflection->getDeclaringClass()->getDisplayName(), $propertyReflection->getName());
426+
continue;
420427
}
421428

422429
$errors[] = RuleErrorBuilder::message(sprintf(

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,4 +1982,22 @@ public function testBug3107(): void
19821982
$this->analyse([__DIR__ . '/data/bug-3107.php'], []);
19831983
}
19841984

1985+
public function testBug12676(): void
1986+
{
1987+
$this->analyse([__DIR__ . '/data/bug-12676.php'], [
1988+
[
1989+
'Parameter #1 $array is passed by reference so it does not accept @readonly property Bug12676\A::$a.',
1990+
15,
1991+
],
1992+
[
1993+
'Parameter #1 $array is passed by reference so it does not accept @readonly property Bug12676\B::$readonlyArr.',
1994+
25,
1995+
],
1996+
[
1997+
'Parameter #1 $array is passed by reference so it does not accept static @readonly property Bug12676\C::$readonlyArr.',
1998+
35,
1999+
],
2000+
]);
2001+
}
2002+
19852003
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Bug12676;
4+
5+
/**
6+
* @immutable
7+
*/
8+
class A {
9+
10+
/** @var array<string, int> */
11+
public array $a;
12+
13+
public function __construct() {
14+
$this->a = ['b' => 2, 'a' => 1];
15+
ksort($this->a);
16+
}
17+
}
18+
19+
class B {
20+
/** @readonly */
21+
public array $readonlyArr;
22+
23+
public function __construct() {
24+
$this->readonlyArr = ['b' => 2, 'a' => 1];
25+
ksort($this->readonlyArr);
26+
}
27+
}
28+
29+
class C {
30+
/** @readonly */
31+
static public array $readonlyArr;
32+
33+
public function __construct() {
34+
self::$readonlyArr = ['b' => 2, 'a' => 1];
35+
ksort(self::$readonlyArr);
36+
}
37+
}

0 commit comments

Comments
 (0)