diff --git a/build/PHPStan/Build/FinalClassRule.php b/build/PHPStan/Build/FinalClassRule.php new file mode 100644 index 0000000000..c094aadda6 --- /dev/null +++ b/build/PHPStan/Build/FinalClassRule.php @@ -0,0 +1,64 @@ + + */ +final class FinalClassRule implements Rule +{ + + public function getNodeType(): string + { + return InClassNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $classReflection = $node->getClassReflection(); + if (!$classReflection->isClass()) { + return []; + } + if ($classReflection->isAbstract()) { + return []; + } + if ($classReflection->isFinal()) { + return []; + } + if ($classReflection->isSubclassOf(Type::class)) { + return []; + } + + // exceptions + if (in_array($classReflection->getName(), [ + FunctionVariant::class, + FunctionVariantWithPhpDocs::class, + DummyParameter::class, + PhpFunctionFromParserNodeReflection::class, + ], true)) { + return []; + } + + return [ + RuleErrorBuilder::message( + sprintf('Class %s must be abstract or final.', $classReflection->getDisplayName()), + ) + ->identifier('phpstan.finalClass') + ->build(), + ]; + } + +} diff --git a/build/phpstan.neon b/build/phpstan.neon index 63e9a82ace..bfb9493112 100644 --- a/build/phpstan.neon +++ b/build/phpstan.neon @@ -9,6 +9,7 @@ includes: - ../phpstan-baseline.php - ignore-by-php-version.neon.php - ignore-by-architecture.neon.php + parameters: level: 8 paths: @@ -98,6 +99,9 @@ parameters: - stubs/NetteDIContainer.stub - stubs/PhpParserName.stub +rules: + - PHPStan\Build\FinalClassRule + services: - class: PHPStan\Build\ServiceLocatorDynamicReturnTypeExtension