Skip to content

Commit f7f40a0

Browse files
committed
Add separate rule for testing unused traits.
1 parent de436ea commit f7f40a0

File tree

13 files changed

+179
-1690
lines changed

13 files changed

+179
-1690
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
# PHPUnit
99
/phpunit.xml
10+
/.phpunit.result.cache
1011

1112
# Build data
1213
/build/

.phpunit.result.cache

Lines changed: 0 additions & 1 deletion
This file was deleted.

README.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# A collection of PHPStan extensions
22

33
This repo contains some useful PHPStan extension for detecting errors in your code. The currently list of rules is:
4-
- ==UnusedClassRule==
4+
## `UnusedClassRule`
5+
## `UnusedTraitRule`
56

67
## Install
78

@@ -23,17 +24,16 @@ include:
2324
```
2425
2526
## Rules
26-
### UnusedClassRule
27-
This rule scans for class and trait declarations and use statements. If a class or trait is declared but not used within the scanned source files, an error is generated.
27+
### `UnusedClassRule`
28+
This rule scans for class declarations and use statements. If a class is declared but not used within the scanned source files, an error is generated.
2829

2930
### Disabling the rule
30-
You can disable scanning classes and traits as follows:
31+
You can disable scanning classes as follows:
3132
```yaml
3233
# phpstan.neon
3334
parameters:
3435
unused_classes:
3536
classes: false
36-
traits: false
3737
```
3838

3939
#### Excluding files
@@ -47,3 +47,18 @@ parameters:
4747
- 'src/Controller'
4848
- 'src/MyUnusedClass.php'
4949
```
50+
51+
### `UnusedTraitRule`
52+
This rule scans for trait declarations and use statements. If a trait is declared but not used within the scanned source files, an error is generated.
53+
54+
### Disabling the rule
55+
You can disable scanning traits as follows:
56+
```yaml
57+
# phpstan.neon
58+
parameters:
59+
unused_classes:
60+
traits: false
61+
```
62+
63+
#### Excluding files
64+
You can exclude directories and individual files from being scanned by this rule using the excludePaths parameter as shown above/

config/extension.neon

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ services:
3131
class: Xact\PHPStan\Collectors\DeclareClassCollector
3232
tags:
3333
- phpstan.collector
34-
-
35-
class: Xact\PHPStan\Collectors\DeclareTraitCollector
36-
tags:
37-
- phpstan.collector
3834

3935
rules:
4036
- Xact\PHPStan\Rules\UnusedClassRule

phpunit.xml.dist

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
<testsuites>
2121
<testsuite name="Project Test Suite">
2222
<directory>tests</directory>
23-
<exclude>tests/UnusedClass/</exclude>
2423
</testsuite>
2524
</testsuites>
2625

src/Rules/UnusedClassRule.php

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use Xact\PHPStan\Collectors\ClassGroupUseCollector;
1313
use Xact\PHPStan\Collectors\ClassUseCollector;
1414
use Xact\PHPStan\Collectors\DeclareClassCollector;
15-
use Xact\PHPStan\Collectors\DeclareTraitCollector;
1615
use Xact\PHPStan\Exception\InvalidNodeTypeException;
1716

1817
class UnusedClassRule implements Rule
@@ -36,7 +35,6 @@ public function processNode(Node $node, Scope $scope): array
3635
}
3736

3837
$classDeclarationData = $node->get(DeclareClassCollector::class);
39-
$traitDeclarationData = $node->get(DeclareTraitCollector::class);
4038
$groupUses = $node->get(ClassGroupUseCollector::class);
4139
$normalUses = $node->get(ClassUseCollector::class);
4240

@@ -71,20 +69,6 @@ public function processNode(Node $node, Scope $scope): array
7169
}
7270
}
7371
}
74-
foreach ($traitDeclarationData as $file => $declarations) {
75-
/**
76-
* @var string $className
77-
* @var int $line
78-
*/
79-
foreach ($declarations as [$className, $line]) {
80-
if (!array_key_exists($className, $usedClasses)) {
81-
$errors[] = RuleErrorBuilder::message("Trait {$className} is never used.")
82-
->file($file)
83-
->line($line)
84-
->build();
85-
}
86-
}
87-
}
8872

8973
return $errors;
9074
}

src/Rules/UnusedTraitRule.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Xact\PHPStan\Rules;
6+
7+
use PhpParser\Node;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Node\CollectedDataNode;
10+
use PHPStan\Rules\Rule;
11+
use PHPStan\Rules\RuleErrorBuilder;
12+
use PHPStan\Rules\Traits\TraitDeclarationCollector;
13+
use PHPStan\Rules\Traits\TraitUseCollector;
14+
use Xact\PHPStan\Exception\InvalidNodeTypeException;
15+
16+
class UnusedTraitRule implements Rule
17+
{
18+
/**
19+
* @inheritDoc
20+
*/
21+
public function getNodeType(): string
22+
{
23+
return CollectedDataNode::class;
24+
}
25+
26+
/**
27+
* @inheritDoc
28+
*/
29+
// phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
30+
public function processNode(Node $node, Scope $scope): array
31+
{
32+
if (!$node instanceof CollectedDataNode) {
33+
throw InvalidNodeTypeException::create($node, CollectedDataNode::class);
34+
}
35+
36+
$traitDeclarationData = $node->get(TraitDeclarationCollector::class);
37+
$traitUses = $node->get(TraitUseCollector::class);
38+
39+
$usedTraits = [];
40+
foreach ($traitUses as $fileUses) {
41+
foreach ((array)$fileUses as $traitUse) {
42+
foreach ((array)$traitUse as $trait) {
43+
$usedTraits[$trait] = $trait;
44+
}
45+
}
46+
}
47+
48+
$errors = [];
49+
foreach ($traitDeclarationData as $file => $declarations) {
50+
/**
51+
* @var string $className
52+
* @var int $line
53+
*/
54+
foreach ($declarations as [$className, $line]) {
55+
if (!array_key_exists($className, $usedTraits)) {
56+
$errors[] = RuleErrorBuilder::message("Trait {$className} is never used.")
57+
->file($file)
58+
->line($line)
59+
->build();
60+
}
61+
}
62+
}
63+
64+
return $errors;
65+
}
66+
}

tests/UnusedClass/ClassA.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
namespace Xact\PHPStan\Tests\UnusedClass;
66

7+
use Xact\PHPStan\Tests\UnusedClass\TraitA;
8+
79
class ClassA
810
{
11+
use TraitA;
12+
13+
public function __construct()
14+
{
15+
$this->testA();
16+
}
917
}

tests/UnusedClass/TraitA.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Xact\PHPStan\Tests\UnusedClass;
6+
7+
trait TraitA
8+
{
9+
public function testA(): int
10+
{
11+
return 1;
12+
}
13+
}

tests/UnusedClass/TraitB.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Xact\PHPStan\Tests\UnusedClass;
6+
7+
trait TraitB
8+
{
9+
}

0 commit comments

Comments
 (0)