Skip to content

Commit

Permalink
Improve no single interface (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba authored Jun 2, 2024
1 parent 883c98d commit 51b5765
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 20 deletions.
5 changes: 5 additions & 0 deletions config/code-complexity-rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ services:
class: Symplify\PHPStanRules\Collector\ImplementedInterfaceCollector
tags:
- phpstan.collector

-
class: Symplify\PHPStanRules\Collector\InterfaceOfAbstractClassCollector
tags:
- phpstan.collector
2 changes: 0 additions & 2 deletions config/services/services.neon
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
services:
- PhpParser\NodeFinder

- Symplify\PHPStanRules\NodeTraverser\SimpleCallableNodeTraverser
- Symplify\PHPStanRules\PhpDocParser\PhpDocNodeTraverser
- Symplify\PHPStanRules\Reflection\ReflectionParser
Expand Down
37 changes: 37 additions & 0 deletions src/Collector/InterfaceOfAbstractClassCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Symplify\PHPStanRules\Collector;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Collectors\Collector;

final class InterfaceOfAbstractClassCollector implements Collector
{
public function getNodeType(): string
{
return Class_::class;
}

/**
* @param Class_ $node
* @return string[]|null
*/
public function processNode(Node $node, Scope $scope): ?array
{
if (! $node->isAbstract()) {
return null;
}

$interfaceNames = [];

foreach ($node->implements as $implement) {
$interfaceNames[] = $implement->toString();
}

return $interfaceNames;
}
}
8 changes: 5 additions & 3 deletions src/NodeFinder/TypeAwareNodeFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/Rules/ForbiddenMultipleClassLikeInOneFileRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

/**
Expand Down
7 changes: 6 additions & 1 deletion src/Rules/NoSingleInterfaceImplementerRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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',
Expand All @@ -58,6 +62,7 @@ protected function getCollectors(): array
return [
self::getContainer()->getByType(ImplementedInterfaceCollector::class),
self::getContainer()->getByType(InterfaceCollector::class),
self::getContainer()->getByType(InterfaceOfAbstractClassCollector::class),
];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 51b5765

Please sign in to comment.