mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Allow assertions on nested properties
This commit is contained in:
parent
c79ba0b09e
commit
19faa31865
@ -130,7 +130,11 @@ class AssertionFinder
|
||||
if ($var_name) {
|
||||
$if_types[$var_name] = [['!falsy']];
|
||||
|
||||
return $if_types;
|
||||
if (!$conditional instanceof PhpParser\Node\Expr\MethodCall
|
||||
&& !$conditional instanceof PhpParser\Node\Expr\StaticCall
|
||||
) {
|
||||
return $if_types;
|
||||
}
|
||||
}
|
||||
|
||||
if ($conditional instanceof PhpParser\Node\Expr\Assign) {
|
||||
@ -332,7 +336,7 @@ class AssertionFinder
|
||||
if ($conditional instanceof PhpParser\Node\Expr\MethodCall
|
||||
|| $conditional instanceof PhpParser\Node\Expr\StaticCall
|
||||
) {
|
||||
$if_types = self::processCustomAssertion($conditional, $this_class_name, $source, false);
|
||||
$if_types += self::processCustomAssertion($conditional, $this_class_name, $source, false);
|
||||
|
||||
return $if_types;
|
||||
}
|
||||
@ -1950,7 +1954,6 @@ class AssertionFinder
|
||||
}
|
||||
}
|
||||
} elseif (\is_string($assertion->var_id)
|
||||
&& strpos($assertion->var_id, '$this->') === 0
|
||||
&& $expr instanceof PhpParser\Node\Expr\MethodCall
|
||||
) {
|
||||
if ($prefix === $assertion->rule[0][0][0]) {
|
||||
@ -1999,7 +2002,6 @@ class AssertionFinder
|
||||
}
|
||||
}
|
||||
} elseif (\is_string($assertion->var_id)
|
||||
&& strpos($assertion->var_id, '$this->') === 0
|
||||
&& $expr instanceof PhpParser\Node\Expr\MethodCall
|
||||
) {
|
||||
if ($prefix === $assertion->rule[0][0][0]) {
|
||||
|
@ -778,7 +778,7 @@ class FunctionCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expressio
|
||||
$stmt,
|
||||
array_map(
|
||||
function (Assertion $assertion) use ($generic_params) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($generic_params ?: []);
|
||||
return $assertion->getUntemplatedCopy($generic_params ?: [], null);
|
||||
},
|
||||
$function_storage->if_true_assertions
|
||||
)
|
||||
@ -790,7 +790,7 @@ class FunctionCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expressio
|
||||
$stmt,
|
||||
array_map(
|
||||
function (Assertion $assertion) use ($generic_params) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($generic_params ?: []);
|
||||
return $assertion->getUntemplatedCopy($generic_params ?: [], null);
|
||||
},
|
||||
$function_storage->if_false_assertions
|
||||
)
|
||||
|
@ -1398,8 +1398,9 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
$statements_analyzer->node_data->setIfTrueAssertions(
|
||||
$stmt,
|
||||
array_map(
|
||||
function (Assertion $assertion) use ($class_template_params) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($class_template_params ?: []);
|
||||
function (Assertion $assertion)
|
||||
use ($class_template_params, $lhs_var_id) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($class_template_params ?: [], $lhs_var_id);
|
||||
},
|
||||
$method_storage->if_true_assertions
|
||||
)
|
||||
@ -1410,8 +1411,9 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
$statements_analyzer->node_data->setIfFalseAssertions(
|
||||
$stmt,
|
||||
array_map(
|
||||
function (Assertion $assertion) use ($class_template_params) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($class_template_params ?: []);
|
||||
function (Assertion $assertion)
|
||||
use ($class_template_params, $lhs_var_id) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($class_template_params ?: [], $lhs_var_id);
|
||||
},
|
||||
$method_storage->if_false_assertions
|
||||
)
|
||||
|
@ -973,7 +973,7 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
$stmt,
|
||||
array_map(
|
||||
function (Assertion $assertion) use ($generic_params) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($generic_params);
|
||||
return $assertion->getUntemplatedCopy($generic_params, null);
|
||||
},
|
||||
$method_storage->if_true_assertions
|
||||
)
|
||||
@ -985,7 +985,7 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
$stmt,
|
||||
array_map(
|
||||
function (Assertion $assertion) use ($generic_params) : Assertion {
|
||||
return $assertion->getUntemplatedCopy($generic_params);
|
||||
return $assertion->getUntemplatedCopy($generic_params, null);
|
||||
},
|
||||
$method_storage->if_false_assertions
|
||||
)
|
||||
|
@ -30,10 +30,12 @@ class Assertion
|
||||
/**
|
||||
* @param array<string, array<string, array{0:\Psalm\Type\Union}>> $template_type_map
|
||||
*/
|
||||
public function getUntemplatedCopy(array $template_type_map) : self
|
||||
public function getUntemplatedCopy(array $template_type_map, ?string $this_var_id) : self
|
||||
{
|
||||
return new Assertion(
|
||||
$this->var_id,
|
||||
is_string($this->var_id) && $this_var_id
|
||||
? str_replace('$this->', $this_var_id . '->', $this->var_id)
|
||||
: $this->var_id,
|
||||
array_map(
|
||||
/**
|
||||
* @param array<int, string> $rules
|
||||
|
@ -730,6 +730,70 @@ class AssertAnnotationTest extends TestCase
|
||||
throw new \Exception();
|
||||
}'
|
||||
],
|
||||
'assertOnNestedProperty' => [
|
||||
'<?php
|
||||
/** @psalm-immutable */
|
||||
class B {
|
||||
public ?array $arr = null;
|
||||
|
||||
public function __construct(?array $arr) {
|
||||
$this->arr = $arr;
|
||||
}
|
||||
}
|
||||
|
||||
/** @psalm-immutable */
|
||||
class A {
|
||||
public B $b;
|
||||
public function __construct(B $b) {
|
||||
$this->b = $b;
|
||||
}
|
||||
|
||||
/** @psalm-assert-if-true !null $this->b->arr */
|
||||
public function hasArray() : bool {
|
||||
return $this->b->arr !== null;
|
||||
}
|
||||
}
|
||||
|
||||
function foo(A $a) : void {
|
||||
if ($a->hasArray()) {
|
||||
echo count($a->b->arr);
|
||||
}
|
||||
}'
|
||||
],
|
||||
'assertOnNestedMethod' => [
|
||||
'<?php
|
||||
/** @psalm-immutable */
|
||||
class B {
|
||||
private ?array $arr = null;
|
||||
|
||||
public function __construct(?array $arr) {
|
||||
$this->arr = $arr;
|
||||
}
|
||||
|
||||
public function getArray() : ?array {
|
||||
return $this->arr;
|
||||
}
|
||||
}
|
||||
|
||||
/** @psalm-immutable */
|
||||
class A {
|
||||
public B $b;
|
||||
public function __construct(B $b) {
|
||||
$this->b = $b;
|
||||
}
|
||||
|
||||
/** @psalm-assert-if-true !null $this->b->getarray() */
|
||||
public function hasArray() : bool {
|
||||
return $this->b->getArray() !== null;
|
||||
}
|
||||
}
|
||||
|
||||
function foo(A $a) : void {
|
||||
if ($a->hasArray()) {
|
||||
echo count($a->b->getArray());
|
||||
}
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user