1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Fix inheritance of method params

This commit is contained in:
Matthew Brown 2019-01-11 08:54:10 -05:00
parent 9947bc56f6
commit ff958ef643
3 changed files with 74 additions and 10 deletions

View File

@ -577,25 +577,65 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $codebase->classlike_storage_provider->get($fq_class_name);
$class_storage = $codebase->methods->getClassLikeStorageForMethod($method_id);
$calling_class_storage = $codebase->classlike_storage_provider->get($fq_class_name);
if ($class_storage->template_types) {
$class_template_params = [];
if ($lhs_type_part instanceof TGenericObject) {
$reversed_class_template_types = array_reverse(array_keys($class_storage->template_types));
if ($calling_class_storage->template_types) {
$i = 0;
foreach ($calling_class_storage->template_types as $type_name => $_) {
if (isset($lhs_type_part->type_params[$i])) {
$class_template_params[$type_name] = [
$lhs_type_part->type_params[$i],
$calling_class_storage->name,
];
}
$provided_type_param_count = count($lhs_type_part->type_params);
$i++;
}
}
foreach ($reversed_class_template_types as $i => $type_name) {
if (isset($lhs_type_part->type_params[$provided_type_param_count - 1 - $i])) {
$class_template_params[$type_name] = [
$lhs_type_part->type_params[$provided_type_param_count - 1 - $i],
$fq_class_name,
];
} else {
$e = $calling_class_storage->template_type_extends;
$i = 0;
foreach ($class_storage->template_types as $type_name => $_) {
if (isset($class_template_params[$type_name])) {
$i++;
continue;
}
if ($class_storage !== $calling_class_storage
&& isset($e[strtolower($class_storage->name)][$type_name])
) {
$type_extends = $e[strtolower($class_storage->name)][$type_name];
if ($type_extends instanceof Type\Atomic\TGenericParam) {
if (isset($calling_class_storage->template_types[$type_extends->param_name])) {
$mapped_offset = array_search(
$type_extends->param_name,
array_keys($calling_class_storage->template_types)
);
$class_template_params[$type_name] = [
$lhs_type_part->type_params[(int) $mapped_offset],
$class_storage->name,
];
}
} else {
$class_template_params[$type_name] = [
new Type\Union([$type_extends]),
$class_storage->name,
];
}
}
if (!isset($class_template_params[$type_name])) {
$class_template_params[$type_name] = [Type::getMixed(), null];
}
$i++;
}
} else {
foreach ($class_storage->template_types as $type_name => $_) {

View File

@ -6,6 +6,7 @@ use Psalm\Internal\Analyzer\MethodAnalyzer;
use Psalm\CodeLocation;
use Psalm\Internal\Provider\ClassLikeStorageProvider;
use Psalm\Internal\Provider\FileReferenceProvider;
use Psalm\Storage\ClassLikeStorage;
use Psalm\Storage\FunctionLikeParameter;
use Psalm\Storage\MethodStorage;
use Psalm\Type;
@ -595,6 +596,28 @@ class Methods
return $storage;
}
/**
* @param string $method_id
*
* @return ClassLikeStorage
*/
public function getClassLikeStorageForMethod($method_id)
{
$declaring_method_id = $this->getDeclaringMethodId($method_id);
if (!$declaring_method_id) {
if (CallMap::inCallMap($method_id)) {
$declaring_method_id = $method_id;
} else {
throw new \UnexpectedValueException('$storage should not be null for ' . $method_id);
}
}
list($declaring_fq_class_name) = explode('::', $declaring_method_id);
return $this->classlike_storage_provider->get($declaring_fq_class_name);
}
/**
* @param string $method_id
*

View File

@ -451,6 +451,7 @@ class ArrayObject implements IteratorAggregate, Traversable, ArrayAccess, Serial
* over Arrays and Objects.
* @link http://php.net/manual/en/class.arrayiterator.php
*
* @template TKey as array-key
* @template TValue
*/
class ArrayIterator implements SeekableIterator, ArrayAccess, Serializable, Countable {