mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Fix #3857 - allow reconciliation on magic properties
This commit is contained in:
parent
f596b17da6
commit
eaae243905
@ -696,43 +696,15 @@ class Reconciler
|
||||
$class_property_type = Type::getMixed();
|
||||
}
|
||||
} else {
|
||||
$property_id = $existing_key_type_part->value . '::$' . $property_name;
|
||||
$class_property_type = self::getPropertyType(
|
||||
$codebase,
|
||||
$existing_key_type_part->value,
|
||||
$property_name
|
||||
);
|
||||
|
||||
if (!$codebase->properties->propertyExists($property_id, true)) {
|
||||
if (!$class_property_type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$declaring_property_class = $codebase->properties->getDeclaringClassForProperty(
|
||||
$property_id,
|
||||
true
|
||||
);
|
||||
|
||||
if ($declaring_property_class === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_property_type = $codebase->properties->getPropertyType(
|
||||
$property_id,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
$declaring_class_storage = $codebase->classlike_storage_provider->get(
|
||||
$declaring_property_class
|
||||
);
|
||||
|
||||
if ($class_property_type) {
|
||||
$class_property_type = \Psalm\Internal\Type\TypeExpander::expandUnion(
|
||||
$codebase,
|
||||
clone $class_property_type,
|
||||
$declaring_class_storage->name,
|
||||
$declaring_class_storage->name,
|
||||
null
|
||||
);
|
||||
} else {
|
||||
$class_property_type = Type::getMixed();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -775,6 +747,58 @@ class Reconciler
|
||||
return $existing_keys[$base_key];
|
||||
}
|
||||
|
||||
private static function getPropertyType(
|
||||
Codebase $codebase,
|
||||
string $fq_class_name,
|
||||
string $property_name
|
||||
) : ?Type\Union {
|
||||
$property_id = $fq_class_name . '::$' . $property_name;
|
||||
|
||||
if (!$codebase->properties->propertyExists($property_id, true)) {
|
||||
$declaring_class_storage = $codebase->classlike_storage_provider->get(
|
||||
$fq_class_name
|
||||
);
|
||||
|
||||
if (isset($declaring_class_storage->pseudo_property_get_types['$' . $property_name])) {
|
||||
return clone $declaring_class_storage->pseudo_property_get_types['$' . $property_name];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$declaring_property_class = $codebase->properties->getDeclaringClassForProperty(
|
||||
$property_id,
|
||||
true
|
||||
);
|
||||
|
||||
if ($declaring_property_class === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_property_type = $codebase->properties->getPropertyType(
|
||||
$property_id,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
$declaring_class_storage = $codebase->classlike_storage_provider->get(
|
||||
$declaring_property_class
|
||||
);
|
||||
|
||||
if ($class_property_type) {
|
||||
return \Psalm\Internal\Type\TypeExpander::expandUnion(
|
||||
$codebase,
|
||||
clone $class_property_type,
|
||||
$declaring_class_storage->name,
|
||||
$declaring_class_storage->name,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return Type::getMixed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $old_var_type_string
|
||||
|
@ -659,6 +659,44 @@ class MagicPropertyTest extends TestCase
|
||||
$record->password;
|
||||
$record->last_login_at = new DateTimeImmutable("now");'
|
||||
],
|
||||
'reconcileMagicProperties' => [
|
||||
'<?php
|
||||
/**
|
||||
* @property string|null $a A
|
||||
* @property string|null $b B
|
||||
*/
|
||||
class Foo
|
||||
{
|
||||
private array $props = [];
|
||||
|
||||
public function __construct() {
|
||||
$this->props["a"] = "hello";
|
||||
$this->props["b"] = "goodbye";
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-mutation-free
|
||||
*/
|
||||
public function __get(string $prop){
|
||||
return $this->props[$prop] ?? null;
|
||||
}
|
||||
|
||||
/** @param mixed $b */
|
||||
public function __set(string $a, $b){
|
||||
$this->props[$a] = $b;
|
||||
}
|
||||
|
||||
public function bar(): string {
|
||||
if (is_null($this->a) || is_null($this->b)) {
|
||||
|
||||
} else {
|
||||
return $this->b;
|
||||
}
|
||||
|
||||
return "hello";
|
||||
}
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user