From 606ac75a5f3b9dc93ddeb248adaa1de3348061f2 Mon Sep 17 00:00:00 2001 From: Dawid Parafinski Date: Fri, 10 Oct 2025 13:52:44 +0200 Subject: [PATCH 1/5] Added rule to enforce interfaces usage --- .gitignore | 6 ++ rules/RequireInterfaceInDependenciesRule.php | 79 +++++++++++++++++++ .../Dependencies/ClassWithoutInterface.php | 17 ++++ .../Fixtures/Dependencies/ConcreteClass.php | 17 ++++ .../Fixtures/Dependencies/TestInterface.php | 14 ++++ .../RequireInterfaceInDependenciesFixture.php | 51 ++++++++++++ ...RequireInterfaceInDependenciesRuleTest.php | 43 ++++++++++ 7 files changed, 227 insertions(+) create mode 100644 .gitignore create mode 100644 rules/RequireInterfaceInDependenciesRule.php create mode 100644 tests/rules/Fixtures/Dependencies/ClassWithoutInterface.php create mode 100644 tests/rules/Fixtures/Dependencies/ConcreteClass.php create mode 100644 tests/rules/Fixtures/Dependencies/TestInterface.php create mode 100644 tests/rules/Fixtures/RequireInterfaceInDependenciesFixture.php create mode 100644 tests/rules/RequireInterfaceInDependenciesRuleTest.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b04fa3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/vendor +/phpunit.xml +/.php_cs.cache +composer.lock +.php-cs-fixer.cache +.phpunit.result.cache diff --git a/rules/RequireInterfaceInDependenciesRule.php b/rules/RequireInterfaceInDependenciesRule.php new file mode 100644 index 0000000..4973ae1 --- /dev/null +++ b/rules/RequireInterfaceInDependenciesRule.php @@ -0,0 +1,79 @@ + + */ +final class RequireInterfaceInDependenciesRule implements Rule +{ + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $errors = []; + + if (!$node->params) { + return []; + } + + foreach ($node->params as $param) { + + if (!$param->type instanceof Node\Name) { + continue; + } + if ($param->var instanceof Error) { + continue; + } + $typeName = $param->type->toString(); + + // Skip built-in types and primitives + if ($this->isBuiltInType($typeName)) { + continue; + } + + if (!interface_exists($typeName) && class_exists($typeName)) { + // Check if this class implements any interface + $interfaces = class_implements($typeName); + + if (!empty($interfaces)) { + $errors[] = RuleErrorBuilder::message( + sprintf( + 'Parameter $%s uses concrete class %s instead of an interface. Available interfaces: %s', + is_string($param->var->name) ? $param->var->name : $param->var->name->getType(), + $typeName, + implode(', ', $interfaces) + ) + )->build(); + } + } + } + + return $errors; + } + + private function isBuiltInType(string $type): bool + { + $builtInTypes = [ + 'string', 'int', 'float', 'bool', 'array', 'object', + 'callable', 'iterable', 'mixed', 'void', 'never', + ]; + + return in_array(strtolower($type), $builtInTypes); + } +} diff --git a/tests/rules/Fixtures/Dependencies/ClassWithoutInterface.php b/tests/rules/Fixtures/Dependencies/ClassWithoutInterface.php new file mode 100644 index 0000000..8f66616 --- /dev/null +++ b/tests/rules/Fixtures/Dependencies/ClassWithoutInterface.php @@ -0,0 +1,17 @@ +concreteClass = $concreteClass; + $this->testInterface = $testInterface; + $this->classWithoutInterface = $classWithoutInterface; + } + + public function methodWithConcreteClass(ConcreteClass $class): void + { + } + + public function methodWithInterface(TestInterface $interface): void + { + } + + public function methodWithoutInterface(ClassWithoutInterface $class): void + { + } + + public function methodWithBuiltInTypes(string $str, int $num): void + { + } +} diff --git a/tests/rules/RequireInterfaceInDependenciesRuleTest.php b/tests/rules/RequireInterfaceInDependenciesRuleTest.php new file mode 100644 index 0000000..3e6497f --- /dev/null +++ b/tests/rules/RequireInterfaceInDependenciesRuleTest.php @@ -0,0 +1,43 @@ + + */ +final class RequireInterfaceInDependenciesRuleTest extends RuleTestCase +{ + protected function getRule(): Rule + { + return new RequireInterfaceInDependenciesRule(); + } + + public function testRule(): void + { + $this->analyse( + [ + __DIR__ . '/Fixtures/RequireInterfaceInDependenciesFixture.php', + ], + [ + [ + 'Parameter $concreteClass uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\TestInterface', + 21, + ], + [ + 'Parameter $class uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\TestInterface', + 31, + ], + ] + ); + } +} From 885057424bac763ac1b7b2183341d1ab78558b99 Mon Sep 17 00:00:00 2001 From: Dawid Parafinski Date: Fri, 10 Oct 2025 14:19:39 +0200 Subject: [PATCH 2/5] Added rule to use proper suffix/prefix --- extension.neon | 2 + phpstan-baseline.neon | 16 ++++ phpstan.neon | 3 + rules/NamingConventionRule.php | 75 +++++++++++++++++++ rules/RequireInterfaceInDependenciesRule.php | 1 - .../Fixtures/NamingConventionFixture.php | 33 ++++++++ .../RequireInterfaceInDependenciesFixture.php | 3 - tests/rules/NamingConventionRuleTest.php | 47 ++++++++++++ ...RequireInterfaceInDependenciesRuleTest.php | 4 +- 9 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 phpstan-baseline.neon create mode 100644 rules/NamingConventionRule.php create mode 100644 tests/rules/Fixtures/NamingConventionFixture.php create mode 100644 tests/rules/NamingConventionRuleTest.php diff --git a/extension.neon b/extension.neon index 80cf7ed..e77ccdd 100644 --- a/extension.neon +++ b/extension.neon @@ -7,3 +7,5 @@ parameters: - stubs/Money/MoneyParser.stub rules: - Ibexa\PHPStan\Rules\NoConfigResolverParametersInConstructorRule + - Ibexa\PHPStan\Rules\RequireInterfaceInDependenciesRule + - Ibexa\PHPStan\Rules\NamingConventionRule diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..0258184 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,16 @@ +parameters: + ignoreErrors: + - + message: "#^Property Ibexa\\\\Tests\\\\PHPStan\\\\Rules\\\\Fixtures\\\\RequireInterfaceInDependenciesFixture\\:\\:\\$classWithoutInterface is never read, only written\\.$#" + count: 1 + path: tests/rules/Fixtures/RequireInterfaceInDependenciesFixture.php + + - + message: "#^Property Ibexa\\\\Tests\\\\PHPStan\\\\Rules\\\\Fixtures\\\\RequireInterfaceInDependenciesFixture\\:\\:\\$concreteClass is never read, only written\\.$#" + count: 1 + path: tests/rules/Fixtures/RequireInterfaceInDependenciesFixture.php + + - + message: "#^Property Ibexa\\\\Tests\\\\PHPStan\\\\Rules\\\\Fixtures\\\\RequireInterfaceInDependenciesFixture\\:\\:\\$testInterface is never read, only written\\.$#" + count: 1 + path: tests/rules/Fixtures/RequireInterfaceInDependenciesFixture.php diff --git a/phpstan.neon b/phpstan.neon index ab3d432..c4d75b1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,6 @@ +includes: + - phpstan-baseline.neon + parameters: level: 8 paths: diff --git a/rules/NamingConventionRule.php b/rules/NamingConventionRule.php new file mode 100644 index 0000000..70ccb2a --- /dev/null +++ b/rules/NamingConventionRule.php @@ -0,0 +1,75 @@ + + */ +final class NamingConventionRule implements Rule +{ + public function getNodeType(): string + { + return Node\Stmt\ClassLike::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$this->isRelevantNode($node)) { + return []; + } + + if ($node->name === null) { + return []; + } + + $className = $node->name->toString(); + $errors = []; + + if ($node instanceof Node\Stmt\Interface_ && substr($className, -9) !== 'Interface') { + $errors[] = RuleErrorBuilder::message( + sprintf( + 'Interface "%s" should have "Interface" suffix', + $className + ) + )->build(); + } + + if ($node instanceof Node\Stmt\Trait_ && substr($className, -5) !== 'Trait') { + $errors[] = RuleErrorBuilder::message( + sprintf( + 'Trait "%s" should have "Trait" suffix', + $className + ) + )->build(); + } + + if ($node instanceof Node\Stmt\Class_ && $node->isAbstract() && strpos($className, 'Abstract') !== 0) { + $errors[] = RuleErrorBuilder::message( + sprintf( + 'Abstract class "%s" should have "Abstract" prefix', + $className + ) + )->build(); + } + + return $errors; + } + + private function isRelevantNode(Node $node): bool + { + return $node instanceof Node\Stmt\Interface_ + || $node instanceof Node\Stmt\Trait_ + || ($node instanceof Node\Stmt\Class_ && $node->isAbstract()); + } +} diff --git a/rules/RequireInterfaceInDependenciesRule.php b/rules/RequireInterfaceInDependenciesRule.php index 4973ae1..8499d31 100644 --- a/rules/RequireInterfaceInDependenciesRule.php +++ b/rules/RequireInterfaceInDependenciesRule.php @@ -33,7 +33,6 @@ public function processNode(Node $node, Scope $scope): array } foreach ($node->params as $param) { - if (!$param->type instanceof Node\Name) { continue; } diff --git a/tests/rules/Fixtures/NamingConventionFixture.php b/tests/rules/Fixtures/NamingConventionFixture.php new file mode 100644 index 0000000..237f0bb --- /dev/null +++ b/tests/rules/Fixtures/NamingConventionFixture.php @@ -0,0 +1,33 @@ + + */ +final class NamingConventionRuleTest extends RuleTestCase +{ + protected function getRule(): Rule + { + return new NamingConventionRule(); + } + + public function testRule(): void + { + $this->analyse( + [ + __DIR__ . '/Fixtures/NamingConventionFixture.php', + ], + [ + [ + 'Interface "WrongName" should have "Interface" suffix', + 11, + ], + [ + 'Trait "SimpleThing" should have "Trait" suffix', + 19, + ], + [ + 'Abstract class "SimpleClass" should have "Abstract" prefix', + 27, + ], + ] + ); + } +} diff --git a/tests/rules/RequireInterfaceInDependenciesRuleTest.php b/tests/rules/RequireInterfaceInDependenciesRuleTest.php index 3e6497f..cdeb4bc 100644 --- a/tests/rules/RequireInterfaceInDependenciesRuleTest.php +++ b/tests/rules/RequireInterfaceInDependenciesRuleTest.php @@ -31,11 +31,11 @@ public function testRule(): void [ [ 'Parameter $concreteClass uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\TestInterface', - 21, + 23, ], [ 'Parameter $class uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\TestInterface', - 31, + 33, ], ] ); From 8f8cfa32fde366956868d65cf6fa952cd7631d9a Mon Sep 17 00:00:00 2001 From: Dawid Parafinski Date: Fri, 10 Oct 2025 15:40:12 +0200 Subject: [PATCH 3/5] Added rule for final class --- extension.neon | 1 + rules/FinalClassRule.php | 77 +++++++++++++++++++ tests/rules/FinalClassRuleTest.php | 53 +++++++++++++ tests/rules/Fixtures/FinalClassFixture.php | 19 +++++ .../Fixtures/FinalRule/AbstractClass.php | 11 +++ tests/rules/Fixtures/FinalRule/FinalClass.php | 11 +++ .../Fixtures/FinalRule/NonFinalClass.php | 11 +++ .../Fixtures/FinalRule/SomeInterface.php | 11 +++ tests/rules/Fixtures/FinalRule/SomeTrait.php | 11 +++ 9 files changed, 205 insertions(+) create mode 100644 rules/FinalClassRule.php create mode 100644 tests/rules/FinalClassRuleTest.php create mode 100644 tests/rules/Fixtures/FinalClassFixture.php create mode 100644 tests/rules/Fixtures/FinalRule/AbstractClass.php create mode 100644 tests/rules/Fixtures/FinalRule/FinalClass.php create mode 100644 tests/rules/Fixtures/FinalRule/NonFinalClass.php create mode 100644 tests/rules/Fixtures/FinalRule/SomeInterface.php create mode 100644 tests/rules/Fixtures/FinalRule/SomeTrait.php diff --git a/extension.neon b/extension.neon index e77ccdd..62e17e7 100644 --- a/extension.neon +++ b/extension.neon @@ -9,3 +9,4 @@ rules: - Ibexa\PHPStan\Rules\NoConfigResolverParametersInConstructorRule - Ibexa\PHPStan\Rules\RequireInterfaceInDependenciesRule - Ibexa\PHPStan\Rules\NamingConventionRule + - Ibexa\PHPStan\Rules\FinalClassRule diff --git a/rules/FinalClassRule.php b/rules/FinalClassRule.php new file mode 100644 index 0000000..300e826 --- /dev/null +++ b/rules/FinalClassRule.php @@ -0,0 +1,77 @@ + + */ +final class FinalClassRule implements Rule +{ + private ReflectionProvider $reflectionProvider; + + public function __construct( + ReflectionProvider $reflectionProvider + ) { + $this->reflectionProvider = $reflectionProvider; + } + + public function getNodeType(): string + { + return Node\Stmt\Class_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + // Skip anonymous classes + if (!isset($node->namespacedName)) { + return []; + } + + $className = $node->namespacedName->toString(); + + if (!$this->reflectionProvider->hasClass($className)) { + return []; + } + + $reflection = $this->reflectionProvider->getClass($className); + + // Skip if already final + if ($reflection->isFinal()) { + return []; + } + + // Skip if abstract (abstract classes shouldn't be final) + if ($reflection->isAbstract()) { + return []; + } + + // Skip interfaces and traits + if ($reflection->isInterface() || $reflection->isTrait()) { + return []; + } + + return [ + RuleErrorBuilder::message( + sprintf( + 'Class %s is not final. All non-abstract classes should be final.', + $reflection->getName() + ) + ) + ->identifier('class.notFinal') + ->tip('Add "final" keyword to the class declaration.') + ->build() + ]; + } +} diff --git a/tests/rules/FinalClassRuleTest.php b/tests/rules/FinalClassRuleTest.php new file mode 100644 index 0000000..7d0ebda --- /dev/null +++ b/tests/rules/FinalClassRuleTest.php @@ -0,0 +1,53 @@ + + */ +final class FinalClassRuleTest extends RuleTestCase +{ + protected function getRule(): Rule + { + return new FinalClassRule($this->createReflectionProvider()); + } + + public function testRule(): void + { + $this->analyse( + [ + __DIR__ . '/Fixtures/FinalRule/NonFinalClass.php', + ], + [ + [ + 'Class Ibexa\Tests\PHPStan\Rules\Fixtures\FinalRule\NonFinalClass is not final. All non-abstract classes should be final.', + 11, + 'Add "final" keyword to the class declaration.', + ], + ] + ); + } + + public function testNoErrorsOnFinalAndAbstractClassesAndInterfaces(): void + { + $this->analyse( + [ + __DIR__ . '/Fixtures/FinalRule/FinalClass.php', + __DIR__ . '/Fixtures/FinalRule/AbstractClass.php', + __DIR__ . '/Fixtures/FinalRule/SomeInterface.php', + __DIR__ . '/Fixtures/FinalRule/SomeTrait.php', + ], + [] + ); + } +} diff --git a/tests/rules/Fixtures/FinalClassFixture.php b/tests/rules/Fixtures/FinalClassFixture.php new file mode 100644 index 0000000..fe61afc --- /dev/null +++ b/tests/rules/Fixtures/FinalClassFixture.php @@ -0,0 +1,19 @@ + Date: Fri, 10 Oct 2025 15:50:18 +0200 Subject: [PATCH 4/5] cleanup some names --- rules/FinalClassRule.php | 4 +-- tests/rules/FinalClassRuleTest.php | 12 +++---- .../AbstractClass.php | 6 ++-- .../{FinalRule => FinalClass}/FinalClass.php | 6 ++-- .../NonFinalClass.php | 6 ++-- .../SomeInterface.php | 6 ++-- .../{FinalRule => FinalClass}/SomeTrait.php | 6 ++-- tests/rules/Fixtures/FinalClassFixture.php | 19 ----------- .../NamingConvention/AbstractCorrectClass.php | 13 ++++++++ .../NamingConvention/CorrectNameInterface.php | 13 ++++++++ .../NamingConvention/CorrectNameTrait.php | 13 ++++++++ .../Fixtures/NamingConvention/SimpleClass.php | 13 ++++++++ .../Fixtures/NamingConvention/SimpleThing.php | 13 ++++++++ .../Fixtures/NamingConvention/WrongName.php | 13 ++++++++ .../Fixtures/NamingConventionFixture.php | 33 ------------------- .../ClassWithoutInterface.php | 2 +- .../ConcreteClass.php | 2 +- .../TestInterface.php | 2 +- .../RequireInterfaceInDependenciesFixture.php | 6 ++-- tests/rules/NamingConventionRuleTest.php | 11 +++++-- ...RequireInterfaceInDependenciesRuleTest.php | 4 +-- 21 files changed, 122 insertions(+), 81 deletions(-) rename tests/rules/Fixtures/{FinalRule => FinalClass}/AbstractClass.php (69%) rename tests/rules/Fixtures/{FinalRule => FinalClass}/FinalClass.php (71%) rename tests/rules/Fixtures/{FinalRule => FinalClass}/NonFinalClass.php (72%) rename tests/rules/Fixtures/{FinalRule => FinalClass}/SomeInterface.php (71%) rename tests/rules/Fixtures/{FinalRule => FinalClass}/SomeTrait.php (73%) delete mode 100644 tests/rules/Fixtures/FinalClassFixture.php create mode 100644 tests/rules/Fixtures/NamingConvention/AbstractCorrectClass.php create mode 100644 tests/rules/Fixtures/NamingConvention/CorrectNameInterface.php create mode 100644 tests/rules/Fixtures/NamingConvention/CorrectNameTrait.php create mode 100644 tests/rules/Fixtures/NamingConvention/SimpleClass.php create mode 100644 tests/rules/Fixtures/NamingConvention/SimpleThing.php create mode 100644 tests/rules/Fixtures/NamingConvention/WrongName.php delete mode 100644 tests/rules/Fixtures/NamingConventionFixture.php rename tests/rules/Fixtures/{Dependencies => RequireInterfaceInDependencies}/ClassWithoutInterface.php (80%) rename tests/rules/Fixtures/{Dependencies => RequireInterfaceInDependencies}/ConcreteClass.php (81%) rename tests/rules/Fixtures/{Dependencies => RequireInterfaceInDependencies}/TestInterface.php (78%) diff --git a/rules/FinalClassRule.php b/rules/FinalClassRule.php index 300e826..962cb9b 100644 --- a/rules/FinalClassRule.php +++ b/rules/FinalClassRule.php @@ -10,9 +10,9 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\Reflection\ReflectionProvider; /** * @implements \PHPStan\Rules\Rule<\PhpParser\Node\Stmt\Class_> @@ -71,7 +71,7 @@ public function processNode(Node $node, Scope $scope): array ) ->identifier('class.notFinal') ->tip('Add "final" keyword to the class declaration.') - ->build() + ->build(), ]; } } diff --git a/tests/rules/FinalClassRuleTest.php b/tests/rules/FinalClassRuleTest.php index 7d0ebda..6d91f24 100644 --- a/tests/rules/FinalClassRuleTest.php +++ b/tests/rules/FinalClassRuleTest.php @@ -26,11 +26,11 @@ public function testRule(): void { $this->analyse( [ - __DIR__ . '/Fixtures/FinalRule/NonFinalClass.php', + __DIR__ . '/Fixtures/FinalClass/NonFinalClass.php', ], [ [ - 'Class Ibexa\Tests\PHPStan\Rules\Fixtures\FinalRule\NonFinalClass is not final. All non-abstract classes should be final.', + 'Class Ibexa\Tests\PHPStan\Rules\Fixtures\FinalClass\NonFinalClass is not final. All non-abstract classes should be final.', 11, 'Add "final" keyword to the class declaration.', ], @@ -42,10 +42,10 @@ public function testNoErrorsOnFinalAndAbstractClassesAndInterfaces(): void { $this->analyse( [ - __DIR__ . '/Fixtures/FinalRule/FinalClass.php', - __DIR__ . '/Fixtures/FinalRule/AbstractClass.php', - __DIR__ . '/Fixtures/FinalRule/SomeInterface.php', - __DIR__ . '/Fixtures/FinalRule/SomeTrait.php', + __DIR__ . '/Fixtures/FinalClass/FinalClass.php', + __DIR__ . '/Fixtures/FinalClass/AbstractClass.php', + __DIR__ . '/Fixtures/FinalClass/SomeInterface.php', + __DIR__ . '/Fixtures/FinalClass/SomeTrait.php', ], [] ); diff --git a/tests/rules/Fixtures/FinalRule/AbstractClass.php b/tests/rules/Fixtures/FinalClass/AbstractClass.php similarity index 69% rename from tests/rules/Fixtures/FinalRule/AbstractClass.php rename to tests/rules/Fixtures/FinalClass/AbstractClass.php index 0ad44df..39ee675 100644 --- a/tests/rules/Fixtures/FinalRule/AbstractClass.php +++ b/tests/rules/Fixtures/FinalClass/AbstractClass.php @@ -6,6 +6,8 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalRule; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalClass; -abstract class AbstractClass {} +abstract class AbstractClass +{ +} diff --git a/tests/rules/Fixtures/FinalRule/FinalClass.php b/tests/rules/Fixtures/FinalClass/FinalClass.php similarity index 71% rename from tests/rules/Fixtures/FinalRule/FinalClass.php rename to tests/rules/Fixtures/FinalClass/FinalClass.php index c84dcc4..a521ad5 100644 --- a/tests/rules/Fixtures/FinalRule/FinalClass.php +++ b/tests/rules/Fixtures/FinalClass/FinalClass.php @@ -6,6 +6,8 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalRule; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalClass; -final class FinalClass {} +final class FinalClass +{ +} diff --git a/tests/rules/Fixtures/FinalRule/NonFinalClass.php b/tests/rules/Fixtures/FinalClass/NonFinalClass.php similarity index 72% rename from tests/rules/Fixtures/FinalRule/NonFinalClass.php rename to tests/rules/Fixtures/FinalClass/NonFinalClass.php index f18dd99..fa997b8 100644 --- a/tests/rules/Fixtures/FinalRule/NonFinalClass.php +++ b/tests/rules/Fixtures/FinalClass/NonFinalClass.php @@ -6,6 +6,8 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalRule; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalClass; -class NonFinalClass {} +class NonFinalClass +{ +} diff --git a/tests/rules/Fixtures/FinalRule/SomeInterface.php b/tests/rules/Fixtures/FinalClass/SomeInterface.php similarity index 71% rename from tests/rules/Fixtures/FinalRule/SomeInterface.php rename to tests/rules/Fixtures/FinalClass/SomeInterface.php index 4c0bd70..783c0f9 100644 --- a/tests/rules/Fixtures/FinalRule/SomeInterface.php +++ b/tests/rules/Fixtures/FinalClass/SomeInterface.php @@ -6,6 +6,8 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalRule; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalClass; -interface SomeInterface {} +interface SomeInterface +{ +} diff --git a/tests/rules/Fixtures/FinalRule/SomeTrait.php b/tests/rules/Fixtures/FinalClass/SomeTrait.php similarity index 73% rename from tests/rules/Fixtures/FinalRule/SomeTrait.php rename to tests/rules/Fixtures/FinalClass/SomeTrait.php index cb7b889..2845579 100644 --- a/tests/rules/Fixtures/FinalRule/SomeTrait.php +++ b/tests/rules/Fixtures/FinalClass/SomeTrait.php @@ -6,6 +6,8 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalRule; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\FinalClass; -trait SomeTrait {} +trait SomeTrait +{ +} diff --git a/tests/rules/Fixtures/FinalClassFixture.php b/tests/rules/Fixtures/FinalClassFixture.php deleted file mode 100644 index fe61afc..0000000 --- a/tests/rules/Fixtures/FinalClassFixture.php +++ /dev/null @@ -1,19 +0,0 @@ -analyse( [ - __DIR__ . '/Fixtures/NamingConventionFixture.php', + __DIR__ . '/Fixtures/NamingConvention/WrongName.php', + __DIR__ . '/Fixtures/NamingConvention/SimpleThing.php', + __DIR__ . '/Fixtures/NamingConvention/SimpleClass.php', + __DIR__ . '/Fixtures/NamingConvention/CorrectNameInterface.php', + __DIR__ . '/Fixtures/NamingConvention/CorrectNameTrait.php', + __DIR__ . '/Fixtures/NamingConvention/AbstractCorrectClass.php', ], [ [ @@ -35,11 +40,11 @@ public function testRule(): void ], [ 'Trait "SimpleThing" should have "Trait" suffix', - 19, + 11, ], [ 'Abstract class "SimpleClass" should have "Abstract" prefix', - 27, + 11, ], ] ); diff --git a/tests/rules/RequireInterfaceInDependenciesRuleTest.php b/tests/rules/RequireInterfaceInDependenciesRuleTest.php index cdeb4bc..13bdff2 100644 --- a/tests/rules/RequireInterfaceInDependenciesRuleTest.php +++ b/tests/rules/RequireInterfaceInDependenciesRuleTest.php @@ -30,11 +30,11 @@ public function testRule(): void ], [ [ - 'Parameter $concreteClass uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\TestInterface', + 'Parameter $concreteClass uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\RequireInterfaceInDependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\RequireInterfaceInDependencies\TestInterface', 23, ], [ - 'Parameter $class uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\Dependencies\TestInterface', + 'Parameter $class uses concrete class Ibexa\Tests\PHPStan\Rules\Fixtures\RequireInterfaceInDependencies\ConcreteClass instead of an interface. Available interfaces: Ibexa\Tests\PHPStan\Rules\Fixtures\RequireInterfaceInDependencies\TestInterface', 33, ], ] From e2e0a923d18fc15b13025a7f4d3c0c980b934253 Mon Sep 17 00:00:00 2001 From: Dawid Parafinski Date: Mon, 13 Oct 2025 08:41:46 +0200 Subject: [PATCH 5/5] Renamed NamingConventionRule to ClassTypeNamingRule --- extension.neon | 2 +- ...entionRule.php => ClassTypeNamingRule.php} | 2 +- ...leTest.php => ClassTypeNamingRuleTest.php} | 20 +++++++++---------- .../AbstractCorrectClass.php | 2 +- .../CorrectNameInterface.php | 2 +- .../CorrectNameTrait.php | 2 +- .../SimpleClass.php | 2 +- .../SimpleThing.php | 2 +- .../WrongName.php | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) rename rules/{NamingConventionRule.php => ClassTypeNamingRule.php} (97%) rename tests/rules/{NamingConventionRuleTest.php => ClassTypeNamingRuleTest.php} (57%) rename tests/rules/Fixtures/{NamingConvention => ClassTypeNaming}/AbstractCorrectClass.php (79%) rename tests/rules/Fixtures/{NamingConvention => ClassTypeNaming}/CorrectNameInterface.php (79%) rename tests/rules/Fixtures/{NamingConvention => ClassTypeNaming}/CorrectNameTrait.php (78%) rename tests/rules/Fixtures/{NamingConvention => ClassTypeNaming}/SimpleClass.php (79%) rename tests/rules/Fixtures/{NamingConvention => ClassTypeNaming}/SimpleThing.php (78%) rename tests/rules/Fixtures/{NamingConvention => ClassTypeNaming}/WrongName.php (78%) diff --git a/extension.neon b/extension.neon index 62e17e7..edf79e3 100644 --- a/extension.neon +++ b/extension.neon @@ -8,5 +8,5 @@ parameters: rules: - Ibexa\PHPStan\Rules\NoConfigResolverParametersInConstructorRule - Ibexa\PHPStan\Rules\RequireInterfaceInDependenciesRule - - Ibexa\PHPStan\Rules\NamingConventionRule + - Ibexa\PHPStan\Rules\ClassTypeNamingRule - Ibexa\PHPStan\Rules\FinalClassRule diff --git a/rules/NamingConventionRule.php b/rules/ClassTypeNamingRule.php similarity index 97% rename from rules/NamingConventionRule.php rename to rules/ClassTypeNamingRule.php index 70ccb2a..c259fab 100644 --- a/rules/NamingConventionRule.php +++ b/rules/ClassTypeNamingRule.php @@ -16,7 +16,7 @@ /** * @implements \PHPStan\Rules\Rule<\PhpParser\Node\Stmt\ClassLike> */ -final class NamingConventionRule implements Rule +final class ClassTypeNamingRule implements Rule { public function getNodeType(): string { diff --git a/tests/rules/NamingConventionRuleTest.php b/tests/rules/ClassTypeNamingRuleTest.php similarity index 57% rename from tests/rules/NamingConventionRuleTest.php rename to tests/rules/ClassTypeNamingRuleTest.php index 7a6724f..507f757 100644 --- a/tests/rules/NamingConventionRuleTest.php +++ b/tests/rules/ClassTypeNamingRuleTest.php @@ -8,30 +8,30 @@ namespace Ibexa\Tests\PHPStan\Rules; -use Ibexa\PHPStan\Rules\NamingConventionRule; +use Ibexa\PHPStan\Rules\ClassTypeNamingRule; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; /** - * @extends \PHPStan\Testing\RuleTestCase<\Ibexa\PHPStan\Rules\NamingConventionRule> + * @extends \PHPStan\Testing\RuleTestCase<\Ibexa\PHPStan\Rules\ClassTypeNamingRule> */ -final class NamingConventionRuleTest extends RuleTestCase +final class ClassTypeNamingRuleTest extends RuleTestCase { protected function getRule(): Rule { - return new NamingConventionRule(); + return new ClassTypeNamingRule(); } public function testRule(): void { $this->analyse( [ - __DIR__ . '/Fixtures/NamingConvention/WrongName.php', - __DIR__ . '/Fixtures/NamingConvention/SimpleThing.php', - __DIR__ . '/Fixtures/NamingConvention/SimpleClass.php', - __DIR__ . '/Fixtures/NamingConvention/CorrectNameInterface.php', - __DIR__ . '/Fixtures/NamingConvention/CorrectNameTrait.php', - __DIR__ . '/Fixtures/NamingConvention/AbstractCorrectClass.php', + __DIR__ . '/Fixtures/ClassTypeNaming/WrongName.php', + __DIR__ . '/Fixtures/ClassTypeNaming/SimpleThing.php', + __DIR__ . '/Fixtures/ClassTypeNaming/SimpleClass.php', + __DIR__ . '/Fixtures/ClassTypeNaming/CorrectNameInterface.php', + __DIR__ . '/Fixtures/ClassTypeNaming/CorrectNameTrait.php', + __DIR__ . '/Fixtures/ClassTypeNaming/AbstractCorrectClass.php', ], [ [ diff --git a/tests/rules/Fixtures/NamingConvention/AbstractCorrectClass.php b/tests/rules/Fixtures/ClassTypeNaming/AbstractCorrectClass.php similarity index 79% rename from tests/rules/Fixtures/NamingConvention/AbstractCorrectClass.php rename to tests/rules/Fixtures/ClassTypeNaming/AbstractCorrectClass.php index 37c4dd5..1a2f293 100644 --- a/tests/rules/Fixtures/NamingConvention/AbstractCorrectClass.php +++ b/tests/rules/Fixtures/ClassTypeNaming/AbstractCorrectClass.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\NamingConvention; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\ClassTypeNaming; abstract class AbstractCorrectClass { diff --git a/tests/rules/Fixtures/NamingConvention/CorrectNameInterface.php b/tests/rules/Fixtures/ClassTypeNaming/CorrectNameInterface.php similarity index 79% rename from tests/rules/Fixtures/NamingConvention/CorrectNameInterface.php rename to tests/rules/Fixtures/ClassTypeNaming/CorrectNameInterface.php index 408ec76..f81d426 100644 --- a/tests/rules/Fixtures/NamingConvention/CorrectNameInterface.php +++ b/tests/rules/Fixtures/ClassTypeNaming/CorrectNameInterface.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\NamingConvention; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\ClassTypeNaming; interface CorrectNameInterface { diff --git a/tests/rules/Fixtures/NamingConvention/CorrectNameTrait.php b/tests/rules/Fixtures/ClassTypeNaming/CorrectNameTrait.php similarity index 78% rename from tests/rules/Fixtures/NamingConvention/CorrectNameTrait.php rename to tests/rules/Fixtures/ClassTypeNaming/CorrectNameTrait.php index 2c87229..7ed6874 100644 --- a/tests/rules/Fixtures/NamingConvention/CorrectNameTrait.php +++ b/tests/rules/Fixtures/ClassTypeNaming/CorrectNameTrait.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\NamingConvention; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\ClassTypeNaming; trait CorrectNameTrait { diff --git a/tests/rules/Fixtures/NamingConvention/SimpleClass.php b/tests/rules/Fixtures/ClassTypeNaming/SimpleClass.php similarity index 79% rename from tests/rules/Fixtures/NamingConvention/SimpleClass.php rename to tests/rules/Fixtures/ClassTypeNaming/SimpleClass.php index 4498615..7ac16c2 100644 --- a/tests/rules/Fixtures/NamingConvention/SimpleClass.php +++ b/tests/rules/Fixtures/ClassTypeNaming/SimpleClass.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\NamingConvention; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\ClassTypeNaming; abstract class SimpleClass { diff --git a/tests/rules/Fixtures/NamingConvention/SimpleThing.php b/tests/rules/Fixtures/ClassTypeNaming/SimpleThing.php similarity index 78% rename from tests/rules/Fixtures/NamingConvention/SimpleThing.php rename to tests/rules/Fixtures/ClassTypeNaming/SimpleThing.php index 1398ca3..05d699a 100644 --- a/tests/rules/Fixtures/NamingConvention/SimpleThing.php +++ b/tests/rules/Fixtures/ClassTypeNaming/SimpleThing.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\NamingConvention; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\ClassTypeNaming; trait SimpleThing { diff --git a/tests/rules/Fixtures/NamingConvention/WrongName.php b/tests/rules/Fixtures/ClassTypeNaming/WrongName.php similarity index 78% rename from tests/rules/Fixtures/NamingConvention/WrongName.php rename to tests/rules/Fixtures/ClassTypeNaming/WrongName.php index b11f90d..1e826db 100644 --- a/tests/rules/Fixtures/NamingConvention/WrongName.php +++ b/tests/rules/Fixtures/ClassTypeNaming/WrongName.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Tests\PHPStan\Rules\Fixtures\NamingConvention; +namespace Ibexa\Tests\PHPStan\Rules\Fixtures\ClassTypeNaming; interface WrongName {