diff --git a/config/code-complexity-rules.neon b/config/code-complexity-rules.neon index c006ee0d..367b5a6f 100644 --- a/config/code-complexity-rules.neon +++ b/config/code-complexity-rules.neon @@ -13,3 +13,8 @@ services: class: Symplify\PHPStanRules\Collector\ImplementedInterfaceCollector tags: - phpstan.collector + + - + class: Symplify\PHPStanRules\Collector\InterfaceOfAbstractClassCollector + tags: + - phpstan.collector diff --git a/config/services/services.neon b/config/services/services.neon index bf7650d1..4e150c7d 100644 --- a/config/services/services.neon +++ b/config/services/services.neon @@ -1,6 +1,4 @@ services: - - PhpParser\NodeFinder - - Symplify\PHPStanRules\NodeTraverser\SimpleCallableNodeTraverser - Symplify\PHPStanRules\PhpDocParser\PhpDocNodeTraverser - Symplify\PHPStanRules\Reflection\ReflectionParser diff --git a/src/Collector/InterfaceOfAbstractClassCollector.php b/src/Collector/InterfaceOfAbstractClassCollector.php new file mode 100644 index 00000000..7601fc82 --- /dev/null +++ b/src/Collector/InterfaceOfAbstractClassCollector.php @@ -0,0 +1,37 @@ +isAbstract()) { + return null; + } + + $interfaceNames = []; + + foreach ($node->implements as $implement) { + $interfaceNames[] = $implement->toString(); + } + + return $interfaceNames; + } +} diff --git a/src/NodeFinder/TypeAwareNodeFinder.php b/src/NodeFinder/TypeAwareNodeFinder.php index a90d7a44..e00a884f 100644 --- a/src/NodeFinder/TypeAwareNodeFinder.php +++ b/src/NodeFinder/TypeAwareNodeFinder.php @@ -12,9 +12,11 @@ */ final class TypeAwareNodeFinder { - public function __construct( - private readonly NodeFinder $nodeFinder - ) { + private readonly NodeFinder $nodeFinder; + + public function __construct() + { + $this->nodeFinder = new NodeFinder(); } /** diff --git a/src/Rules/ForbiddenMultipleClassLikeInOneFileRule.php b/src/Rules/ForbiddenMultipleClassLikeInOneFileRule.php index 3bec2ef9..19afa4d9 100644 --- a/src/Rules/ForbiddenMultipleClassLikeInOneFileRule.php +++ b/src/Rules/ForbiddenMultipleClassLikeInOneFileRule.php @@ -25,9 +25,11 @@ final class ForbiddenMultipleClassLikeInOneFileRule implements Rule, DocumentedR */ public const ERROR_MESSAGE = 'Multiple class/interface/trait is not allowed in single file'; + private readonly NodeFinder $nodeFinder; + public function __construct( - private readonly NodeFinder $nodeFinder ) { + $this->nodeFinder = new NodeFinder(); } /** diff --git a/src/Rules/NoSingleInterfaceImplementerRule.php b/src/Rules/NoSingleInterfaceImplementerRule.php index d1518720..95d9bd88 100644 --- a/src/Rules/NoSingleInterfaceImplementerRule.php +++ b/src/Rules/NoSingleInterfaceImplementerRule.php @@ -13,6 +13,7 @@ use PHPStan\Rules\RuleErrorBuilder; use Symplify\PHPStanRules\Collector\ImplementedInterfaceCollector; use Symplify\PHPStanRules\Collector\InterfaceCollector; +use Symplify\PHPStanRules\Collector\InterfaceOfAbstractClassCollector; use Symplify\RuleDocGenerator\Contract\DocumentedRuleInterface; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -45,10 +46,14 @@ public function processNode(Node $node, Scope $scope): array { $implementedInterfaces = Arrays::flatten($node->get(ImplementedInterfaceCollector::class)); $interfaces = Arrays::flatten($node->get(InterfaceCollector::class)); + $interfacesOfAbstractClass = Arrays::flatten($node->get(InterfaceOfAbstractClassCollector::class)); $onceUsedInterfaces = $this->resolveOnceUsedInterfaces($implementedInterfaces); - $onceImplementedInterfaces = array_intersect($onceUsedInterfaces, $interfaces); + + // remove the abstract class implemented, as required transitionally + $onceImplementedInterfaces = array_diff($onceImplementedInterfaces, $interfacesOfAbstractClass); + if ($onceImplementedInterfaces === []) { return []; } diff --git a/tests/Rules/NoSingleInterfaceImplementerRule/NoSingleInterfaceImplementerRuleTest.php b/tests/Rules/NoSingleInterfaceImplementerRule/NoSingleInterfaceImplementerRuleTest.php index 43e16165..42997cf7 100644 --- a/tests/Rules/NoSingleInterfaceImplementerRule/NoSingleInterfaceImplementerRuleTest.php +++ b/tests/Rules/NoSingleInterfaceImplementerRule/NoSingleInterfaceImplementerRuleTest.php @@ -10,6 +10,7 @@ use PHPUnit\Framework\Attributes\DataProvider; use Symplify\PHPStanRules\Collector\ImplementedInterfaceCollector; use Symplify\PHPStanRules\Collector\InterfaceCollector; +use Symplify\PHPStanRules\Collector\InterfaceOfAbstractClassCollector; use Symplify\PHPStanRules\Rules\NoSingleInterfaceImplementerRule; use Symplify\PHPStanRules\Tests\Rules\NoSingleInterfaceImplementerRule\Fixture\SimpleInterface; @@ -33,6 +34,9 @@ public static function provideData(): Iterator yield [[__DIR__ . '/Fixture/SimpleInterface.php'], []]; yield [[__DIR__ . '/Fixture/AllowAbstract.php', __DIR__ . '/Fixture/SimpleInterface.php'], []]; + // already counted in abstract class + yield [[__DIR__ . '/Fixture/AllowAbstract.php', __DIR__ . '/Fixture/SimpleInterface.php', __DIR__ . '/Fixture/ImplementsSimpleInterface.php'], []]; + yield [ [ __DIR__ . '/Fixture/SimpleInterface.php', @@ -58,6 +62,7 @@ protected function getCollectors(): array return [ self::getContainer()->getByType(ImplementedInterfaceCollector::class), self::getContainer()->getByType(InterfaceCollector::class), + self::getContainer()->getByType(InterfaceOfAbstractClassCollector::class), ]; } diff --git a/tests/Rules/NoSingleInterfaceImplementerRule/config/configured_rule.neon b/tests/Rules/NoSingleInterfaceImplementerRule/config/configured_rule.neon index 6ae757dd..3e4010b3 100644 --- a/tests/Rules/NoSingleInterfaceImplementerRule/config/configured_rule.neon +++ b/tests/Rules/NoSingleInterfaceImplementerRule/config/configured_rule.neon @@ -1,13 +1,3 @@ -rules: - - Symplify\PHPStanRules\Rules\NoSingleInterfaceImplementerRule - -services: - - - class: Symplify\PHPStanRules\Collector\InterfaceCollector - tags: - - phpstan.collector - - - - class: Symplify\PHPStanRules\Collector\ImplementedInterfaceCollector - tags: - - phpstan.collector +includes: + - ../../../../config/code-complexity-rules.neon + - ../../../../config/services/services.neon