mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Add better support for inheriting docblocks
This commit is contained in:
parent
7cf8c362f0
commit
9c4599a0f0
@ -1585,7 +1585,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
: [];
|
||||
|
||||
if ($actual_method_storage->overridden_downstream) {
|
||||
$overridden_method_ids[] = 'overridden::downstream';
|
||||
$overridden_method_ids['overridden::downstream'] = 'overridden::downstream';
|
||||
}
|
||||
|
||||
if (!$return_type && isset($class_storage->interface_method_ids[strtolower($stmt->name->name)])) {
|
||||
|
@ -264,13 +264,11 @@ class TypeAnalyzer
|
||||
*
|
||||
* @param Type\Union $input_type
|
||||
* @param Type\Union $container_type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSimplyContainedBy(
|
||||
Type\Union $input_type,
|
||||
Type\Union $container_type
|
||||
) {
|
||||
) : bool {
|
||||
if ($input_type->getId() === $container_type->getId()) {
|
||||
return true;
|
||||
}
|
||||
@ -285,10 +283,26 @@ class TypeAnalyzer
|
||||
$container_type_not_null = clone $container_type;
|
||||
$container_type_not_null->removeType('null');
|
||||
|
||||
return !array_diff_key(
|
||||
$input_type_not_null->getTypes(),
|
||||
$container_type_not_null->getTypes()
|
||||
);
|
||||
foreach ($input_type->getTypes() as $input_key => $input_type_part) {
|
||||
foreach ($container_type->getTypes() as $container_key => $container_type_part) {
|
||||
if (get_class($container_type_part) === TNamedObject::class
|
||||
&& $input_type_part instanceof TNamedObject
|
||||
&& $input_type_part->value === $container_type_part->value
|
||||
) {
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if ($input_key === $container_key) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -554,7 +554,7 @@ class Methods
|
||||
$class_storage = $this->classlike_storage_provider->get($fq_class_name);
|
||||
|
||||
if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) {
|
||||
$appearing_method_id = $class_storage->overridden_method_ids[$method_name][0];
|
||||
$appearing_method_id = reset($class_storage->overridden_method_ids[$method_name]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -757,7 +757,7 @@ class Methods
|
||||
}
|
||||
|
||||
if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) {
|
||||
return $class_storage->overridden_method_ids[$method_name][0];
|
||||
return reset($class_storage->overridden_method_ids[$method_name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,13 +293,13 @@ class Populator
|
||||
&& $method_storage->inheritdoc
|
||||
&& $declaring_method_storage->throws
|
||||
) {
|
||||
$method_storage->throws = $declaring_method_storage->throws;
|
||||
}
|
||||
|
||||
if (count($storage->overridden_method_ids[$method_name]) === 1
|
||||
&& $method_storage->signature_return_type
|
||||
&& !$method_storage->signature_return_type->isVoid()
|
||||
&& $method_storage->return_type === $method_storage->signature_return_type
|
||||
&& ($method_storage->return_type === $method_storage->signature_return_type
|
||||
|| $method_storage->inherited_return_type)
|
||||
) {
|
||||
if (isset($declaring_class_storage->methods[$method_name])) {
|
||||
$declaring_method_storage = $declaring_class_storage->methods[$method_name];
|
||||
@ -768,7 +768,7 @@ class Populator
|
||||
}
|
||||
}
|
||||
}
|
||||
$storage->overridden_method_ids[$method_name][] = $interface_method_ids[0];
|
||||
$storage->overridden_method_ids[$method_name][$interface_method_ids[0]] = $interface_method_ids[0];
|
||||
} else {
|
||||
$storage->interface_method_ids[$method_name] = $interface_method_ids;
|
||||
}
|
||||
@ -1006,10 +1006,10 @@ class Populator
|
||||
if (isset($declaring_class_storage->methods[$method_name])
|
||||
&& $declaring_class_storage->methods[$method_name]->abstract
|
||||
) {
|
||||
$storage->overridden_method_ids[$method_name][] = $declaring_method_id;
|
||||
$storage->overridden_method_ids[$method_name][$declaring_method_id] = $declaring_method_id;
|
||||
}
|
||||
} else {
|
||||
$storage->overridden_method_ids[$method_name][] = $declaring_method_id;
|
||||
$storage->overridden_method_ids[$method_name][$declaring_method_id] = $declaring_method_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,7 @@ class Reflection
|
||||
$storage->declaring_method_ids[$method_name] = $declaring_method_id;
|
||||
$storage->inheritable_method_ids[$method_name] = $declaring_method_id;
|
||||
|
||||
$storage->overridden_method_ids[$method_name][] = $declaring_method_id;
|
||||
$storage->overridden_method_ids[$method_name][$declaring_method_id] = $declaring_method_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ class ClassLikeStorage
|
||||
public $appearing_method_ids = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<string>>
|
||||
* @var array<string, array<string, string>>
|
||||
*/
|
||||
public $overridden_method_ids = [];
|
||||
|
||||
|
@ -1975,6 +1975,21 @@ class TemplateExtendsTest extends TestCase
|
||||
|
||||
echo (new F())->getValue();'
|
||||
],
|
||||
'lessSpecificNonGenericReturnType' => [
|
||||
'<?php
|
||||
/**
|
||||
* @template-implements IteratorAggregate<int, int>
|
||||
*/
|
||||
class Bar implements IteratorAggregate {
|
||||
public function getIterator() : Traversable {
|
||||
yield from range(0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
$bat = new Bar();
|
||||
|
||||
foreach ($bat as $num) {}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user