diff --git a/src/Parser/NewAssignedToPropertyVisitor.php b/src/Parser/NewAssignedToPropertyVisitor.php index 05df87b423..209e72730d 100644 --- a/src/Parser/NewAssignedToPropertyVisitor.php +++ b/src/Parser/NewAssignedToPropertyVisitor.php @@ -13,7 +13,10 @@ final class NewAssignedToPropertyVisitor extends NodeVisitorAbstract public function enterNode(Node $node): ?Node { if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignRef) { - if ($node->var instanceof Node\Expr\PropertyFetch && $node->expr instanceof Node\Expr\New_) { + if ( + ($node->var instanceof Node\Expr\PropertyFetch || $node->var instanceof Node\Expr\StaticPropertyFetch) + && $node->expr instanceof Node\Expr\New_ + ) { $node->expr->setAttribute(self::ATTRIBUTE_NAME, $node->var); } } diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 09f34d1d40..19b6d3b262 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -208,6 +208,29 @@ public function testBug3777(): void 168, ], ]); + + $this->analyse([__DIR__ . '/data/bug-3777-static.php'], [ + [ + 'Static property Bug3777Static\Bar::$foo (Bug3777Static\Foo) does not accept Bug3777Static\Fooo.', + 58, + ], + [ + 'Static property Bug3777Static\Ipsum::$ipsum (Bug3777Static\Lorem) does not accept Bug3777Static\Lorem.', + 95, + ], + [ + 'Static property Bug3777Static\Ipsum2::$lorem2 (Bug3777Static\Lorem2) does not accept Bug3777Static\Lorem2.', + 129, + ], + [ + 'Static property Bug3777Static\Ipsum2::$ipsum2 (Bug3777Static\Lorem2) does not accept Bug3777Static\Lorem2.', + 131, + ], + [ + 'Static property Bug3777Static\Ipsum3::$ipsum3 (Bug3777Static\Lorem3) does not accept Bug3777Static\Lorem3.', + 168, + ], + ]); } public function testAppendendArrayKey(): void @@ -614,6 +637,11 @@ public function testGenericsInCallableInConstructor(): void $this->analyse([__DIR__ . '/data/generics-in-callable-in-constructor.php'], []); } + public function testBug10686(): void + { + $this->analyse([__DIR__ . '/data/bug-10686.php'], []); + } + public function testBug11275(): void { if (PHP_VERSION_ID < 80000) { diff --git a/tests/PHPStan/Rules/Properties/data/bug-10686.php b/tests/PHPStan/Rules/Properties/data/bug-10686.php new file mode 100644 index 0000000000..0d6922d5da --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-10686.php @@ -0,0 +1,33 @@ += 7.4 + +namespace Bug10686; + +class Model {} + +/** + * @template T of object|array + */ +class WeakAnalysingMap +{ + /** @var list */ + public array $values = []; +} + +class Reference +{ + /** @var WeakAnalysingMap */ + private static WeakAnalysingMap $analysingTheirModelMap; + + public function createAnalysingTheirModel(): Model + { + if ((self::$analysingTheirModelMap ?? null) === null) { + self::$analysingTheirModelMap = new WeakAnalysingMap(); + } + + $theirModel = new Model(); + + self::$analysingTheirModelMap->values[] = $theirModel; + + return end(self::$analysingTheirModelMap->values); + } +} diff --git a/tests/PHPStan/Rules/Properties/data/bug-3777-static.php b/tests/PHPStan/Rules/Properties/data/bug-3777-static.php new file mode 100644 index 0000000000..0cc9c7b930 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-3777-static.php @@ -0,0 +1,172 @@ + + */ + public static $dates; + + public function __construct() + { + static::$dates = new \SplObjectStorage(); + assertType('SplObjectStorage', static::$dates); + } +} + +/** @template T of object */ +class Foo +{ + + public function __construct() + { + + } + +} + +/** @template T of object */ +class Fooo +{ + +} + +class Bar +{ + + /** @var Foo<\stdClass> */ + private static $foo; + + /** @var Fooo<\stdClass> */ + private static $fooo; + + public function __construct() + { + static::$foo = new Foo(); + assertType('Bug3777Static\Foo', static::$foo); + + static::$fooo = new Fooo(); + assertType('Bug3777Static\Fooo', static::$fooo); + } + + public function doBar() + { + static::$foo = new Fooo(); + assertType('Bug3777Static\Fooo', static::$foo); + } + +} + +/** + * @template T of object + * @template U of object + */ +class Lorem +{ + + /** + * @param T $t + * @param U $u + */ + public function __construct($t, $u) + { + + } + +} + +class Ipsum +{ + + /** @var Lorem<\stdClass, \Exception> */ + private static $lorem; + + /** @var Lorem<\stdClass, \Exception> */ + private static $ipsum; + + public function __construct() + { + static::$lorem = new Lorem(new \stdClass, new \Exception()); + assertType('Bug3777Static\Lorem', static::$lorem); + static::$ipsum = new Lorem(new \Exception(), new \stdClass); + assertType('Bug3777Static\Lorem', static::$ipsum); + } + +} + +/** + * @template T of object + * @template U of object + */ +class Lorem2 +{ + + /** + * @param T $t + */ + public function __construct($t) + { + + } + +} + +class Ipsum2 +{ + + /** @var Lorem2<\stdClass, \Exception> */ + private static $lorem2; + + /** @var Lorem2<\stdClass, \Exception> */ + private static $ipsum2; + + public function __construct() + { + static::$lorem2 = new Lorem2(new \stdClass); + assertType('Bug3777Static\Lorem2', static::$lorem2); + static::$ipsum2 = new Lorem2(new \Exception()); + assertType('Bug3777Static\Lorem2', static::$ipsum2); + } + +} + +/** + * @template T of object + * @template U of object + */ +class Lorem3 +{ + + /** + * @param T $t + * @param U $u + */ + public function __construct($t, $u) + { + + } + +} + +class Ipsum3 +{ + + /** @var Lorem3<\stdClass, \Exception> */ + private static $lorem3; + + /** @var Lorem3<\stdClass, \Exception> */ + private static $ipsum3; + + public function __construct() + { + static::$lorem3 = new Lorem3(new \stdClass, new \Exception()); + assertType('Bug3777Static\Lorem3', static::$lorem3); + static::$ipsum3 = new Lorem3(new \Exception(), new \stdClass()); + assertType('Bug3777Static\Lorem3', static::$ipsum3); + } + +}