diff --git a/src/Analyser/ExprHandler/MethodCallHandler.php b/src/Analyser/ExprHandler/MethodCallHandler.php index 28e0181c331..f2dc9fd9af2 100644 --- a/src/Analyser/ExprHandler/MethodCallHandler.php +++ b/src/Analyser/ExprHandler/MethodCallHandler.php @@ -176,6 +176,8 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex } } else { + $nodeScopeResolver->callNodeCallback($nodeCallback, new InvalidateExprNode($normalizedExpr->var), $scope, $storage); + $scope = $scope->invalidateExpression($normalizedExpr->var, true); $throwPoints[] = InternalThrowPoint::createImplicit($scope, $expr); } $hasYield = $hasYield || $argsResult->hasYield(); diff --git a/tests/PHPStan/Analyser/nsrt/bug-3831.php b/tests/PHPStan/Analyser/nsrt/bug-3831.php new file mode 100644 index 00000000000..b0459f5b298 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-3831.php @@ -0,0 +1,96 @@ + */ + public array $footer = []; + + public function test(): void + { + $this->counter = 0; + assertType('0', $this->counter); + + $this->{'increment'}(); + assertType('int', $this->counter); + } + + public function testDynamicVar(): void + { + $this->footer = []; + assertType('array{}', $this->footer); + + $method = 'compileSection'; + $this->{$method}(); + assertType('array', $this->footer); + } + + private function increment(): int + { + $this->counter++; + return 0; + } + + private function compileSection(): void + { + $this->footer[] = 'section-name'; + } +} + +class Template +{ + /** @var array */ + public $footer = []; + + public function render(): string + { + $content = ''; + $this->footer = []; + + assertType('array{}', $this->footer); + $this->{'compileSection'}(); + assertType('array', $this->footer); + + if (count($this->footer) > 0) { + $content = str_replace('some', 'thing', $content); + } + return $content; + } + + private function compileSection(): void + { + $this->footer[] = 'section-name'; + } +} + +class TemplateDynamicVar +{ + /** @var array */ + public $footer = []; + + public function render(): string + { + $content = ''; + $this->footer = []; + + assertType('array{}', $this->footer); + $method = 'compileSection'; + $this->{$method}(); + assertType('array', $this->footer); + + if (count($this->footer) > 0) { + $content = str_replace('some', 'thing', $content); + } + return $content; + } + + private function compileSection(): void + { + $this->footer[] = 'section-name'; + } +} diff --git a/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php index b87408f1499..48dce91125c 100644 --- a/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/NumberComparisonOperatorsConstantConditionRuleTest.php @@ -308,4 +308,9 @@ public function testBug11146(): void $this->analyse([__DIR__ . '/data/bug-11146.php'], []); } + public function testBug3831(): void + { + $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-3831.php'], []); + } + }