diff --git a/rules.neon b/rules.neon index e737eaa8..dd517bd3 100644 --- a/rules.neon +++ b/rules.neon @@ -20,6 +20,7 @@ rules: - PHPStan\Rules\DisallowedConstructs\DisallowedImplicitArrayCreationRule - PHPStan\Rules\DisallowedConstructs\DisallowedShortTernaryRule - PHPStan\Rules\ForeachLoop\OverwriteVariablesWithForeachRule + - PHPStan\Rules\Methods\MethodVisibilityOverrideRule - PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule - PHPStan\Rules\Operators\OperandInArithmeticPostDecrementRule - PHPStan\Rules\Operators\OperandInArithmeticPostIncrementRule diff --git a/src/Rules/Methods/MethodVisibilityOverrideRule.php b/src/Rules/Methods/MethodVisibilityOverrideRule.php new file mode 100644 index 00000000..91fbe6c2 --- /dev/null +++ b/src/Rules/Methods/MethodVisibilityOverrideRule.php @@ -0,0 +1,59 @@ + + */ +class MethodVisibilityOverrideRule implements Rule +{ + + public function getNodeType(): string + { + return InClassMethodNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $methodReflection = $scope->getFunction(); + if (!$methodReflection instanceof MethodReflection) { + return []; + } + + $methodName = $methodReflection->getName(); + if (strtolower($methodName) === '__construct') { + return []; + } + + $declaringClass = $methodReflection->getDeclaringClass(); + $parentClass = $declaringClass->getParentClass(); + + if ($parentClass === false) { + return []; + } + + if (!$parentClass->hasNativeMethod($methodName)) { + return []; + } + + $parentMethodReflection = $parentClass->getNativeMethod($methodName); + + if (!$parentMethodReflection->isPrivate() && !$parentMethodReflection->isPublic() && $methodReflection->isPublic()) { + $message = sprintf( + 'Method %s::%s() overrides visibility from protected to public', + $declaringClass->getDisplayName(), + $methodName, + ); + return [$message]; + } + + return []; + } + +} diff --git a/tests/Rules/Methods/MethodVisibilityOverrideRuleTest.php b/tests/Rules/Methods/MethodVisibilityOverrideRuleTest.php new file mode 100644 index 00000000..4e234ce4 --- /dev/null +++ b/tests/Rules/Methods/MethodVisibilityOverrideRuleTest.php @@ -0,0 +1,27 @@ +analyse([__DIR__ . '/data/visibility-override.php'], [ + [ + 'Method MethodVisibilityOverride\\SubClass::foo3() overrides visibility from protected to public', + 63, + ], + [ + 'Method MethodVisibilityOverride\\OtherSubSubClass::foo3() overrides visibility from protected to public', + 93, + ], + ]); + } + +} diff --git a/tests/Rules/Methods/data/visibility-override.php b/tests/Rules/Methods/data/visibility-override.php new file mode 100644 index 00000000..64d58780 --- /dev/null +++ b/tests/Rules/Methods/data/visibility-override.php @@ -0,0 +1,98 @@ +