Skip to content
Permalink
Browse files

Allow assertions on nested properties

  • Loading branch information
muglug committed Dec 30, 2019
1 parent c79ba0b commit 19faa318656fe57b9a51a17224679de241ea948e
@@ -130,7 +130,11 @@ public static function scrapeAssertions(
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 @@ public static function scrapeAssertions(
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 @@ protected static function processCustomAssertion(
}
}
} 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 @@ protected static function processCustomAssertion(
}
}
} 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 @@ public static function analyze(
$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 @@ function (Assertion $assertion) use ($generic_params) : Assertion {
$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 @@ function (PhpParser\Node\Arg $arg) {
$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 @@ function (Assertion $assertion) use ($class_template_params) : Assertion {
$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 @@ function (PhpParser\Node\Arg $arg) {
$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 @@ function (Assertion $assertion) use ($generic_params) : Assertion {
$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 @@ public function __construct($var_id, array $rule)
/**
* @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 @@ function doBar($data) {
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());
}
}'
],
];
}

0 comments on commit 19faa31

Please sign in to comment.
You can’t perform that action at this time.