1
0
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:
Matthew Brown 2019-12-30 10:01:31 -05:00
parent c79ba0b09e
commit 19faa31865
6 changed files with 84 additions and 14 deletions

View File

@ -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]) {

View File

@ -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
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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

View File

@ -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());
}
}'
],
];
}