Skip to content

Commit

Permalink
Support for empty() - it's like !isset()
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Dec 29, 2016
1 parent 793edec commit 10eb46d
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 1 deletion.
25 changes: 24 additions & 1 deletion src/Analyser/NodeScopeResolver.php
Expand Up @@ -171,6 +171,13 @@ public function processNodes(
}
}
}
} else {
if ($node instanceof Expr\Empty_) {
if ($node->expr instanceof PropertyFetch) {
$scope = $scope->specifyFetchedPropertyFromIsset($node->expr);
}
$scope = $this->assignVariable($scope, $node->expr);
}
}
});
}
Expand Down Expand Up @@ -333,6 +340,13 @@ private function processNode(\PhpParser\Node $node, Scope $scope, \Closure $node
}
}
}
} else {
if ($node instanceof Expr\Empty_) {
if ($node->expr instanceof PropertyFetch) {
$scope = $scope->specifyFetchedPropertyFromIsset($node->expr);
}
$scope = $this->assignVariable($scope, $node->expr);
}
}
};
$this->processNode($node->cond, $scope, $specifyFetchedProperty);
Expand Down Expand Up @@ -480,6 +494,13 @@ private function processNode(\PhpParser\Node $node, Scope $scope, \Closure $node
$scope = $this->lookForAssigns($scope, $node->left);
}

if ($node instanceof Expr\Empty_ && $subNodeName === 'expr') {
if ($node->expr instanceof PropertyFetch) {
$scope = $scope->specifyFetchedPropertyFromIsset($node->expr);
}
$scope = $this->lookForEnterVariableAssign($scope, $node->expr);
}

$nodeScope = $scope->exitFirstLevelStatements();
if ($scope->isInFirstLevelStatement()) {
if ($node instanceof Ternary && $subNodeName !== 'cond') {
Expand Down Expand Up @@ -724,6 +745,8 @@ private function lookForAssigns(Scope $scope, \PhpParser\Node $node): Scope
foreach ($node->vars as $var) {
$scope = $this->lookForAssigns($scope, $var);
}
} elseif ($node instanceof Expr\Empty_) {
$scope = $this->lookForAssigns($scope, $node->expr);
} elseif ($node instanceof ArrayDimFetch && $node->dim !== null) {
$scope = $this->lookForAssigns($scope, $node->dim);
} elseif ($node instanceof Expr\Closure) {
Expand All @@ -743,7 +766,7 @@ private function lookForAssigns(Scope $scope, \PhpParser\Node $node): Scope

private function updateScopeForVariableAssign(Scope $scope, \PhpParser\Node $node): Scope
{
if (($node instanceof Assign || $node instanceof AssignRef) || $node instanceof Isset_) {
if ($node instanceof Assign || $node instanceof AssignRef || $node instanceof Isset_) {
if ($node instanceof Assign || $node instanceof AssignRef) {
$vars = [$node->var];
} elseif ($node instanceof Isset_) {
Expand Down
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/Classes/AccessPropertiesRuleTest.php
Expand Up @@ -61,6 +61,14 @@ public function testAccessProperties()
'Access to property $foo on an unknown class TestAccessProperties\UnknownClass.',
63,
],
[
'Access to an undefined property TestAccessProperties\FooAccessProperties::$emptyBaz.',
68,
],
[
'Access to an undefined property TestAccessProperties\FooAccessProperties::$emptyNonexistent.',
70,
],
]
);
}
Expand Down
10 changes: 10 additions & 0 deletions tests/PHPStan/Rules/Classes/data/access-properties.php
Expand Up @@ -61,6 +61,16 @@ public function foo(\stdClass $stdClass)

$bar = new UnknownClass();
$bar->foo;

if (!empty($foo->emptyBaz)) {
$foo->emptyBaz;
}
$foo->emptyBaz;
if (empty($foo->emptyNonexistent)) {
$foo->emptyNonexistent;
return;
}
$foo->emptyNonexistent;
}

}
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php
Expand Up @@ -62,6 +62,14 @@ public function testDefinedVariables()
'Undefined variable: $this',
99,
],
[
'Undefined variable: $variableInEmpty',
145,
],
[
'Undefined variable: $negatedVariableInEmpty',
156,
],
]);
}

Expand Down
19 changes: 19 additions & 0 deletions tests/PHPStan/Rules/Variables/data/defined-variables.php
Expand Up @@ -141,3 +141,22 @@ function () use (&$variablePassedByReferenceToClosure) {

};
echo $variablePassedByReferenceToClosure;
if (empty($variableInEmpty) && empty($anotherVariableInEmpty['foo'])) {
echo $variableInEmpty; // does not exist here
return;
} else {
//echo $variableInEmpty; // exists here - not yet supported
}

if (!empty($negatedVariableInEmpty)) {
echo $negatedVariableInEmpty; // exists here
}

echo $variableInEmpty; // exists here
echo $negatedVariableInEmpty; // does not exist here

if (isset($variableInIsset) && isset($anotherVariableInIsset['foo'])) {
echo $variableInIsset;
} else {
echo $variableInIsset; // does not exist
}

0 comments on commit 10eb46d

Please sign in to comment.