mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +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();
|
$class_property_type = Type::getMixed();
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
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 {
|
} else {
|
||||||
@ -775,6 +747,58 @@ class Reconciler
|
|||||||
return $existing_keys[$base_key];
|
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 $key
|
||||||
* @param string $old_var_type_string
|
* @param string $old_var_type_string
|
||||||
|
@ -659,6 +659,44 @@ class MagicPropertyTest extends TestCase
|
|||||||
$record->password;
|
$record->password;
|
||||||
$record->last_login_at = new DateTimeImmutable("now");'
|
$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