mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Fix #641 - allow is_a to operate on strings as well
This commit is contained in:
parent
4552e69ef2
commit
03b3a764e3
@ -814,6 +814,20 @@ class AssertionFinder
|
||||
if ($first_var_name) {
|
||||
$first_arg = $expr->args[1]->value;
|
||||
|
||||
$is_a_prefix = '';
|
||||
|
||||
if (isset($expr->args[2]->value)) {
|
||||
$third_arg = $expr->args[2]->value;
|
||||
|
||||
if (!$third_arg instanceof PhpParser\Node\Expr\ConstFetch
|
||||
|| !in_array(strtolower($third_arg->name->parts[0]), ['true', 'false'])
|
||||
) {
|
||||
return $if_types;
|
||||
}
|
||||
|
||||
$is_a_prefix = strtolower($third_arg->name->parts[0]) === 'true' ? 'isa-' : '';
|
||||
}
|
||||
|
||||
if ($first_arg instanceof PhpParser\Node\Scalar\String_) {
|
||||
$if_types[$first_var_name] = $prefix . $first_arg->value;
|
||||
} elseif ($first_arg instanceof PhpParser\Node\Expr\ClassConstFetch
|
||||
@ -824,11 +838,11 @@ class AssertionFinder
|
||||
$class_node = $first_arg->class;
|
||||
|
||||
if ($class_node->parts === ['static'] || $class_node->parts === ['self']) {
|
||||
$if_types[$first_var_name] = $prefix . $this_class_name;
|
||||
$if_types[$first_var_name] = $prefix . $is_a_prefix . $this_class_name;
|
||||
} elseif ($class_node->parts === ['parent']) {
|
||||
// do nothing
|
||||
} else {
|
||||
$if_types[$first_var_name] = $prefix . ClassLikeChecker::getFQCLNFromNameObject(
|
||||
$if_types[$first_var_name] = $prefix . $is_a_prefix . ClassLikeChecker::getFQCLNFromNameObject(
|
||||
$class_node,
|
||||
$source->getAliases()
|
||||
);
|
||||
@ -1125,16 +1139,6 @@ class AssertionFinder
|
||||
&& strtolower($second_arg->name) === 'class'
|
||||
)
|
||||
) {
|
||||
if (isset($stmt->args[2]->value)) {
|
||||
$third_arg = $stmt->args[2]->value;
|
||||
|
||||
if (!$third_arg instanceof PhpParser\Node\Expr\ConstFetch
|
||||
|| strtolower($third_arg->name->parts[0]) !== 'false'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,8 @@ class TClassString extends TString
|
||||
/**
|
||||
* @param string $class_type string
|
||||
*/
|
||||
public function __construct($class_type = 'object') {
|
||||
public function __construct($class_type = 'object')
|
||||
{
|
||||
$this->class_type = $class_type;
|
||||
}
|
||||
|
||||
|
@ -731,7 +731,26 @@ class Reconciler
|
||||
return Type::getMixed();
|
||||
}
|
||||
|
||||
$new_type = Type::parseString($new_var_type);
|
||||
if (substr($new_var_type, 0, 4) === 'isa-') {
|
||||
if ($existing_var_type->isMixed()) {
|
||||
return Type::getMixed();
|
||||
}
|
||||
|
||||
$new_var_type = substr($new_var_type, 4);
|
||||
|
||||
$existing_has_object = $existing_var_type->hasObjectType();
|
||||
$existing_has_string = $existing_var_type->hasString();
|
||||
|
||||
if ($existing_has_object && !$existing_has_string) {
|
||||
$new_type = Type::parseString($new_var_type);
|
||||
} elseif ($existing_has_string && !$existing_has_object) {
|
||||
$new_type = Type::getClassString($new_var_type);
|
||||
} else {
|
||||
$new_type = Type::getMixed();
|
||||
}
|
||||
} else {
|
||||
$new_type = Type::parseString($new_var_type);
|
||||
}
|
||||
|
||||
if ($existing_var_type->isMixed()) {
|
||||
return $new_type;
|
||||
|
@ -103,6 +103,36 @@ class ClassTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'classStringInstantiation' => [
|
||||
'<?php
|
||||
class Foo {}
|
||||
class Bar {}
|
||||
$class = mt_rand(0, 1) === 1 ? Foo::class : Bar::class;
|
||||
$object = new $class();',
|
||||
'assertions' => [
|
||||
'$object' => 'Foo|Bar',
|
||||
],
|
||||
],
|
||||
'instantiateClassAndIsA' => [
|
||||
'<?php
|
||||
class Foo {
|
||||
public function bar() : void{}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
function getFooClass() {
|
||||
return mt_rand(0, 1) === 1 ? Foo::class : null;
|
||||
}
|
||||
|
||||
$foo_class = getFooClass();
|
||||
|
||||
if (is_string($foo_class) && is_a($foo_class, Foo::class, true)) {
|
||||
$foo = new $foo_class();
|
||||
$foo->bar();
|
||||
}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -753,16 +753,6 @@ class TypeReconciliationTest extends TestCase
|
||||
|
||||
function takesNullableString(?string $s) : void {}',
|
||||
],
|
||||
'classStringInstantiation' => [
|
||||
'<?php
|
||||
class Foo {}
|
||||
class Bar {}
|
||||
$class = mt_rand(0, 1) === 1 ? Foo::class : Bar::class;
|
||||
$object = new $class();',
|
||||
'assertions' => [
|
||||
'$object' => 'Foo|Bar',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user