Skip to content

Commit

Permalink
Initial support for assignment in condition
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Mar 5, 2019
1 parent 18350a9 commit 753ec78
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/Analyser/TypeSpecifier.php
Expand Up @@ -135,6 +135,9 @@ public function specifyTypesInCondition(
if ($expressions !== null) {
/** @var Expr $exprNode */
$exprNode = $expressions[0];
if ($exprNode instanceof Expr\Assign) {
$exprNode = $exprNode->var;
}
/** @var \PHPStan\Type\ConstantScalarType $constantType */
$constantType = $expressions[1];
if ($constantType->getValue() === false) {
Expand Down
27 changes: 27 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Expand Up @@ -8803,6 +8803,33 @@ public function testUnionProperties(
);
}

public function dataAssignmentInCondition(): array
{
return [
[
'AssignmentInCondition\Foo',
'$bar',
],
];
}

/**
* @dataProvider dataAssignmentInCondition
* @param string $description
* @param string $expression
*/
public function testAssignmentInCondition(
string $description,
string $expression
): void
{
$this->assertTypes(
__DIR__ . '/data/assignment-in-condition.php',
$description,
$expression
);
}

private function assertTypes(
string $file,
string $description,
Expand Down
110 changes: 110 additions & 0 deletions tests/PHPStan/Analyser/TypeSpecifierTest.php
Expand Up @@ -6,6 +6,7 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Equal;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\PropertyFetch;
Expand Down Expand Up @@ -46,6 +47,7 @@ protected function setUp(): void
$this->scope = $this->scope->assignVariable('bar', new ObjectType('Bar'));
$this->scope = $this->scope->assignVariable('stringOrNull', new UnionType([new StringType(), new NullType()]));
$this->scope = $this->scope->assignVariable('barOrNull', new UnionType([new ObjectType('Bar'), new NullType()]));
$this->scope = $this->scope->assignVariable('barOrFalse', new UnionType([new ObjectType('Bar'), new ConstantBooleanType(false)]));
$this->scope = $this->scope->assignVariable('stringOrFalse', new UnionType([new StringType(), new ConstantBooleanType(false)]));
$this->scope = $this->scope->assignVariable('array', new ArrayType(new MixedType(), new MixedType()));
$this->scope = $this->scope->assignVariable('foo', new MixedType());
Expand Down Expand Up @@ -631,6 +633,114 @@ public function dataCondition(): array
'isset(Foo::$bar)' => '~object|nonEmpty',
],
],
[
new Identical(
new Variable('barOrNull'),
new Expr\ConstFetch(new Name('null'))
),
[
'$barOrNull' => 'null',
],
[
'$barOrNull' => '~null',
],
],
[
new Identical(
new Expr\Assign(
new Variable('notNullBar'),
new Variable('barOrNull')
),
new Expr\ConstFetch(new Name('null'))
),
[
'$notNullBar' => 'null',
],
[
'$notNullBar' => '~null',
],
],
[
new NotIdentical(
new Variable('barOrNull'),
new Expr\ConstFetch(new Name('null'))
),
[
'$barOrNull' => '~null',
],
[
'$barOrNull' => 'null',
],
],
[
new NotIdentical(
new Expr\Assign(
new Variable('notNullBar'),
new Variable('barOrNull')
),
new Expr\ConstFetch(new Name('null'))
),
[
'$notNullBar' => '~null',
],
[
'$notNullBar' => 'null',
],
],
[
new Identical(
new Variable('barOrFalse'),
new Expr\ConstFetch(new Name('false'))
),
[
'$barOrFalse' => 'false & ~object|nonEmpty',
],
[
'$barOrFalse' => '~false',
],
],
[
new Identical(
new Expr\Assign(
new Variable('notFalseBar'),
new Variable('barOrFalse')
),
new Expr\ConstFetch(new Name('false'))
),
[
'$notFalseBar' => 'false & ~object|nonEmpty',
],
[
'$notFalseBar' => '~false',
],
],
[
new NotIdentical(
new Variable('barOrFalse'),
new Expr\ConstFetch(new Name('false'))
),
[
'$barOrFalse' => '~false',
],
[
'$barOrFalse' => 'false & ~object|nonEmpty',
],
],
[
new NotIdentical(
new Expr\Assign(
new Variable('notFalseBar'),
new Variable('barOrFalse')
),
new Expr\ConstFetch(new Name('false'))
),
[
'$notFalseBar' => '~false',
],
[
'$notFalseBar' => 'false & ~object|nonEmpty',
],
],
];
}

Expand Down
21 changes: 21 additions & 0 deletions tests/PHPStan/Analyser/data/assignment-in-condition.php
@@ -0,0 +1,21 @@
<?php

namespace AssignmentInCondition;

class Foo
{

public function doFoo(): ?self
{

}

public function doBar()
{
$foo = new self();
if (null !== $bar = $foo->doFoo()) {
die;
}
}

}

0 comments on commit 753ec78

Please sign in to comment.