Skip to content

Commit c032e4e

Browse files
authored
Merge pull request #183 from caugner/fix-unused-code
Suppress UnusedClass/PossiblyUnusedMethod on well-known classes/methods of fresh Laravel/Lumen projects
2 parents bb47983 + aebbf15 commit c032e4e

File tree

5 files changed

+115
-20
lines changed

5 files changed

+115
-20
lines changed

src/Handlers/SuppressHandler.php

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +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;
8+
use Psalm\Storage\MethodStorage;
9+
use Psalm\Storage\PropertyStorage;
10+
use function array_intersect;
1011
use function in_array;
1112

1213
class SuppressHandler implements AfterClassLikeVisitInterface
1314
{
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+
1462
public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event)
1563
{
16-
$storage = $event->getStorage();
64+
$class = $event->getStorage();
1765

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);
2169
}
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);
2775
}
2876
}
2977

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);
3384
}
3485

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;
38107
}
39108
}
40109
}

tests/laravel-test-baseline.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="4.7.3@38c452ae584467e939d55377aaf83b5a26f19dd1">
2+
<files psalm-version="4.8.1@f73f2299dbc59a3e6c4d66cff4605176e728ee69">
33
<file src="app/Exceptions/Handler.php">
44
<NonInvariantDocblockPropertyType occurrences="2">
55
<code>$dontFlash</code>

tests/laravel-test-psalm.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
33
xmlns="https://getpsalm.org/schema/config"
44
errorLevel="1"
5+
findUnusedCode="true"
56
resolveFromConfigFile="false"
67
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
78
errorBaseline="../psalm-plugin-laravel/tests/laravel-test-baseline.xml"

tests/lumen-test-baseline.xml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="4.7.3@38c452ae584467e939d55377aaf83b5a26f19dd1">
2+
<files psalm-version="4.8.1@f73f2299dbc59a3e6c4d66cff4605176e728ee69">
33
<file src="app/Console/Kernel.php">
44
<PropertyNotSetInConstructor occurrences="1">
55
<code>Kernel</code>
66
</PropertyNotSetInConstructor>
77
</file>
8+
<file src="app/Events/ExampleEvent.php">
9+
<PossiblyUnusedMethod occurrences="1">
10+
<code>__construct</code>
11+
</PossiblyUnusedMethod>
12+
</file>
813
<file src="app/Exceptions/Handler.php">
914
<LessSpecificReturnStatement occurrences="1">
1015
<code>parent::render($request, $exception)</code>
@@ -13,10 +18,29 @@
1318
<code>\Illuminate\Http\Response|\Illuminate\Http\JsonResponse</code>
1419
</MoreSpecificReturnType>
1520
</file>
21+
<file src="app/Http/Controllers/ExampleController.php">
22+
<UnusedClass occurrences="1">
23+
<code>ExampleController</code>
24+
</UnusedClass>
25+
</file>
26+
<file src="app/Http/Middleware/ExampleMiddleware.php">
27+
<UnusedClass occurrences="1">
28+
<code>ExampleMiddleware</code>
29+
</UnusedClass>
30+
</file>
1631
<file src="app/Jobs/ExampleJob.php">
1732
<PropertyNotSetInConstructor occurrences="1">
1833
<code>ExampleJob</code>
1934
</PropertyNotSetInConstructor>
35+
<UnusedClass occurrences="1">
36+
<code>ExampleJob</code>
37+
</UnusedClass>
38+
</file>
39+
<file src="app/Listeners/ExampleListener.php">
40+
<PossiblyUnusedMethod occurrences="2">
41+
<code>__construct</code>
42+
<code>handle</code>
43+
</PossiblyUnusedMethod>
2044
</file>
2145
<file src="app/Models/User.php">
2246
<NonInvariantDocblockPropertyType occurrences="1">

tests/lumen-test-psalm.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
33
xmlns="https://getpsalm.org/schema/config"
44
errorLevel="1"
5+
findUnusedCode="true"
56
resolveFromConfigFile="false"
67
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
78
errorBaseline="../psalm-plugin-laravel/tests/lumen-test-baseline.xml"

0 commit comments

Comments
 (0)