Avoid dead catch false positive for inconsistently overridden trait methods - #6199
Avoid dead catch false positive for inconsistently overridden trait methods#6199peter17 wants to merge 3 commits into
Conversation
|
Hi again @staabm here is a proposal to fix phpstan/phpstan#10315 |
|
@staabm any comment on this? Thanks! |
|
Hey, thanks for the PR. I will come back to this PR when time allows. there is quite a bit of work in my queue atm |
…ethods A trait's try/catch can be dead in the context of one class using the trait and alive in another, e.g. when it depends on whether an abstract method gets overridden without throwing. Apply the same ConstantConditionInTraitHelper mechanism already used for isset/empty/?? to CatchWithUnthrownExceptionRule, so disagreeing verdicts across classes using the trait suppress the error instead of reporting it. Closes phpstan/phpstan#10315
|
@SanderMuller please review |
|
Reviewed at Four things, one of which I would want resolved before merge. 1. 2. Trait errors lose their "in context of class" decoration. Routing through the collector means a dead catch inside a trait is now reported once on the trait instead of once per using class: Consistent with how isset/empty already behave, and arguably nicer (no duplicates for a trait used by twenty classes) - but it is user-visible, and baseline entries that carry 3. The collector key is built from $key = sprintf('%s:%d', $node->getOriginalCaughtType()->describe(VerbosityLevel::typeOnly()), $node->getOriginalNode()->getStartLine());
4. Only one of the two new tests is a regression test. CI, worth a look before merge. Otherwise: full suite 21343 green, self-analysis clean, phpcs clean on the four changed files, and the branch is up to date with |
|
Thanks — this was a very useful review. All four addressed; 1 and 3 in code. 1. 3. No more 2 + 3, now pinned by a test. There was no coverage of a dead catch in a trait at all, so both the new reporting shape and the key granularity could change unnoticed. Added
The second case discriminates the key granularity: collapsing 4. Which test guards the fix. Confirmed, and it still holds after the restructure: suppressing the new node's emission in CI. I could not attribute the old-PHPUnit failure to the diff either, and after this restructure the analyser-side change is a strictly additive node emission behind Verification after the changes: 122 tests in I updated the PR description above. |
|
Checked
Gates on my side: 122 tests in Non-blocking note for later: in the dead path the unchecked-exception early return happens before the trait bookkeeping, so that case emits no verdict at all while the alive path always emits one. Harmless today - a lone "no error" group reports nothing, which matches current behaviour - but if the emit ever moves above that return, the two paths would start disagreeing about a catch neither of them reports. |
A trait's try/catch can be dead in the context of one class using the trait and alive in another, e.g. when it depends on whether an abstract method gets overridden without throwing. Apply the same ConstantConditionInTraitHelper mechanism already used for isset/empty/?? to CatchWithUnthrownExceptionRule, so disagreeing verdicts across classes using the trait suppress the error instead of reporting it.
Closes phpstan/phpstan#10315
Edit: routing trait catches through the collector changes where they are reported. A dead catch inside a trait used to be reported once per class using the trait, decorated with
(in context of class …); it is now reported once on the trait itself:before
after
This matches how isset/empty/
??in traits already behave and removes the duplication for a trait used by many classes, but it is user-visible: baseline entries carrying(in context of class …)forcatch.neverThrownwill stop matching and need regenerating. Worth a release-notes line.