-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathUnusedPublicClassMethodRule.php
123 lines (104 loc) · 3.98 KB
/
UnusedPublicClassMethodRule.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<?php
declare(strict_types=1);
namespace TomasVotruba\UnusedPublic\Rules;
use Nette\Utils\Arrays;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\CollectedDataNode;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use TomasVotruba\UnusedPublic\Collectors\FormTypeClassCollector;
use TomasVotruba\UnusedPublic\Collectors\PublicClassMethodCollector;
use TomasVotruba\UnusedPublic\Configuration;
use TomasVotruba\UnusedPublic\Enum\RuleTips;
use TomasVotruba\UnusedPublic\NodeCollectorExtractor;
use TomasVotruba\UnusedPublic\Templates\TemplateMethodCallsProvider;
use TomasVotruba\UnusedPublic\Templates\UsedMethodAnalyzer;
use TomasVotruba\UnusedPublic\Utils\Strings;
/**
* @see \TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\UnusedPublicClassMethodRuleTest
*/
final readonly class UnusedPublicClassMethodRule implements Rule
{
/**
* @var string
*
* @api
*/
public const ERROR_MESSAGE = 'Public method "%s::%s()" is never used';
public function __construct(
private Configuration $configuration,
private TemplateMethodCallsProvider $templateMethodCallsProvider,
private UsedMethodAnalyzer $usedMethodAnalyzer,
private NodeCollectorExtractor $nodeCollectorExtractor,
) {
}
public function getNodeType(): string
{
return CollectedDataNode::class;
}
/**
* @param CollectedDataNode $node
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $this->configuration->isUnusedMethodEnabled()) {
return [];
}
$twigMethodNames = $this->templateMethodCallsProvider->provideTwigMethodCalls();
$bladeMethodNames = $this->templateMethodCallsProvider->provideBladeMethodCalls();
$completeMethodCallReferences = $this->nodeCollectorExtractor->extractMethodCallReferences($node);
$formTypeClasses = Arrays::flatten($node->get(FormTypeClassCollector::class));
// php method calls are case-insensitive
$lowerCompleteMethodCallReferences = Strings::lowercase($completeMethodCallReferences);
$ruleErrors = [];
$publicClassMethodCollector = $node->get(PublicClassMethodCollector::class);
foreach ($publicClassMethodCollector as $filePath => $declarations) {
foreach ($declarations as [$className, $methodName, $line]) {
if (in_array($className, $formTypeClasses, true)) {
continue;
}
if ($this->isUsedClassMethod(
$className,
$methodName,
$lowerCompleteMethodCallReferences,
$twigMethodNames,
$bladeMethodNames
)) {
continue;
}
/** @var string $methodName */
$errorMessage = sprintf(self::ERROR_MESSAGE, $className, $methodName);
$ruleErrors[] = RuleErrorBuilder::message($errorMessage)
->file($filePath)
->line($line)
->tip(RuleTips::SOLUTION_MESSAGE)
->build();
}
}
return $ruleErrors;
}
/**
* @param string[] $lowerCompleteMethodCallReferences
* @param string[] $twigMethodNames
* @param string[] $bladeMethodNames
*/
private function isUsedClassMethod(
string $className,
string $methodName,
array $lowerCompleteMethodCallReferences,
array $twigMethodNames,
array $bladeMethodNames
): bool {
if ($this->usedMethodAnalyzer->isUsedInTwig($methodName, $twigMethodNames)) {
return true;
}
if (in_array($methodName, $bladeMethodNames, true)) {
return true;
}
$methodReference = $className . '::' . $methodName;
return in_array(strtolower($methodReference), $lowerCompleteMethodCallReferences, true);
}
}