11
11
use Psalm \Plugin \EventHandler \AfterClassLikeVisitInterface ;
12
12
use Psalm \Plugin \EventHandler \AfterCodebasePopulatedInterface ;
13
13
use Psalm \Plugin \EventHandler \AfterMethodCallAnalysisInterface ;
14
+ use Psalm \Plugin \EventHandler \BeforeAddIssueInterface ;
14
15
use Psalm \Plugin \EventHandler \Event \AfterClassLikeVisitEvent ;
15
16
use Psalm \Plugin \EventHandler \Event \AfterCodebasePopulatedEvent ;
16
17
use Psalm \Plugin \EventHandler \Event \AfterMethodCallAnalysisEvent ;
18
+ use Psalm \Plugin \EventHandler \Event \BeforeAddIssueEvent ;
17
19
use Psalm \SymfonyPsalmPlugin \Issue \NamingConventionViolation ;
18
20
use Psalm \SymfonyPsalmPlugin \Issue \PrivateService ;
19
21
use Psalm \SymfonyPsalmPlugin \Issue \ServiceNotFound ;
22
24
use Psalm \Type \Union ;
23
25
use Symfony \Component \DependencyInjection \Exception \ServiceNotFoundException ;
24
26
25
- class ContainerHandler implements AfterMethodCallAnalysisInterface, AfterClassLikeVisitInterface, AfterCodebasePopulatedInterface
27
+ class ContainerHandler implements AfterMethodCallAnalysisInterface, AfterClassLikeVisitInterface, AfterCodebasePopulatedInterface, BeforeAddIssueInterface
26
28
{
27
29
private const GET_CLASSLIKES = [
28
30
'Psr\Container\ContainerInterface ' ,
@@ -38,9 +40,18 @@ class ContainerHandler implements AfterMethodCallAnalysisInterface, AfterClassLi
38
40
*/
39
41
private static $ containerMeta ;
40
42
43
+ /**
44
+ * @var array<string> collection of cower-cased class names that are present in the container
45
+ */
46
+ private static array $ containerClassNames = [];
47
+
41
48
public static function init (ContainerMeta $ containerMeta ): void
42
49
{
43
50
self ::$ containerMeta = $ containerMeta ;
51
+
52
+ self ::$ containerClassNames = array_map (function (string $ className ): string {
53
+ return strtolower ($ className );
54
+ }, self ::$ containerMeta ->getClassNames ());
44
55
}
45
56
46
57
public static function afterMethodCallAnalysis (AfterMethodCallAnalysisEvent $ event ): void
@@ -173,17 +184,27 @@ public static function afterCodebasePopulated(AfterCodebasePopulatedEvent $event
173
184
return ;
174
185
}
175
186
176
- $ containerClassNames = array_map (function (string $ className ): string {
177
- return strtolower ($ className );
178
- }, self ::$ containerMeta ->getClassNames ());
179
-
180
187
foreach ($ event ->getCodebase ()->classlike_storage_provider ->getAll () as $ name => $ storage ) {
181
- if (in_array ($ name , $ containerClassNames , true )) {
188
+ if (in_array ($ name , self :: $ containerClassNames , true )) {
182
189
$ storage ->suppressed_issues [] = 'UnusedClass ' ;
183
190
}
184
191
}
185
192
}
186
193
194
+ public static function beforeAddIssue (BeforeAddIssueEvent $ event ): ?bool
195
+ {
196
+ $ data = $ event ->getIssue ()->toIssueData ('error ' );
197
+ if ('PossiblyUnusedMethod ' === $ data ->type
198
+ && '__construct ' === $ data ->selected_text
199
+ && null !== $ data ->dupe_key
200
+ && in_array (preg_replace ('/::__construct$/ ' , '' , $ data ->dupe_key ), self ::$ containerClassNames , true )) {
201
+ // Don't report service constructors as PossiblyUnusedMethod
202
+ return false ;
203
+ }
204
+
205
+ return null ;
206
+ }
207
+
187
208
public static function isContainerMethod (string $ declaringMethodId , string $ methodName ): bool
188
209
{
189
210
return in_array (
0 commit comments