Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Parser/NewAssignedToPropertyVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,29 @@ public function testBug3777(): void
168,
],
]);

$this->analyse([__DIR__ . '/data/bug-3777-static.php'], [
[
'Static property Bug3777Static\Bar::$foo (Bug3777Static\Foo<stdClass>) does not accept Bug3777Static\Fooo<object>.',
58,
],
[
'Static property Bug3777Static\Ipsum::$ipsum (Bug3777Static\Lorem<stdClass, Exception>) does not accept Bug3777Static\Lorem<Exception, stdClass>.',
95,
],
[
'Static property Bug3777Static\Ipsum2::$lorem2 (Bug3777Static\Lorem2<stdClass, Exception>) does not accept Bug3777Static\Lorem2<stdClass, object>.',
129,
],
[
'Static property Bug3777Static\Ipsum2::$ipsum2 (Bug3777Static\Lorem2<stdClass, Exception>) does not accept Bug3777Static\Lorem2<Exception, object>.',
131,
],
[
'Static property Bug3777Static\Ipsum3::$ipsum3 (Bug3777Static\Lorem3<stdClass, Exception>) does not accept Bug3777Static\Lorem3<Exception, stdClass>.',
168,
],
]);
}

public function testAppendendArrayKey(): void
Expand Down Expand Up @@ -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) {
Expand Down
33 changes: 33 additions & 0 deletions tests/PHPStan/Rules/Properties/data/bug-10686.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php // lint >= 7.4

namespace Bug10686;

class Model {}

/**
* @template T of object|array<mixed>
*/
class WeakAnalysingMap
{
/** @var list<T> */
public array $values = [];
}

class Reference
{
/** @var WeakAnalysingMap<Model> */
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);
}
}
172 changes: 172 additions & 0 deletions tests/PHPStan/Rules/Properties/data/bug-3777-static.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
<?php

namespace Bug3777Static;

use function PHPStan\Testing\assertType;

class HelloWorld
{
/**
* @var \SplObjectStorage<\DateTimeImmutable, null>
*/
public static $dates;

public function __construct()
{
static::$dates = new \SplObjectStorage();
assertType('SplObjectStorage<DateTimeImmutable, null>', 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<stdClass>', static::$foo);

static::$fooo = new Fooo();
assertType('Bug3777Static\Fooo<stdClass>', static::$fooo);
}

public function doBar()
{
static::$foo = new Fooo();
assertType('Bug3777Static\Fooo<object>', 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<stdClass, Exception>', static::$lorem);
static::$ipsum = new Lorem(new \Exception(), new \stdClass);
assertType('Bug3777Static\Lorem<Exception, stdClass>', 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<stdClass, object>', static::$lorem2);
static::$ipsum2 = new Lorem2(new \Exception());
assertType('Bug3777Static\Lorem2<Exception, object>', 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<stdClass, Exception>', static::$lorem3);
static::$ipsum3 = new Lorem3(new \Exception(), new \stdClass());
assertType('Bug3777Static\Lorem3<Exception, stdClass>', static::$ipsum3);
}

}
Loading