Skip to content

Commit aebbf15

Browse files
committed
refactor: generalize SuppressHandler
1 parent fc80186 commit aebbf15

File tree

1 file changed

+78
-43
lines changed

1 file changed

+78
-43
lines changed

src/Handlers/SuppressHandler.php

Lines changed: 78 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,108 @@
22

33
namespace Psalm\LaravelPlugin\Handlers;
44

5-
use Illuminate\Console\Command;
6-
use Illuminate\Foundation\Http\FormRequest;
7-
use Illuminate\Notifications\Notification;
85
use Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface;
96
use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;
7+
use Psalm\Storage\ClassLikeStorage;
108
use Psalm\Storage\MethodStorage;
11-
use function array_key_exists;
9+
use Psalm\Storage\PropertyStorage;
10+
use function array_intersect;
1211
use function in_array;
1312

1413
class SuppressHandler implements AfterClassLikeVisitInterface
1514
{
16-
private const UNUSED_CLASSES = [
17-
"App\Console\Kernel",
18-
"App\Exceptions\Handler",
19-
"App\Http\Controllers\Controller",
20-
"App\Http\Kernel",
21-
"App\Http\Middleware\Authenticate",
22-
"App\Http\Middleware\TrustHosts",
23-
"App\Providers\AppServiceProvider",
24-
"App\Providers\AuthServiceProvider",
25-
"App\Providers\BroadcastServiceProvider",
26-
"App\Providers\EventServiceProvider",
15+
/**
16+
* @var array<string, list<class-string>>
17+
*/
18+
private const BY_CLASS = [
19+
'UnusedClass' => [
20+
'App\Console\Kernel',
21+
'App\Exceptions\Handler',
22+
'App\Http\Controllers\Controller',
23+
'App\Http\Kernel',
24+
'App\Http\Middleware\Authenticate',
25+
'App\Http\Middleware\TrustHosts',
26+
'App\Providers\AppServiceProvider',
27+
'App\Providers\AuthServiceProvider',
28+
'App\Providers\BroadcastServiceProvider',
29+
'App\Providers\EventServiceProvider',
30+
],
2731
];
2832

29-
private const UNUSED_METHODS = [
30-
"App\Http\Middleware\RedirectIfAuthenticated" => ["handle"],
33+
/**
34+
* @var array<string, array<class-string, list<string>>>
35+
*/
36+
private const BY_CLASS_METHOD = [
37+
'PossiblyUnusedMethod' => [
38+
'App\Http\Middleware\RedirectIfAuthenticated' => ['handle'],
39+
],
40+
];
41+
42+
/**
43+
* @var array<string, list<class-string>>
44+
*/
45+
private const BY_PARENT_CLASS = [
46+
'PropertyNotSetInConstructor' => [
47+
'Illuminate\Console\Command',
48+
'Illuminate\Foundation\Http\FormRequest',
49+
'Illuminate\Notifications\Notification',
50+
],
51+
];
52+
53+
/**
54+
* @var array<string, array<class-string, list<string>>>
55+
*/
56+
private const BY_PARENT_CLASS_PROPERTY = [
57+
'NonInvariantDocblockPropertyType' => [
58+
'Illuminate\Console\Command' => ['description'],
59+
],
3160
];
3261

3362
public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event)
3463
{
35-
$storage = $event->getStorage();
64+
$class = $event->getStorage();
3665

37-
if (in_array(Command::class, $storage->parent_classes)) {
38-
if (!in_array('PropertyNotSetInConstructor', $storage->suppressed_issues)) {
39-
$storage->suppressed_issues[] = 'PropertyNotSetInConstructor';
40-
}
41-
if (isset($storage->properties['description'])) {
42-
$property = $storage->properties['description'];
43-
if (!in_array('NonInvariantDocblockPropertyType', $property->suppressed_issues)) {
44-
$property->suppressed_issues[] = 'NonInvariantDocblockPropertyType';
45-
}
66+
foreach (self::BY_CLASS as $issue => $class_names) {
67+
if (in_array($class->name, $class_names)) {
68+
self::suppress($issue, $class);
4669
}
4770
}
4871

49-
// FormRequest: suppress PropertyNotSetInConstructor.
50-
if (in_array(FormRequest::class, $storage->parent_classes) && !in_array('PropertyNotSetInConstructor', $storage->suppressed_issues)) {
51-
$storage->suppressed_issues[] = 'PropertyNotSetInConstructor';
72+
foreach (self::BY_CLASS_METHOD as $issue => $method_by_class) {
73+
foreach ($method_by_class[$class->name] ?? [] as $method_name) {
74+
self::suppress($issue, $class->methods[$method_name] ?? null);
75+
}
5276
}
5377

54-
// Notification: suppress PropertyNotSetInConstructor.
55-
if (in_array(Notification::class, $storage->parent_classes) && !in_array('PropertyNotSetInConstructor', $storage->suppressed_issues)) {
56-
$storage->suppressed_issues[] = 'PropertyNotSetInConstructor';
57-
}
78+
foreach (self::BY_PARENT_CLASS as $issue => $parent_classes) {
79+
if (!array_intersect($class->parent_classes, $parent_classes)) {
80+
continue;
81+
}
5882

59-
// Suppress UnusedClass on well-known classes.
60-
if (in_array($storage->name, self::UNUSED_CLASSES)) {
61-
$storage->suppressed_issues[] = 'UnusedClass';
83+
self::suppress($issue, $class);
6284
}
6385

64-
// Suppress PossiblyUnusedMethod on well-known methods.
65-
if (array_key_exists($storage->name, self::UNUSED_METHODS)) {
66-
foreach (self::UNUSED_METHODS[$storage->name] as $method_name) {
67-
$method = $storage->methods[$method_name] ?? null;
68-
if ($method instanceof MethodStorage) {
69-
$method->suppressed_issues[] = 'PossiblyUnusedMethod';
86+
foreach (self::BY_PARENT_CLASS_PROPERTY as $issue => $methods_by_parent_class) {
87+
foreach ($methods_by_parent_class as $parent_class => $property_names) {
88+
if (!in_array($parent_class, $class->parent_classes)) {
89+
continue;
90+
}
91+
92+
foreach ($property_names as $property_name) {
93+
self::suppress($issue, $class->properties[$property_name] ?? null);
7094
}
7195
}
7296
}
7397
}
98+
99+
/**
100+
* @param string $issue
101+
* @param ClassLikeStorage|PropertyStorage|MethodStorage|null $storage
102+
*/
103+
private static function suppress(string $issue, $storage): void
104+
{
105+
if ($storage && !in_array($issue, $storage->suppressed_issues)) {
106+
$storage->suppressed_issues[] = $issue;
107+
}
108+
}
74109
}

0 commit comments

Comments
 (0)