Skip to content

Commit

Permalink
Fix unset on nested array
Browse files Browse the repository at this point in the history
  • Loading branch information
rvanvelzen authored and ondrejmirtes committed Nov 10, 2022
1 parent 80ba5a0 commit 582a9cb
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 12 deletions.
24 changes: 12 additions & 12 deletions src/Analyser/MutatingScope.php
Expand Up @@ -3370,17 +3370,8 @@ public function unsetExpression(Expr $expr): self
$exprVarNativeType = $this->getType($expr->var);
$dimNativeType = $this->getType($expr->dim);
$unsetNativeType = $exprVarNativeType->unsetOffset($dimNativeType);
$scope = $this->specifyExpressionType($expr->var, $unsetType, $unsetNativeType)->invalidateExpression(
new FuncCall(new FullyQualified('count'), [new Arg($expr->var)]),
)->invalidateExpression(
new FuncCall(new FullyQualified('sizeof'), [new Arg($expr->var)]),
)->invalidateExpression(
new FuncCall(new Name('count'), [new Arg($expr->var)]),
)->invalidateExpression(
new FuncCall(new Name('sizeof'), [new Arg($expr->var)]),
);

if ($expr->var instanceof Expr\ArrayDimFetch && $expr->var->dim !== null) {
$scope = $this->addMoreSpecificType($expr->var, $unsetType, $unsetNativeType);
$scope = $scope->specifyExpressionType(
$expr->var->var,
$scope->getType($expr->var->var)->setOffsetValueType(
Expand All @@ -3392,9 +3383,18 @@ public function unsetExpression(Expr $expr): self
$scope->getNativeType($expr->var),
),
);
} else {
$scope = $this->specifyExpressionType($expr->var, $unsetType, $unsetNativeType);
}

return $scope;
return $scope->invalidateExpression(
new FuncCall(new FullyQualified('count'), [new Arg($expr->var)]),
)->invalidateExpression(
new FuncCall(new FullyQualified('sizeof'), [new Arg($expr->var)]),
)->invalidateExpression(
new FuncCall(new Name('count'), [new Arg($expr->var)]),
)->invalidateExpression(
new FuncCall(new Name('sizeof'), [new Arg($expr->var)]),
);
}

return $this;
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Expand Up @@ -1126,6 +1126,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/strtr.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/static-has-method.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/mixed-to-number.php');
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Variables/data/bug-8113.php');
}

/**
Expand Down
5 changes: 5 additions & 0 deletions tests/PHPStan/Rules/Variables/UnsetRuleTest.php
Expand Up @@ -81,4 +81,9 @@ public function testBug7417(): void
$this->analyse([__DIR__ . '/data/bug-7417.php'], []);
}

public function testBug8113(): void
{
$this->analyse([__DIR__ . '/data/bug-8113.php'], []);
}

}
48 changes: 48 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-8113.php
@@ -0,0 +1,48 @@
<?php declare(strict_types=1);

namespace Bug8113;

use function PHPStan\Testing\assertType;

function () {
/** @var mixed[][] $review */
$review = array(
'Review' => array('id' => 23,
'User' => array(
'first_name' => 'x',
),
),
'SurveyInvitation' => array(
'is_too_old_to_follow' => 'yes',
),
'User' => array(
'first_name' => 'x',
),
);

assertType('array<array>', $review);

if (
array_key_exists('review', $review['SurveyInvitation']) &&
$review['SurveyInvitation']['review'] === null
) {
assertType("array<array>&hasOffsetValue('SurveyInvitation', array&hasOffsetValue('review', null))", $review);
$review['Review'] = [
'id' => null,
'text' => null,
'answer' => null,
];
assertType("non-empty-array<array>&hasOffsetValue('Review', array{id: null, text: null, answer: null})&hasOffsetValue('SurveyInvitation', array&hasOffsetValue('review', null))", $review);
unset($review['SurveyInvitation']['review']);
assertType("non-empty-array<array>&hasOffsetValue('Review', array{id: null, text: null, answer: null})&hasOffsetValue('SurveyInvitation', array<mixed~'review', mixed>)", $review);
}
assertType('array<array>', $review);
if (array_key_exists('User', $review['Review'])) {
assertType("array<array>&hasOffsetValue('Review', array&hasOffset('User'))", $review);
$review['User'] = $review['Review']['User'];
assertType("hasOffsetValue('Review', array&hasOffset('User'))&hasOffsetValue('User', mixed)&non-empty-array", $review);
unset($review['Review']['User']);
assertType("hasOffsetValue('Review', array<mixed~'User', mixed>)&hasOffsetValue('User', mixed)&non-empty-array", $review);
}
assertType("array&hasOffsetValue('Review', array)", $review);
};

0 comments on commit 582a9cb

Please sign in to comment.