Skip to content

Commit

Permalink
Fix/issue 3171 dynamic properties
Browse files Browse the repository at this point in the history
  • Loading branch information
rajyan committed Apr 22, 2022
1 parent 750eeb4 commit fb83f47
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 29 deletions.
35 changes: 10 additions & 25 deletions src/Analyser/NodeScopeResolver.php
Expand Up @@ -1536,10 +1536,8 @@ private function lookForExpressionCallback(MutatingScope $scope, Expr $expr, Clo
$scope = $this->lookForExpressionCallback($scope, $expr->var, $callback);
} elseif ($expr instanceof PropertyFetch || $expr instanceof Expr\NullsafePropertyFetch) {
$scope = $this->lookForExpressionCallback($scope, $expr->var, $callback);
} elseif ($expr instanceof StaticPropertyFetch) {
if ($expr->class instanceof Expr) {
$scope = $this->lookForExpressionCallback($scope, $expr->class, $callback);
}
} elseif ($expr instanceof StaticPropertyFetch && $expr->class instanceof Expr) {
$scope = $this->lookForExpressionCallback($scope, $expr->class, $callback);
} elseif ($expr instanceof Array_ || $expr instanceof List_) {
foreach ($expr->items as $item) {
if ($item === null) {
Expand Down Expand Up @@ -1576,29 +1574,16 @@ private function ensureShallowNonNullability(MutatingScope $scope, Expr $exprToS
return new EnsuredNonNullabilityResult($scope, []);
}

private function ensureNonNullability(MutatingScope $scope, Expr $expr, bool $findMethods): EnsuredNonNullabilityResult
private function ensureNonNullability(MutatingScope $scope, Expr $expr): EnsuredNonNullabilityResult
{
$exprToSpecify = $expr;
$specifiedExpressions = [];
while (true) {
$result = $this->ensureShallowNonNullability($scope, $exprToSpecify);
$scope = $result->getScope();
$scope = $this->lookForExpressionCallback($scope, $expr, function ($scope, $expr) use (&$specifiedExpressions) {
$result = $this->ensureShallowNonNullability($scope, $expr);
foreach ($result->getSpecifiedExpressions() as $specifiedExpression) {
$specifiedExpressions[] = $specifiedExpression;
}

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 ($findMethods && $exprToSpecify instanceof StaticCall && $exprToSpecify->class instanceof Expr) {
$exprToSpecify = $exprToSpecify->class;
} else {
break;
}
}
return $result->getScope();
});

return new EnsuredNonNullabilityResult($scope, $specifiedExpressions);
}
Expand Down Expand Up @@ -2304,7 +2289,7 @@ static function (?Type $offsetType, Type $valueType) use (&$arrayType): void {
static fn (): MutatingScope => $rightResult->getScope()->filterByFalseyValue($expr),
);
} elseif ($expr instanceof Coalesce) {
$nonNullabilityResult = $this->ensureNonNullability($scope, $expr->left, false);
$nonNullabilityResult = $this->ensureNonNullability($scope, $expr->left);
$condScope = $this->lookForSetAllowedUndefinedExpressions($nonNullabilityResult->getScope(), $expr->left);
$condResult = $this->processExprNode($expr->left, $condScope, $nodeCallback, $context->enterDeep());
$scope = $this->revertNonNullability($condResult->getScope(), $nonNullabilityResult->getSpecifiedExpressions());
Expand Down Expand Up @@ -2378,7 +2363,7 @@ static function (?Type $offsetType, Type $valueType) use (&$arrayType): void {
$throwPoints = $result->getThrowPoints();
}
} elseif ($expr instanceof Expr\Empty_) {
$nonNullabilityResult = $this->ensureNonNullability($scope, $expr->expr, true);
$nonNullabilityResult = $this->ensureNonNullability($scope, $expr->expr);
$scope = $this->lookForSetAllowedUndefinedExpressions($nonNullabilityResult->getScope(), $expr->expr);
$result = $this->processExprNode($expr->expr, $scope, $nodeCallback, $context->enterDeep());
$scope = $result->getScope();
Expand All @@ -2391,7 +2376,7 @@ static function (?Type $offsetType, Type $valueType) use (&$arrayType): void {
$throwPoints = [];
$nonNullabilityResults = [];
foreach ($expr->vars as $var) {
$nonNullabilityResult = $this->ensureNonNullability($scope, $var, true);
$nonNullabilityResult = $this->ensureNonNullability($scope, $var);
$scope = $this->lookForSetAllowedUndefinedExpressions($nonNullabilityResult->getScope(), $var);
$result = $this->processExprNode($var, $scope, $nodeCallback, $context->enterDeep());
$scope = $result->getScope();
Expand Down
12 changes: 8 additions & 4 deletions tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php
Expand Up @@ -510,10 +510,6 @@ public function testAccessPropertiesOnDynamicProperties(): void
'Cannot access property $selfOrNull on TestAccessProperties\RevertNonNullabilityForIsset|null.',
402,
],
[
'Access to an undefined property stdClass|null::$array.',
412,
],
],
);
}
Expand Down Expand Up @@ -840,4 +836,12 @@ public function testBug3171(): void
$this->analyse([__DIR__ . '/data/bug-3171.php'], []);
}

public function testBug3171OnDynamicProperties(): void
{
$this->checkThisOnly = false;
$this->checkUnionTypes = true;
$this->checkDynamicProperties = true;
$this->analyse([__DIR__ . '/data/bug-3171.php'], []);
}

}

0 comments on commit fb83f47

Please sign in to comment.