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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$assertion_type_parts = explode('|', $assertion_type);
|
|
||||||
|
|
||||||
$class_template_types = !$stmt instanceof PhpParser\Node\Stmt\ClassMethod || !$stmt->isStatic()
|
$class_template_types = !$stmt instanceof PhpParser\Node\Stmt\ClassMethod || !$stmt->isStatic()
|
||||||
? $this->class_template_types
|
? $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(
|
$namespaced_type = Type::parseTokens(
|
||||||
Type::fixUpLocalType(
|
Type::fixUpLocalType(
|
||||||
$assertion_type_part,
|
$assertion_type,
|
||||||
$this->aliases,
|
$this->aliases,
|
||||||
$this->function_template_types + $class_template_types,
|
$this->function_template_types + $class_template_types,
|
||||||
$this->type_aliases,
|
$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
|
$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 {
|
} 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 $template_type_map = null,
|
||||||
array $type_aliases = null,
|
array $type_aliases = null,
|
||||||
?string $self_fqcln = null,
|
?string $self_fqcln = null,
|
||||||
?string $parent_fqcln = null
|
?string $parent_fqcln = null,
|
||||||
|
bool $allow_assertions = false
|
||||||
) {
|
) {
|
||||||
$type_tokens = self::tokenize($string_type);
|
$type_tokens = self::tokenize($string_type);
|
||||||
|
|
||||||
@ -1122,6 +1123,11 @@ abstract class Type
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($allow_assertions && $string_type_token[0] === 'falsy') {
|
||||||
|
$type_tokens[$i][0] = 'false-y';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($type_aliases[$string_type_token[0]])) {
|
if (isset($type_aliases[$string_type_token[0]])) {
|
||||||
$replacement_tokens = $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\ObjectLike;
|
||||||
use Psalm\Type\Atomic\TArray;
|
use Psalm\Type\Atomic\TArray;
|
||||||
use Psalm\Type\Atomic\TArrayKey;
|
use Psalm\Type\Atomic\TArrayKey;
|
||||||
|
use Psalm\Type\Atomic\TAssertionFalsy;
|
||||||
use Psalm\Type\Atomic\TBool;
|
use Psalm\Type\Atomic\TBool;
|
||||||
use Psalm\Type\Atomic\TCallable;
|
use Psalm\Type\Atomic\TCallable;
|
||||||
use Psalm\Type\Atomic\TCallableArray;
|
use Psalm\Type\Atomic\TCallableArray;
|
||||||
@ -217,6 +218,9 @@ abstract class Atomic
|
|||||||
case 'html-escaped-string':
|
case 'html-escaped-string':
|
||||||
return new THtmlEscapedString();
|
return new THtmlEscapedString();
|
||||||
|
|
||||||
|
case 'false-y':
|
||||||
|
return new TAssertionFalsy();
|
||||||
|
|
||||||
case '$this':
|
case '$this':
|
||||||
return new TNamedObject('static');
|
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 'iterable';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAssertionString()
|
||||||
|
{
|
||||||
|
return 'iterable';
|
||||||
|
}
|
||||||
|
|
||||||
public function getId()
|
public function getId()
|
||||||
{
|
{
|
||||||
$s = '';
|
$s = '';
|
||||||
|
@ -209,7 +209,7 @@ class TList extends \Psalm\Type\Atomic
|
|||||||
*/
|
*/
|
||||||
public function getAssertionString()
|
public function getAssertionString()
|
||||||
{
|
{
|
||||||
return $this->getKey();
|
return 'list';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -822,6 +822,13 @@ class AssertAnnotationTest extends TestCase
|
|||||||
echo count($a->getArray());
|
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