-
Notifications
You must be signed in to change notification settings - Fork 523
Fix false positive dead catch on property assignment #1047
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Rerunning tests because the failing tests seemed not related to this PR. |
@ondrejmirtes |
src/Analyser/NodeScopeResolver.php
Outdated
@@ -3310,6 +3310,9 @@ private function processAssignVar( | |||
if ($propertyReflection->canChangeTypeAfterAssignment()) { | |||
$scope = $scope->assignExpression($var, $assignedExprType); | |||
} | |||
if ($assignedExprType->isSuperTypeOf($propertyReflection->getWritableType())->no()) { | |||
$throwPoints[] = ThrowPoint::createImplicit($scope, $assignedExpr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error might occur if we have a property with a native type int
and we try to assign int|string
into it. It means that the condition should be !$assignedExprType->isSuperTypeOf($propertyReflection->getWritableType())->yes()
instead. Please add a test and modify the implementation.
Also there might be a situation where the property is not defined at all. In that case we should simulate MethodCall to __set
and see what throw points that produces (when the method exists). You can do that by calling $this->processExprNode(new MethodCall($var->var, '__set'), $scope, static function (): void {}, $context)->getThrowPoints()
.
There's a similar bug that you can look to in the next PR :) phpstan/phpstan#4852
Thank you!
@ondrejmirtes |
@ondrejmirtes
ThrowPoint::createExplicit($scope, $scope->getType(new New_(new Name(\TypeError::class))), $assignedExpr, false) |
Instead of Explicit/implicit throw points - "explicit" is for cases where the So I guess in this case it's an explicit throw point. |
Thank you very much for your information!
phpstan-src/src/Type/ObjectType.php Line 61 in d32942a
Thanks, I had a misunderstanding watching property $superTypes here. I was thinking that calling new ObjectType(\TypeError::class) is not setting the $superTypes , but this property was only a cache.
|
src/Analyser/NodeScopeResolver.php
Outdated
} else { | ||
// fallback | ||
$assignedExprType = $scope->getType($assignedExpr); | ||
$nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope); | ||
$scope = $scope->assignExpression($var, $assignedExprType); | ||
// simulate dynamic property assign to get throw points | ||
$throwPoints = array_merge($throwPoints, $this->processExprNode( | ||
new MethodCall($var->var, '__set'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs some tests :)
- Class without the
__set
magic method - does not throw anything (dead catch reported). - Class with
__set
magic method and@throws void
annotation (dead catch reported). - Class with
__set
magic method and@throws SomeException
(dead catch not reported).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
For the first case, there is a implicit ThrowPoint already, when method reflection is not found.
I'm not sure with the purpose of this throw point, so I'm gonna check it.
phpstan-src/src/Analyser/NodeScopeResolver.php
Line 1994 in 2167438
$throwPoints[] = ThrowPoint::createImplicit($scope, $expr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was from this case
84b0934
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, understood
I shouldn’t process __set
if its not declared.
Thank you! |
fixes phpstan/phpstan#6256
I hope I understood the concept of ThrowPoint correctly...