1
0
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:
Brown 2019-06-11 11:19:57 -04:00
parent 7cf8c362f0
commit 9c4599a0f0
7 changed files with 46 additions and 17 deletions

View File

@ -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)])) {

View File

@ -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;
} }
/** /**

View File

@ -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]);
} }
} }

View File

@ -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;
} }
} }

View File

@ -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;
} }
} }

View File

@ -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 = [];

View File

@ -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) {}',
],
]; ];
} }