diff --git a/src/Rule/ForbidUselessNullableReturnRule.php b/src/Rule/ForbidUselessNullableReturnRule.php index 982080e..f741f07 100644 --- a/src/Rule/ForbidUselessNullableReturnRule.php +++ b/src/Rule/ForbidUselessNullableReturnRule.php @@ -6,6 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\ClosureReturnStatementsNode; use PHPStan\Node\ReturnStatementsNode; +use PHPStan\Reflection\MethodReflection; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -38,6 +39,10 @@ public function processNode( $verbosity = VerbosityLevel::precise(); $methodReflection = $scope->getFunction(); + if ($methodReflection instanceof MethodReflection && $this->isOverridable($methodReflection)) { + return []; + } + if ($node instanceof ClosureReturnStatementsNode) { $declaredType = $scope->getFunctionType($node->getClosureExpr()->getReturnType(), false, false); } elseif ($methodReflection !== null) { @@ -80,4 +85,9 @@ public function processNode( return []; } + private function isOverridable(MethodReflection $methodReflection): bool + { + return !$methodReflection->isFinal()->yes() && !$methodReflection->isPrivate() && !$methodReflection->isStatic() && !$methodReflection->getDeclaringClass()->isFinalByKeyword(); + } + } diff --git a/tests/Rule/data/ForbidUselessNullableReturnRule/code.php b/tests/Rule/data/ForbidUselessNullableReturnRule/code.php index e040520..22ecdd6 100644 --- a/tests/Rule/data/ForbidUselessNullableReturnRule/code.php +++ b/tests/Rule/data/ForbidUselessNullableReturnRule/code.php @@ -2,7 +2,7 @@ namespace ForbidUselessNullableReturnRule; -class ExampleClass { +final class ExampleClass { private ?int $foo; @@ -87,3 +87,30 @@ function nullableFunction(int $int): ?int // error: Declared return type int|nul $globalFn = static function (int $int): ?int { // error: Declared return type int|null contains null, but it is never returned. Returned types: int. return $int; }; + +class NonFinalClass { + public static function staticMethod(): ?int // error: Declared return type int|null contains null, but it is never returned. Returned types: 1. + { + return 1; + } + + final public function finalMethod(): ?int // error: Declared return type int|null contains null, but it is never returned. Returned types: 1. + { + return 1; + } + + private function privateMethod(): ?int // error: Declared return type int|null contains null, but it is never returned. Returned types: 1. + { + return 1; + } + + public function publicMethod(): ?int + { + return 1; + } + + protected function protectedMethod(): ?int + { + return 1; + } +}