Skip to content

Commit 60e575a

Browse files
committed
Invoke PropertyAssignNode in short set property hook
1 parent 325e624 commit 60e575a

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4698,6 +4698,7 @@ private function processPropertyHooks(
46984698

46994699
if ($hook->body instanceof Expr) {
47004700
$this->processExprNode($stmt, $hook->body, $hookScope, $nodeCallback, ExpressionContext::createTopLevel());
4701+
$nodeCallback(new PropertyAssignNode(new PropertyFetch(new Variable('this'), $propertyName, $hook->body->getAttributes()), $hook->body, false), $hookScope);
47014702
} elseif (is_array($hook->body)) {
47024703
$this->processStmtNodes($stmt, $hook->body, $hookScope, $nodeCallback, StatementContext::createTopLevel());
47034704
}

tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,4 +688,38 @@ public function testBug12131(): void
688688
]);
689689
}
690690

691+
public function testShortBodySetHook(): void
692+
{
693+
if (PHP_VERSION_ID < 80400) {
694+
$this->markTestSkipped('Test requires PHP 8.4.');
695+
}
696+
697+
$this->checkExplicitMixed = true;
698+
$this->analyse([__DIR__ . '/data/short-set-property-hook-assign.php'], [
699+
[
700+
'Property ShortSetPropertyHookAssign\Foo::$i (int) does not accept string.',
701+
9,
702+
],
703+
[
704+
'Property ShortSetPropertyHookAssign\Foo::$s (non-empty-string) does not accept \'\'.',
705+
18,
706+
],
707+
[
708+
'Property ShortSetPropertyHookAssign\GenericFoo<T of ShortSetPropertyHookAssign\Foo>::$a (T of ShortSetPropertyHookAssign\Foo) does not accept ShortSetPropertyHookAssign\Foo.',
709+
36,
710+
'Type ShortSetPropertyHookAssign\Foo is not always the same as T. It breaks the contract for some argument types, typically subtypes.',
711+
],
712+
[
713+
'Property ShortSetPropertyHookAssign\GenericFoo<T of ShortSetPropertyHookAssign\Foo>::$b (T of ShortSetPropertyHookAssign\Foo) does not accept ShortSetPropertyHookAssign\Foo.',
714+
50,
715+
'Type ShortSetPropertyHookAssign\Foo is not always the same as T. It breaks the contract for some argument types, typically subtypes.',
716+
],
717+
[
718+
'Property ShortSetPropertyHookAssign\GenericFoo<T of ShortSetPropertyHookAssign\Foo>::$c (T of ShortSetPropertyHookAssign\Foo) does not accept ShortSetPropertyHookAssign\Foo.',
719+
59,
720+
'Type ShortSetPropertyHookAssign\Foo is not always the same as T. It breaks the contract for some argument types, typically subtypes.',
721+
],
722+
]);
723+
}
724+
691725
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php // lint >= 8.4
2+
3+
namespace ShortSetPropertyHookAssign;
4+
5+
class Foo
6+
{
7+
8+
public int $i {
9+
set => 'foo';
10+
}
11+
12+
public int $i2 {
13+
set => 1;
14+
}
15+
16+
/** @var non-empty-string */
17+
public string $s {
18+
set => '';
19+
}
20+
21+
/** @var non-empty-string */
22+
public string $s2 {
23+
set => 'foo';
24+
}
25+
26+
}
27+
28+
/**
29+
* @template T of Foo
30+
*/
31+
class GenericFoo
32+
{
33+
34+
/** @var T */
35+
public Foo $a {
36+
set => new Foo();
37+
}
38+
39+
/** @var T */
40+
public Foo $a2 {
41+
set => $this->a2;
42+
}
43+
44+
/**
45+
* @param T $c
46+
*/
47+
public function __construct(
48+
/** @var T */
49+
public Foo $b {
50+
set => new Foo();
51+
},
52+
53+
/** @var T */
54+
public Foo $b2 {
55+
set => $this->b2;
56+
},
57+
58+
public Foo $c {
59+
set => new Foo();
60+
},
61+
62+
public Foo $c2 {
63+
set => $this->c2;
64+
}
65+
)
66+
{
67+
}
68+
69+
}

0 commit comments

Comments
 (0)