mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Fix #2409 - use more robust assertion parsing
This commit is contained in:
parent
5bd9b988fb
commit
16b8edd583
@ -2659,25 +2659,19 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
|
||||
return null;
|
||||
}
|
||||
|
||||
$assertion_type_parts = explode('|', $assertion_type);
|
||||
|
||||
$class_template_types = !$stmt instanceof PhpParser\Node\Stmt\ClassMethod || !$stmt->isStatic()
|
||||
? $this->class_template_types
|
||||
: [];
|
||||
|
||||
foreach ($assertion_type_parts as $i => $assertion_type_part) {
|
||||
if ($assertion_type_part !== 'falsy'
|
||||
&& $assertion_type_part !== 'array'
|
||||
&& $assertion_type_part !== 'list'
|
||||
&& $assertion_type_part !== 'iterable'
|
||||
) {
|
||||
$namespaced_type = Type::parseTokens(
|
||||
Type::fixUpLocalType(
|
||||
$assertion_type_part,
|
||||
$assertion_type,
|
||||
$this->aliases,
|
||||
$this->function_template_types + $class_template_types,
|
||||
$this->type_aliases,
|
||||
null
|
||||
null,
|
||||
null,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
@ -2687,9 +2681,20 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
|
||||
$this->function_template_types + $class_template_types
|
||||
);
|
||||
|
||||
$assertion_type_parts[$i] = $prefix . $namespaced_type->getId();
|
||||
foreach ($namespaced_type->getTypes() as $namespaced_type_part) {
|
||||
if ($namespaced_type_part instanceof Type\Atomic\TAssertionFalsy
|
||||
|| ($namespaced_type_part instanceof Type\Atomic\TList
|
||||
&& $namespaced_type_part->type_param->isMixed())
|
||||
|| ($namespaced_type_part instanceof Type\Atomic\TArray
|
||||
&& $namespaced_type_part->type_params[0]->isArrayKey()
|
||||
&& $namespaced_type_part->type_params[1]->isMixed())
|
||||
|| ($namespaced_type_part instanceof Type\Atomic\TIterable
|
||||
&& $namespaced_type_part->type_params[0]->isMixed()
|
||||
&& $namespaced_type_part->type_params[1]->isMixed())
|
||||
) {
|
||||
$assertion_type_parts[] = $prefix . $namespaced_type_part->getAssertionString();
|
||||
} else {
|
||||
$assertion_type_parts[$i] = $prefix . $assertion_type_part;
|
||||
$assertion_type_parts[] = $prefix . $namespaced_type_part->getId();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1030,7 +1030,8 @@ abstract class Type
|
||||
array $template_type_map = null,
|
||||
array $type_aliases = null,
|
||||
?string $self_fqcln = null,
|
||||
?string $parent_fqcln = null
|
||||
?string $parent_fqcln = null,
|
||||
bool $allow_assertions = false
|
||||
) {
|
||||
$type_tokens = self::tokenize($string_type);
|
||||
|
||||
@ -1122,6 +1123,11 @@ abstract class Type
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($allow_assertions && $string_type_token[0] === 'falsy') {
|
||||
$type_tokens[$i][0] = 'false-y';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($type_aliases[$string_type_token[0]])) {
|
||||
$replacement_tokens = $type_aliases[$string_type_token[0]];
|
||||
|
||||
|
@ -26,6 +26,7 @@ use Psalm\Type;
|
||||
use Psalm\Type\Atomic\ObjectLike;
|
||||
use Psalm\Type\Atomic\TArray;
|
||||
use Psalm\Type\Atomic\TArrayKey;
|
||||
use Psalm\Type\Atomic\TAssertionFalsy;
|
||||
use Psalm\Type\Atomic\TBool;
|
||||
use Psalm\Type\Atomic\TCallable;
|
||||
use Psalm\Type\Atomic\TCallableArray;
|
||||
@ -217,6 +218,9 @@ abstract class Atomic
|
||||
case 'html-escaped-string':
|
||||
return new THtmlEscapedString();
|
||||
|
||||
case 'false-y':
|
||||
return new TAssertionFalsy();
|
||||
|
||||
case '$this':
|
||||
return new TNamedObject('static');
|
||||
}
|
||||
|
50
src/Psalm/Type/Atomic/TAssertionFalsy.php
Normal file
50
src/Psalm/Type/Atomic/TAssertionFalsy.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace Psalm\Type\Atomic;
|
||||
|
||||
class TAssertionFalsy extends \Psalm\Type\Atomic
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return 'falsy';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return 'falsy';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAssertionString()
|
||||
{
|
||||
return 'falsy';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $namespace
|
||||
* @param array<string> $aliased_classes
|
||||
* @param string|null $this_class
|
||||
* @param int $php_major_version
|
||||
* @param int $php_minor_version
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function toPhpString(
|
||||
$namespace,
|
||||
array $aliased_classes,
|
||||
$this_class,
|
||||
$php_major_version,
|
||||
$php_minor_version
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function canBeFullyExpressedInPhp()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@ -44,6 +44,14 @@ class TIterable extends Atomic
|
||||
return 'iterable';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAssertionString()
|
||||
{
|
||||
return 'iterable';
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
$s = '';
|
||||
|
@ -209,7 +209,7 @@ class TList extends \Psalm\Type\Atomic
|
||||
*/
|
||||
public function getAssertionString()
|
||||
{
|
||||
return $this->getKey();
|
||||
return 'list';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -822,6 +822,13 @@ class AssertAnnotationTest extends TestCase
|
||||
echo count($a->getArray());
|
||||
}'
|
||||
],
|
||||
'preventErrorWhenAssertingOnArrayUnion' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-assert array<string,string|object> $data
|
||||
*/
|
||||
function validate(array $data): void {}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user