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) {
|
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)])) {
|
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 $input_type
|
||||||
* @param Type\Union $container_type
|
* @param Type\Union $container_type
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public static function isSimplyContainedBy(
|
public static function isSimplyContainedBy(
|
||||||
Type\Union $input_type,
|
Type\Union $input_type,
|
||||||
Type\Union $container_type
|
Type\Union $container_type
|
||||||
) {
|
) : bool {
|
||||||
if ($input_type->getId() === $container_type->getId()) {
|
if ($input_type->getId() === $container_type->getId()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -285,10 +283,26 @@ class TypeAnalyzer
|
|||||||
$container_type_not_null = clone $container_type;
|
$container_type_not_null = clone $container_type;
|
||||||
$container_type_not_null->removeType('null');
|
$container_type_not_null->removeType('null');
|
||||||
|
|
||||||
return !array_diff_key(
|
foreach ($input_type->getTypes() as $input_key => $input_type_part) {
|
||||||
$input_type_not_null->getTypes(),
|
foreach ($container_type->getTypes() as $container_key => $container_type_part) {
|
||||||
$container_type_not_null->getTypes()
|
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);
|
$class_storage = $this->classlike_storage_provider->get($fq_class_name);
|
||||||
|
|
||||||
if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_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 {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -757,7 +757,7 @@ class Methods
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) {
|
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
|
&& $method_storage->inheritdoc
|
||||||
&& $declaring_method_storage->throws
|
&& $declaring_method_storage->throws
|
||||||
) {
|
) {
|
||||||
$method_storage->throws = $declaring_method_storage->throws;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($storage->overridden_method_ids[$method_name]) === 1
|
if (count($storage->overridden_method_ids[$method_name]) === 1
|
||||||
&& $method_storage->signature_return_type
|
&& $method_storage->signature_return_type
|
||||||
&& !$method_storage->signature_return_type->isVoid()
|
&& !$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])) {
|
if (isset($declaring_class_storage->methods[$method_name])) {
|
||||||
$declaring_method_storage = $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 {
|
} else {
|
||||||
$storage->interface_method_ids[$method_name] = $interface_method_ids;
|
$storage->interface_method_ids[$method_name] = $interface_method_ids;
|
||||||
}
|
}
|
||||||
@ -1006,10 +1006,10 @@ class Populator
|
|||||||
if (isset($declaring_class_storage->methods[$method_name])
|
if (isset($declaring_class_storage->methods[$method_name])
|
||||||
&& $declaring_class_storage->methods[$method_name]->abstract
|
&& $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 {
|
} 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->declaring_method_ids[$method_name] = $declaring_method_id;
|
||||||
$storage->inheritable_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 = [];
|
public $appearing_method_ids = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<string, array<string>>
|
* @var array<string, array<string, string>>
|
||||||
*/
|
*/
|
||||||
public $overridden_method_ids = [];
|
public $overridden_method_ids = [];
|
||||||
|
|
||||||
|
@ -1975,6 +1975,21 @@ class TemplateExtendsTest extends TestCase
|
|||||||
|
|
||||||
echo (new F())->getValue();'
|
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