|
2 | 2 |
|
3 | 3 | namespace Psalm\LaravelPlugin\Handlers;
|
4 | 4 |
|
5 |
| -use Illuminate\Console\Command; |
6 |
| -use Illuminate\Foundation\Http\FormRequest; |
7 |
| -use Illuminate\Notifications\Notification; |
8 | 5 | use Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface;
|
9 | 6 | use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;
|
| 7 | +use Psalm\Storage\ClassLikeStorage; |
| 8 | +use Psalm\Storage\MethodStorage; |
| 9 | +use Psalm\Storage\PropertyStorage; |
| 10 | +use function array_intersect; |
10 | 11 | use function in_array;
|
11 | 12 |
|
12 | 13 | class SuppressHandler implements AfterClassLikeVisitInterface
|
13 | 14 | {
|
| 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 | + ], |
| 31 | + ]; |
| 32 | + |
| 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 | + ], |
| 60 | + ]; |
| 61 | + |
14 | 62 | public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event)
|
15 | 63 | {
|
16 |
| - $storage = $event->getStorage(); |
| 64 | + $class = $event->getStorage(); |
17 | 65 |
|
18 |
| - if (in_array(Command::class, $storage->parent_classes)) { |
19 |
| - if (!in_array('PropertyNotSetInConstructor', $storage->suppressed_issues)) { |
20 |
| - $storage->suppressed_issues[] = 'PropertyNotSetInConstructor'; |
| 66 | + foreach (self::BY_CLASS as $issue => $class_names) { |
| 67 | + if (in_array($class->name, $class_names)) { |
| 68 | + self::suppress($issue, $class); |
21 | 69 | }
|
22 |
| - if (isset($storage->properties['description'])) { |
23 |
| - $property = $storage->properties['description']; |
24 |
| - if (!in_array('NonInvariantDocblockPropertyType', $property->suppressed_issues)) { |
25 |
| - $property->suppressed_issues[] = 'NonInvariantDocblockPropertyType'; |
26 |
| - } |
| 70 | + } |
| 71 | + |
| 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); |
27 | 75 | }
|
28 | 76 | }
|
29 | 77 |
|
30 |
| - // FormRequest: suppress PropertyNotSetInConstructor. |
31 |
| - if (in_array(FormRequest::class, $storage->parent_classes) && !in_array('PropertyNotSetInConstructor', $storage->suppressed_issues)) { |
32 |
| - $storage->suppressed_issues[] = 'PropertyNotSetInConstructor'; |
| 78 | + foreach (self::BY_PARENT_CLASS as $issue => $parent_classes) { |
| 79 | + if (!array_intersect($class->parent_classes, $parent_classes)) { |
| 80 | + continue; |
| 81 | + } |
| 82 | + |
| 83 | + self::suppress($issue, $class); |
33 | 84 | }
|
34 | 85 |
|
35 |
| - // Notification: suppress PropertyNotSetInConstructor. |
36 |
| - if (in_array(Notification::class, $storage->parent_classes) && !in_array('PropertyNotSetInConstructor', $storage->suppressed_issues)) { |
37 |
| - $storage->suppressed_issues[] = 'PropertyNotSetInConstructor'; |
| 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); |
| 94 | + } |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 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; |
38 | 107 | }
|
39 | 108 | }
|
40 | 109 | }
|
0 commit comments