Skip to content

Commit 55a3444

Browse files
committed
Fix overriding trait properties in PHPDocs
1 parent 37c29d5 commit 55a3444

6 files changed

Lines changed: 132 additions & 2 deletions

File tree

src/Reflection/Php/PhpClassReflectionExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ private function createProperty(
199199
throw new \PHPStan\ShouldNotHappenException();
200200
}
201201

202-
if ($hierarchyDistances[$annotationProperty->getDeclaringClass()->getName()] < $hierarchyDistances[$propertyReflection->getDeclaringClass()->getName()]) {
202+
if ($hierarchyDistances[$annotationProperty->getDeclaringClass()->getName()] <= $hierarchyDistances[$propertyReflection->getDeclaringClass()->getName()]) {
203203
return $annotationProperty;
204204
}
205205
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9834,6 +9834,11 @@ public function dataArrayShapeKeysStrings(): array
98349834
return $this->gatherAssertTypes(__DIR__ . '/data/array-shapes-keys-strings.php');
98359835
}
98369836

9837+
public function dataBug1216(): array
9838+
{
9839+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-1216.php');
9840+
}
9841+
98379842
/**
98389843
* @dataProvider dataBug2574
98399844
* @dataProvider dataBug2577
@@ -9871,6 +9876,7 @@ public function dataArrayShapeKeysStrings(): array
98719876
* @dataProvider dataIsNumeric
98729877
* @dataProvider dataBug3142
98739878
* @dataProvider dataArrayShapeKeysStrings
9879+
* @dataProvider dataBug1216
98749880
* @param ConstantStringType $expectedType
98759881
* @param Type $actualType
98769882
*/
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace Bug1216;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
abstract class Foo
8+
{
9+
/**
10+
* @var int
11+
*/
12+
protected $foo;
13+
}
14+
15+
trait Bar
16+
{
17+
/**
18+
* @var int
19+
*/
20+
protected $bar;
21+
22+
protected $untypedBar;
23+
}
24+
25+
/**
26+
* @property string $foo
27+
* @property string $bar
28+
* @property string $untypedBar
29+
*/
30+
class Baz extends Foo
31+
{
32+
33+
public function __construct()
34+
{
35+
assertType('string', $this->foo);
36+
assertType('string', $this->bar);
37+
assertType('string', $this->untypedBar);
38+
}
39+
40+
}
41+
42+
function (Baz $baz): void {
43+
assertType('string', $baz->foo);
44+
assertType('string', $baz->bar);
45+
assertType('string', $baz->untypedBar);
46+
};

tests/PHPStan/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public function dataProperties(): array
100100
],
101101
'conflictingAnnotationProperty' => [
102102
'class' => \AnnotationsProperties\Bar::class,
103-
'type' => \AnnotationsProperties\Bar::class,
103+
'type' => \AnnotationsProperties\Foo::class,
104104
'writable' => true,
105105
'readable' => true,
106106
],

tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,18 @@ public function testTypesAssignedToProperties(): void
7777
]);
7878
}
7979

80+
public function testBug1216(): void
81+
{
82+
$this->analyse([__DIR__ . '/data/bug-1216.php'], [
83+
[
84+
'Property Bug1216PropertyTest\Baz::$untypedBar (string) does not accept int.',
85+
35,
86+
],
87+
[
88+
'Property Bug1216PropertyTest\Dummy::$foo (Exception) does not accept stdClass.',
89+
59,
90+
],
91+
]);
92+
}
93+
8094
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace Bug1216PropertyTest;
4+
5+
abstract class Foo
6+
{
7+
/**
8+
* @var int
9+
*/
10+
protected $foo;
11+
}
12+
13+
trait Bar
14+
{
15+
/**
16+
* @var int
17+
*/
18+
protected $bar;
19+
20+
protected $untypedBar;
21+
}
22+
23+
/**
24+
* @property string $foo
25+
* @property string $bar
26+
* @property string $untypedBar
27+
*/
28+
class Baz extends Foo
29+
{
30+
31+
public function __construct()
32+
{
33+
$this->foo = 'foo'; // OK
34+
$this->bar = 'bar'; // OK
35+
$this->untypedBar = 123; // error
36+
}
37+
38+
}
39+
40+
trait DecoratorTrait
41+
{
42+
43+
/** @var \stdClass */
44+
public $foo;
45+
46+
}
47+
48+
/**
49+
* @property \Exception $foo
50+
*/
51+
class Dummy
52+
{
53+
54+
use DecoratorTrait;
55+
56+
}
57+
58+
function (Dummy $dummy): void {
59+
$dummy->foo = new \stdClass();
60+
};
61+
62+
function (Dummy $dummy): void {
63+
$dummy->foo = new \Exception();
64+
};

0 commit comments

Comments
 (0)