Skip to content

Commit c4d0527

Browse files
committed
First collector rule: NotAnalysedTraitRule
1 parent 199dee4 commit c4d0527

8 files changed

+185
-0
lines changed

conf/bleedingEdge.neon

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ parameters:
1717
readOnlyByPhpDoc: true
1818
phpDocParserRequireWhitespaceBeforeDescription: true
1919
runtimeReflectionRules: true
20+
notAnalysedTrait: true

conf/config.level4.neon

+15
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ rules:
2222
conditionalTags:
2323
PHPStan\Rules\Comparison\ConstantLooseComparisonRule:
2424
phpstan.rules.rule: %featureToggles.looseComparison%
25+
PHPStan\Rules\Traits\TraitDeclarationCollector:
26+
phpstan.collector: %featureToggles.notAnalysedTrait%
27+
PHPStan\Rules\Traits\TraitUseCollector:
28+
phpstan.collector: %featureToggles.notAnalysedTrait%
29+
PHPStan\Rules\Traits\NotAnalysedTraitRule:
30+
phpstan.rules.rule: %featureToggles.notAnalysedTrait%
2531

2632
parameters:
2733
checkAdvancedIsset: true
@@ -175,3 +181,12 @@ services:
175181
class: PHPStan\Rules\Properties\NullsafePropertyFetchRule
176182
tags:
177183
- phpstan.rules.rule
184+
185+
-
186+
class: PHPStan\Rules\Traits\TraitDeclarationCollector
187+
188+
-
189+
class: PHPStan\Rules\Traits\TraitUseCollector
190+
191+
-
192+
class: PHPStan\Rules\Traits\NotAnalysedTraitRule

conf/config.neon

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ parameters:
4747
readOnlyByPhpDoc: false
4848
phpDocParserRequireWhitespaceBeforeDescription: false
4949
runtimeReflectionRules: false
50+
notAnalysedTrait: false
5051
fileExtensions:
5152
- php
5253
checkAdvancedIsset: false
@@ -251,6 +252,7 @@ parametersSchema:
251252
readOnlyByPhpDoc: bool()
252253
phpDocParserRequireWhitespaceBeforeDescription: bool()
253254
runtimeReflectionRules: bool()
255+
notAnalysedTrait: bool()
254256
])
255257
fileExtensions: listOf(string())
256258
checkAdvancedIsset: bool()
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Traits;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Node\CollectedDataNode;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Rules\RuleErrorBuilder;
10+
use function sprintf;
11+
use function strtolower;
12+
13+
/**
14+
* @implements Rule<CollectedDataNode>
15+
*/
16+
class NotAnalysedTraitRule implements Rule
17+
{
18+
19+
public function getNodeType(): string
20+
{
21+
return CollectedDataNode::class;
22+
}
23+
24+
public function processNode(Node $node, Scope $scope): array
25+
{
26+
$traitDeclarationData = $node->get(TraitDeclarationCollector::class);
27+
$traitUseData = $node->get(TraitUseCollector::class);
28+
29+
$declaredTraits = [];
30+
foreach ($traitDeclarationData as $file => $declaration) {
31+
foreach ($declaration as [$name, $line]) {
32+
$declaredTraits[strtolower($name)] = [$file, $name, $line];
33+
}
34+
}
35+
36+
foreach ($traitUseData as $usedNamesData) {
37+
foreach ($usedNamesData as $usedNames) {
38+
foreach ($usedNames as $usedName) {
39+
unset($declaredTraits[strtolower($usedName)]);
40+
}
41+
}
42+
}
43+
44+
$errors = [];
45+
foreach ($declaredTraits as [$file, $name, $line]) {
46+
$errors[] = RuleErrorBuilder::message(sprintf(
47+
'Trait %s is used zero times and is not analysed.',
48+
$name,
49+
))->file($file)->line($line)->build();
50+
}
51+
52+
return $errors;
53+
}
54+
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Traits;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Collectors\Collector;
8+
9+
/**
10+
* @implements Collector<Node\Stmt\Trait_, array{string, int}>
11+
*/
12+
class TraitDeclarationCollector implements Collector
13+
{
14+
15+
public function getNodeType(): string
16+
{
17+
return Node\Stmt\Trait_::class;
18+
}
19+
20+
public function processNode(Node $node, Scope $scope)
21+
{
22+
if ($node->namespacedName === null) {
23+
return null;
24+
}
25+
26+
return [$node->namespacedName->toString(), $node->getLine()];
27+
}
28+
29+
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Traits;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Collectors\Collector;
8+
use function array_map;
9+
10+
/**
11+
* @implements Collector<Node\Stmt\TraitUse, list<int, string>>
12+
*/
13+
class TraitUseCollector implements Collector
14+
{
15+
16+
public function getNodeType(): string
17+
{
18+
return Node\Stmt\TraitUse::class;
19+
}
20+
21+
public function processNode(Node $node, Scope $scope)
22+
{
23+
return array_map(static fn (Node\Name $traitName) => $traitName->toString(), $node->traits);
24+
}
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Traits;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Testing\RuleTestCase;
7+
8+
/**
9+
* @extends RuleTestCase<NotAnalysedTraitRule>
10+
*/
11+
class NotAnalysedTraitRuleTest extends RuleTestCase
12+
{
13+
14+
protected function getRule(): Rule
15+
{
16+
return new NotAnalysedTraitRule();
17+
}
18+
19+
protected function getCollectors(): array
20+
{
21+
return [
22+
new TraitDeclarationCollector(),
23+
new TraitUseCollector(),
24+
];
25+
}
26+
27+
public function testRule(): void
28+
{
29+
$this->analyse([__DIR__ . '/data/not-analysed-trait.php'], [
30+
[
31+
'Trait NotAnalysedTrait\Bar is used zero times and is not analysed.',
32+
10,
33+
],
34+
]);
35+
}
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace NotAnalysedTrait;
4+
5+
trait Foo
6+
{
7+
8+
}
9+
10+
trait Bar
11+
{
12+
13+
}
14+
15+
class UsesFoo
16+
{
17+
18+
use Foo;
19+
20+
}

0 commit comments

Comments
 (0)