1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Prevent incorrect template being passed to function

This commit is contained in:
Brown 2019-06-24 10:54:03 -04:00
parent 16768e363c
commit 2a1ed6ca6a
2 changed files with 66 additions and 35 deletions

View File

@ -519,46 +519,58 @@ class TypeAnalyzer
);
}
if ($intersection_container_type_lower === $intersection_input_type_lower) {
continue 2;
}
if ($intersection_input_type_lower === 'generator'
&& in_array($intersection_container_type_lower, ['iterator', 'traversable', 'iterable'], true)
if (!$intersection_container_type instanceof TTemplateParam
|| $intersection_input_type instanceof TTemplateParam
) {
continue 2;
}
if ($intersection_container_type instanceof TTemplateParam
&& $intersection_input_type instanceof TTemplateParam
) {
if ($intersection_container_type->param_name !== $intersection_input_type->param_name) {
return false;
}
}
if ($intersection_input_type_lower === 'traversable'
&& $intersection_container_type_lower === 'iterable'
) {
continue 2;
}
if ($intersection_container_type_lower === $intersection_input_type_lower) {
continue 2;
}
$input_type_is_interface = $codebase->interfaceExists($intersection_input_type_lower);
$container_type_is_interface = $codebase->interfaceExists($intersection_container_type_lower);
if ($intersection_input_type_lower === 'generator'
&& in_array($intersection_container_type_lower, ['iterator', 'traversable', 'iterable'], true)
) {
continue 2;
}
if ($allow_interface_equality && $input_type_is_interface && $container_type_is_interface) {
continue 2;
}
if ($intersection_input_type_lower === 'traversable'
&& $intersection_container_type_lower === 'iterable'
) {
continue 2;
}
if ($codebase->classExists($intersection_input_type_lower)
&& $codebase->classOrInterfaceExists($intersection_container_type_lower)
&& $codebase->classExtendsOrImplements(
$intersection_input_type_lower,
$intersection_container_type_lower
)
) {
continue 2;
}
$input_type_is_interface = $codebase->interfaceExists($intersection_input_type_lower);
$container_type_is_interface = $codebase->interfaceExists($intersection_container_type_lower);
if ($input_type_is_interface
&& $codebase->interfaceExtends(
$intersection_input_type_lower,
$intersection_container_type_lower
)
) {
continue 2;
if ($allow_interface_equality && $input_type_is_interface && $container_type_is_interface) {
continue 2;
}
if ($codebase->classExists($intersection_input_type_lower)
&& $codebase->classOrInterfaceExists($intersection_container_type_lower)
&& $codebase->classExtendsOrImplements(
$intersection_input_type_lower,
$intersection_container_type_lower
)
) {
continue 2;
}
if ($input_type_is_interface
&& $codebase->interfaceExtends(
$intersection_input_type_lower,
$intersection_container_type_lower
)
) {
continue 2;
}
}
if (ExpressionAnalyzer::isMock($intersection_input_type_lower)) {
@ -690,6 +702,10 @@ class TypeAnalyzer
}
if ($container_type_part instanceof TTemplateParam && $input_type_part instanceof TTemplateParam) {
if ($container_type_part->param_name !== $input_type_part->param_name) {
return false;
}
return self::isContainedBy(
$codebase,
$input_type_part->as,

View File

@ -1033,7 +1033,7 @@ class TemplateTest extends TestCase
class I {
/**
* @template T as Foo
* @param class-string $class
* @param class-string<T> $class
* @template-typeof T $class
* @return T|null
*/
@ -3490,6 +3490,21 @@ class TemplateTest extends TestCase
}',
'error_message' => 'InvalidReturnStatement'
],
'preventWrongTemplateBeingPassed' => [
'<?php
/**
* @template T of DateTime
* @template T2 of DateTime
* @param callable(T): T $parameter
* @param T2 $value
* @return T
*/
function foo(callable $parameter, $value)
{
return $parameter($value);
}',
'error_message' => 'InvalidArgument'
],
];
}
}