Skip to content

Commit

Permalink
Fix isset() with multiple arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
jlherren authored and ondrejmirtes committed Oct 18, 2020
1 parent 5be8b80 commit 1893100
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 26 deletions.
45 changes: 19 additions & 26 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1221,36 +1221,25 @@ private function ensureNonNullability(MutatingScope $scope, Expr $expr, bool $fi
{
$exprToSpecify = $expr;
$specifiedExpressions = [];
while (
$exprToSpecify instanceof PropertyFetch
|| $exprToSpecify instanceof StaticPropertyFetch
|| (
$findMethods && (
$exprToSpecify instanceof MethodCall
|| $exprToSpecify instanceof StaticCall
)
)
) {
if (
$exprToSpecify instanceof PropertyFetch
|| $exprToSpecify instanceof MethodCall
) {
while (true) {
$exprType = $scope->getType($exprToSpecify);
$exprTypeWithoutNull = TypeCombinator::removeNull($exprType);
if (!$exprType->equals($exprTypeWithoutNull)) {
$specifiedExpressions[] = new EnsuredNonNullabilityResultExpression($exprToSpecify, $exprType);
$scope = $scope->specifyExpressionType($exprToSpecify, $exprTypeWithoutNull);
}

if ($exprToSpecify instanceof PropertyFetch) {
$exprToSpecify = $exprToSpecify->var;
} elseif ($exprToSpecify instanceof StaticPropertyFetch && $exprToSpecify->class instanceof Expr) {
$exprToSpecify = $exprToSpecify->class;
} elseif ($findMethods && $exprToSpecify instanceof MethodCall) {
$exprToSpecify = $exprToSpecify->var;
} elseif ($exprToSpecify->class instanceof Expr) {
} elseif ($findMethods && $exprToSpecify instanceof StaticCall && $exprToSpecify->class instanceof Expr) {
$exprToSpecify = $exprToSpecify->class;
} else {
break;
}

$exprType = $scope->getType($exprToSpecify);
$exprTypeWithoutNull = TypeCombinator::removeNull($exprType);
if ($exprType->equals($exprTypeWithoutNull)) {
continue;
}

$specifiedExpressions[] = new EnsuredNonNullabilityResultExpression($exprToSpecify, $exprType);

$scope = $scope->specifyExpressionType($exprToSpecify, $exprTypeWithoutNull);
}

return new EnsuredNonNullabilityResult($scope, $specifiedExpressions);
Expand Down Expand Up @@ -1861,15 +1850,19 @@ static function () use ($expr, $rightResult): MutatingScope {
$scope = $this->lookForExitVariableAssign($scope, $expr->expr);
} elseif ($expr instanceof Expr\Isset_) {
$hasYield = false;
$nonNullabilityResults = [];
foreach ($expr->vars as $var) {
$nonNullabilityResult = $this->ensureNonNullability($scope, $var, true);
$scope = $this->lookForEnterVariableAssign($nonNullabilityResult->getScope(), $var);
$result = $this->processExprNode($var, $scope, $nodeCallback, $context->enterDeep());
$scope = $result->getScope();
$hasYield = $hasYield || $result->hasYield();
$scope = $this->revertNonNullability($scope, $nonNullabilityResult->getSpecifiedExpressions());
$nonNullabilityResults[] = $nonNullabilityResult;
$scope = $this->lookForExitVariableAssign($scope, $var);
}
foreach (array_reverse($nonNullabilityResults) as $nonNullabilityResult) {
$scope = $this->revertNonNullability($scope, $nonNullabilityResult->getSpecifiedExpressions());
}
} elseif ($expr instanceof Instanceof_) {
$result = $this->processExprNode($expr->expr, $scope, $nodeCallback, $context->enterDeep());
$scope = $result->getScope();
Expand Down
4 changes: 4 additions & 0 deletions tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ public function testAccessProperties(): void
'Cannot access property $selfOrNull on TestAccessProperties\RevertNonNullabilityForIsset|null.',
402,
],
[
'Cannot access property $array on stdClass|null.',
412,
],
]
);
}
Expand Down
15 changes: 15 additions & 0 deletions tests/PHPStan/Rules/Properties/data/access-properties.php
Original file line number Diff line number Diff line change
Expand Up @@ -403,3 +403,18 @@ public function doFoo()
}

}

class Bug1884
{

function mustReport(?\stdClass $nullable): bool
{
return isset($nullable->array['key']);
}

function mustNotReport(?\stdClass $nullable): bool
{
return isset($nullable, $nullable->array['key']);
}

}

0 comments on commit 1893100

Please sign in to comment.