Skip to content

Commit 25bda88

Browse files
committed
Resolve #12999
1 parent 64512a5 commit 25bda88

File tree

5 files changed

+28
-14
lines changed

5 files changed

+28
-14
lines changed

src/Reflection/Php/PhpClassReflectionExtension.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ private function createProperty(
218218
$types[] = $value;
219219
}
220220

221-
return new PhpPropertyReflection($declaringClassReflection, null, null, TypeCombinator::union(...$types), $classReflection->getNativeReflection()->getProperty($propertyName), null, null, null, false, false, false, false, []);
221+
return new PhpPropertyReflection($declaringClassReflection, null, null, TypeCombinator::union(...$types), $classReflection->getNativeReflection()->getProperty($propertyName), null, null, null, false, false, false, false, [], false);
222222
}
223223
}
224224

@@ -227,6 +227,7 @@ private function createProperty(
227227
$isDeprecated = $deprecation !== null;
228228
$isInternal = false;
229229
$isReadOnlyByPhpDoc = $classReflection->isImmutable();
230+
$isFinalByPhpDoc = $classReflection->isFinal();
230231
$isAllowedPrivateMutation = false;
231232

232233
if (
@@ -308,6 +309,7 @@ private function createProperty(
308309
}
309310
$isInternal = $resolvedPhpDoc->isInternal();
310311
$isReadOnlyByPhpDoc = $isReadOnlyByPhpDoc || $resolvedPhpDoc->isReadOnly();
312+
$isFinalByPhpDoc = $isFinalByPhpDoc || $resolvedPhpDoc->isFinal();
311313
$isAllowedPrivateMutation = $resolvedPhpDoc->isAllowedPrivateMutation();
312314
}
313315

@@ -435,6 +437,7 @@ private function createProperty(
435437
$isReadOnlyByPhpDoc,
436438
$isAllowedPrivateMutation,
437439
$this->attributeReflectionFactory->fromNativeReflection($propertyReflection->getAttributes(), InitializerExprContext::fromClass($declaringClassReflection->getName(), $declaringClassReflection->getFileName())),
440+
$isFinalByPhpDoc,
438441
);
439442
}
440443

src/Reflection/Php/PhpPropertyReflection.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function __construct(
4444
private bool $isReadOnlyByPhpDoc,
4545
private bool $isAllowedPrivateMutation,
4646
private array $attributes,
47+
private bool $isFinalByPhpDoc,
4748
)
4849
{
4950
}
@@ -98,6 +99,11 @@ public function isReadOnlyByPhpDoc(): bool
9899
return $this->isReadOnlyByPhpDoc;
99100
}
100101

102+
public function isFinalByPhpDoc(): bool
103+
{
104+
return $this->isFinalByPhpDoc;
105+
}
106+
101107
public function getReadableType(): Type
102108
{
103109
if ($this->type === null) {

src/Rules/Variables/UnsetRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public function processNode(Node $node, Scope $scope): array
8282
if (
8383
!$propertyReflection->isPrivate()
8484
&& !$propertyReflection->isFinal()->yes()
85+
&& !$propertyReflection->isFinalByPhpDoc()
8586
&& !$propertyReflection->getDeclaringClass()->isFinal()
8687
) {
8788
$errors[] = RuleErrorBuilder::message(

tests/PHPStan/Rules/Variables/UnsetRuleTest.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -167,55 +167,55 @@ public function testUnsetHookedProperty(): void
167167
],
168168
[
169169
'Cannot unset property UnsetHookedProperty\NonFinalClass::$publicProperty because it might have hooks in a subclass.',
170-
13,
170+
14,
171171
],
172172
[
173173
'Cannot unset property UnsetHookedProperty\ContainerClass::$finalClass because it might have hooks in a subclass.',
174-
83,
174+
86,
175175
],
176176
[
177177
'Cannot unset property UnsetHookedProperty\ContainerClass::$nonFinalClass because it might have hooks in a subclass.',
178-
87,
178+
91,
179179
],
180180
[
181181
'Cannot unset hooked UnsetHookedProperty\Foo::$iii property.',
182-
89,
182+
93,
183183
],
184184
[
185185
'Cannot unset property UnsetHookedProperty\ContainerClass::$foo because it might have hooks in a subclass.',
186-
90,
186+
94,
187187
],
188188
[
189189
'Cannot unset hooked UnsetHookedProperty\User::$name property.',
190-
92,
190+
96,
191191
],
192192
[
193193
'Cannot unset hooked UnsetHookedProperty\User::$fullName property.',
194-
93,
194+
97,
195195
],
196196
[
197197
'Cannot unset property UnsetHookedProperty\ContainerClass::$user because it might have hooks in a subclass.',
198-
94,
198+
98,
199199
],
200200
[
201201
'Cannot unset hooked UnsetHookedProperty\User::$name property.',
202-
96,
202+
100,
203203
],
204204
[
205205
'Cannot unset hooked UnsetHookedProperty\User::$name property.',
206-
97,
206+
101,
207207
],
208208
[
209209
'Cannot unset hooked UnsetHookedProperty\User::$fullName property.',
210-
98,
210+
102,
211211
],
212212
[
213213
'Cannot unset hooked UnsetHookedProperty\User::$fullName property.',
214-
99,
214+
103,
215215
],
216216
[
217217
'Cannot unset property UnsetHookedProperty\ContainerClass::$arrayOfUsers because it might have hooks in a subclass.',
218-
100,
218+
104,
219219
],
220220
]);
221221
}

tests/PHPStan/Rules/Variables/data/unset-hooked-property.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ function doUnset(Foo $foo, User $user, NonFinalClass $nonFinalClass, FinalClass
99
unset($foo->ii);
1010
unset($foo->iii);
1111

12+
unset($nonFinalClass->publicAnnotatedFinalProperty);
1213
unset($nonFinalClass->publicFinalProperty);
1314
unset($nonFinalClass->publicProperty);
1415

@@ -49,6 +50,8 @@ class NonFinalClass {
4950
private string $privateProperty;
5051
public string $publicProperty;
5152
final public string $publicFinalProperty;
53+
/** @final */
54+
public string $publicAnnotatedFinalProperty;
5255

5356
function doFoo() {
5457
unset($this->privateProperty);
@@ -82,6 +85,7 @@ function dooNestedUnset(ContainerClass $containerClass) {
8285
unset($containerClass->finalClass->publicProperty);
8386
unset($containerClass->finalClass);
8487

88+
unset($containerClass->nonFinalClass->publicAnnotatedFinalProperty);
8589
unset($containerClass->nonFinalClass->publicFinalProperty);
8690
unset($containerClass->nonFinalClass->publicProperty);
8791
unset($containerClass->nonFinalClass);

0 commit comments

Comments
 (0)