Report abstract method overriding non-abstract method in OverridingMethodRule and OverridingPropertyRule#5730
Conversation
…ethodRule` and `OverridingPropertyRule` - Add non-ignorable error in OverridingMethodRule when an abstract method overrides a non-abstract parent method - Handle constructor special case separately since MethodPrototypeFinder skips non-abstract constructor prototypes - Add non-ignorable error in OverridingPropertyRule when an abstract property with hooks overrides a non-abstract hooked property (per-hook reporting) - Error message matches PHP's native fatal error: "Cannot make non abstract method X::Y() abstract in class Z" - Cover static methods, protected methods, multi-level inheritance, and constructors in tests
ondrejmirtes
left a comment
There was a problem hiding this comment.
tests/PHPStan/Rules/Properties/data/bug-14457.phpneeds to be excluded frommake lintin Makefile- There are escaped mutants https://github.com/phpstan/phpstan-src/actions/runs/26278594657/job/77349482802?pr=5730 which means more tests have to be added
- Add tests/PHPStan/Rules/Properties/data/bug-14457.php to make lint exclusion list (PHP 8.4 property hooks syntax) - Change !$prototype->isAbstract()->yes() to $prototype->isAbstract()->no() in OverridingPropertyRule — equivalent for PhpPropertyReflection (always returns Yes or No), but killable by TrinaryLogicMutator since the reversed mutation (->yes()) is caught by the abstract-overriding-abstract test case Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Pushed. Here's what was done to address the review:
|
Summary
PHP forbids making a non-abstract method abstract in a child class (it's a fatal error), but PHPStan did not report this. This PR adds the check in both
OverridingMethodRule(for regular methods and constructors) andOverridingPropertyRule(for property hooks).Changes
src/Rules/Methods/OverridingMethodRule.php: Added abstract-overriding-non-abstract check in two places:$prototypeData === nullpath, sinceMethodPrototypeFinderintentionally skips non-abstract constructor prototypessrc/Rules/Properties/OverridingPropertyRule.php: Added per-hook abstract-overriding-non-abstract check within thesupportsPropertyHooks()block. When a child property is declaredabstractand the prototype property has concrete hooks, each matching hook type is reported individually (matching PHP's per-hook error behavior).->nonIgnorable()as instructed in the issue comments.method.abstractOverridingNonAbstractandproperty.abstractOverridingNonAbstractHookRoot cause
OverridingMethodRulechecked for final methods, static/non-static mismatches, visibility changes, parameter contravariance, and return type covariance — but never checked whether an abstract method was trying to override a non-abstract one. The same gap existed inOverridingPropertyRulefor property hooks.Analogous cases probed
MethodPrototypeFinderskips non-abstract constructor prototypes (by design, for signature compatibility), so the check was added separately in the constructor handling branch. ✅ Fixedpublic int $x;to be overridden byabstract public int $x { get; }— no error needed. ✅ Verified (no fix needed)Test
tests/PHPStan/Rules/Methods/data/bug-14457.php— Regression test for abstract method overriding non-abstract, covering: basic case, static methods, protected methods, multi-level inheritance, constructors, and OK cases (abstract→abstract, concrete→concrete, concrete→abstract).tests/PHPStan/Rules/Properties/data/bug-14457.php— Regression test for abstract property hooks overriding non-abstract hooks, covering: get hook, set hook, both hooks, and OK cases (abstract→abstract, concrete→abstract, concrete→concrete).Fixes phpstan/phpstan#14457