1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix handling of inherited method call

This commit is contained in:
Matthew Brown 2019-06-24 23:42:36 -04:00
parent c0b86bd40d
commit 9d998bf3ac
2 changed files with 67 additions and 8 deletions

View File

@ -711,19 +711,28 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
&& $stmt->class instanceof PhpParser\Node\Name
&& $stmt->class->parts === ['parent']
&& $context->self
&& ($self_class_storage = $codebase->classlike_storage_provider->get($context->self))
&& $self_class_storage->template_type_extends
) {
$self_class_storage = $codebase->classlike_storage_provider->get($context->self);
$extended_types = $self_class_storage->template_type_extends[$fq_class_name] ?? [];
if ($extended_types) {
foreach ($self_class_storage->template_type_extends as $template_fq_class_name => $extended_types) {
foreach ($extended_types as $type_key => $extended_type) {
if (!is_string($type_key)) {
continue;
}
if (isset($found_generic_params[$type_key][$fq_class_name])) {
$found_generic_params[$type_key][$fq_class_name][0] = clone $extended_type;
if (isset($found_generic_params[$type_key][$template_fq_class_name])) {
$found_generic_params[$type_key][$template_fq_class_name][0] = clone $extended_type;
continue;
}
foreach ($extended_type->getTypes() as $t) {
if ($t instanceof Type\Atomic\TTemplateParam
&& isset($found_generic_params[$t->param_name][$t->defining_class ?: ''])
) {
$found_generic_params[$type_key][$template_fq_class_name] = [
$found_generic_params[$t->param_name][$t->defining_class ?: ''][0]
];
}
}
}
}

View File

@ -650,7 +650,7 @@ class TemplateExtendsTest extends TestCase
/** @param class-string<T> $class */
public function __construct(string $class) {
$this->class = $class;
$this->class = $class;
}
}
@ -2120,6 +2120,56 @@ class TemplateExtendsTest extends TestCase
return new C(new $t);
}',
],
'extendWithExplicitOverriddenTemplatedSignatureHopped' => [
'<?php
class Obj {}
/**
* @template T1
*/
class Container1 {
/** @var T1 */
private $t1;
/** @param T1 $t1 */
public function __construct($t1) {
$this->t1 = $t1;
}
/**
* @return T1
*/
public function getValue()
{
return $this->t1;
}
}
/**
* @template T2
* @template-extends Container1<T2>
*/
class Container2 extends Container1 {}
/**
* @template T3 as Obj
* @template-extends Container2<T3>
*/
class Container3 extends Container2 {
/** @param T3 $t3 */
public function __construct($t3) {
Container1::__construct($t3);
}
/**
* @return T3
*/
public function getValue()
{
return parent::getValue();
}
}',
],
];
}