-
Notifications
You must be signed in to change notification settings - Fork 506
Remember narrowed types from the constructor when analysing other methods #3930
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
src/Analyser/NodeScopeResolver.php
Outdated
return 0; | ||
} | ||
|
||
return [!$a->isStatic(), $a->name->toLowerString() !== '__construct'] <=> [!$b->isStatic(), $b->name->toLowerString() !== '__construct']; |
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.
We have a better way to ask for constructor, that works for same-named constructors as class on PHP 7.
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.
ExtendedMethodReflection
has no isConstructor
method.
I took inspiration from
$isConstructor = $isFromTrait || $stmt->name->toLowerString() === '__construct'; |
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.
I looked into adding ExtendedMethodReflection->isConstructor(): TrinaryLogic
, but this is incompatible with
PhpMethodFromParserNodeReflection->isConstructor(): bool
any preferences how you want this to be resolved?
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.
I think we can leave as it is. This is mostly useful for readonly properties anyway, which means __construct()
constructors...
re-ordering the order in which methods get analyzed affected the ordering of errors in tests... I am not yet sure where/how to compensate that |
Here's this line: phpstan-src/src/Testing/RuleTestCase.php Line 244 in 375f68e
You could call |
I have put it behind bleeding edge and added corresponding opt-in methods for the test-base-classes so we can move forward without the need to adjust all tests |
This pull request has been marked as ready for review. |
sorry for push bombing :-) - I am finished now |
I just realized there's one more thing we could use this for: with natively typed properties (non-nullable), expressions like We should preserve PropertyInitializationExpr and then check for that in IssetCheck. This is for non-readonly properties too. |
great idea. done |
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 is getting really close to merging 👍
src/Rules/IssetCheck.php
Outdated
&& $expr->name instanceof Node\Identifier | ||
&& $expr->var instanceof Expr\Variable | ||
&& $expr->var->name === 'this' | ||
&& !TypeCombinator::containsNull($propertyReflection->getNativeType()) |
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.
- Doing
Type::isNull()
would make more sense. This example doesn't covermixed
(which can include null). - But I think we should pay more attention to
$typeMessageCallback
passed to IssetCheck. For both the type check and the error message. Something a little bit different happens in EmptyRule which should be covered by a set of tests. (Becauseempty($x)
is!isset($x) || $x == false
).
src/Rules/IssetCheck.php
Outdated
$this->propertyDescriptor->describeProperty($propertyReflection, $scope, $expr), | ||
$operatorDescription, | ||
), | ||
)->identifier(sprintf('%s.neverNullOrUninitialized', $identifier))->build(); |
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 identifier should include property
75ca7d5
to
e9343d7
Compare
Perfect, thank you! |
Hi, this looks pretty neat, thx! I was just wondering why e.g. https://phpstan.org/r/9c85e54d-6c87-42ee-84d5-6db7447c3e4e does not work in the same way? Is it possible to remember such expressions too? UPDATE: changed playground snippet, there was a bug.. Sorry, haven't thought too much about how this works, is it related to the fact that other methods might write / change the property of the wrapper object anytime in between the constructor and method call? |
we should be able to remember anything which cannot change after constructor was executed (e.g. because its readonly or because the runtime does not allow to change it once set by design). here is the code which decides what will be remembered and what skipped: |
cool, thx! I think my real case I experienced yesterday was not using readonly props, so it wouldn't work.. and this one is somewhat super special. I'll think about it maybe :) |
closes phpstan/phpstan#12860
closes phpstan/phpstan#10048
closes phpstan/phpstan#11828
closes phpstan/phpstan#9075
closes phpstan/phpstan#6063
closes phpstan/phpstan#12723