Draft
Conversation
…ler heuristic Replace the broad reflection heuristic that marked all public controller methods as used with precise AST-based detection of: - Route::get/post/put/patch/delete/any/match — extract [Class, 'method'] from action arg - Route::resource — mark 7 CRUD methods (index/create/store/show/edit/update/destroy) - Route::apiResource — mark 5 CRUD methods (index/store/show/update/destroy) - Event::listen — mark handle() + __construct() on listener class - Event::subscribe — mark subscribe() + __construct() on subscriber class - Schedule::job — mark handle() + __construct() on job class All other reflection-based checks (Eloquent, commands, jobs, middleware, notifications, form requests, factories, seeders, policies, mailables, broadcast events, JSON resources, validation rules) remain unchanged.
…route __construct, invokable controllers
- Move routeNotificationFor* detection from Notification to Notifiable/RoutesNotifications trait users
- Replace deprecated HandlesAuthorization trait check with *Policy naming convention for policy detection
- Mark __construct as used for controllers referenced in Route:: registrations
- Support invokable controllers (Route::get('/path', Controller::class) marking __invoke + __construct)
- Detect migration classes (up/down methods) - Detect observers via Model::observe() calls and #[ObservedBy] attribute - Mark middleware __construct as used alongside handle/terminate
- Detect $this->authorize('ability', $model) in controllers using AuthorizesRequests trait
- Resolve model → policy class using Laravel naming convention
- Support Gate::define() for explicit ability registration
- Support Gate::policy() to mark all public methods on registered policy classes
- Convert kebab-case ability names to camelCase (e.g. 'force-download' → 'forceDownload')
Other providers (Symfony, Doctrine, Twig, Nette) install real packages as dev dependencies. Laravel was the only one using ~210 lines of inline stubs. Install laravel/framework and use real Illuminate classes instead.
Laravel 11+ requires PHP ^8.2, which breaks CI on PHP 8.1. Laravel 10 requires PHP ^8.1 and all tests pass with it.
Eloquent (illuminate/database) can be used standalone without laravel/framework. The new EloquentUsageProvider auto-enables when illuminate/database is installed, covering Model methods, Factory, Seeder, Migration, and Observer detection.
Methods declared in vendor interfaces/parent classes are already handled by VendorUsageProvider, so the Laravel provider doesn't need to mark them: - broadcastOn: declared in ShouldBroadcast interface - toArray, with, additional: declared in JsonResource parent class - validate: declared in ValidationRule interface - passes, message: declared in Rule interface The remaining checks cover methods called via method_exists() magic (broadcastWith, broadcastAs, broadcastWhen, paginationInformation) which VendorUsageProvider cannot detect.
The isPolicyMethod() fallback previously matched any class ending in "Policy" (e.g. RetentionPolicy, CachePolicy), which could suppress legitimate dead code warnings on non-authorization classes that happen to have methods named view, create, update, delete, etc. Laravel's own guessPolicyName() always generates candidates within a \Policies\ namespace segment. Policies registered outside that convention (via Gate::policy() or #[UsePolicy]) are already handled by the precise detection layer. So we can safely require \Policies\ in the class name for the heuristic fallback.
- Route::match with invokable controller (class string at arg index 2) - Job methods uniqueVia and displayName - FormRequest methods failedValidation and failedAuthorization - #[ObservedBy] with array syntax
The previous implementation only checked {rootNamespace}\Policies\{Model}Policy,
which missed models in sub-namespaces (e.g. App\Models\Admin\User would only
try App\Policies\UserPolicy, missing App\Policies\Admin\UserPolicy).
Now mirrors Laravel's Gate::guessPolicyName() candidate list:
- \Models\ → \Models\Policies\ replacement
- \Models\ → \Policies\ replacement
- Segment-based candidates from most to least specific
All existing candidates where the class exists are emitted as usages,
rather than just the first match.
Laravel supports 'Controller@method' strings in route definitions. Parse these alongside array callables and class-string invokables in Route::get/post/put/patch/delete/any and Route::match calls.
Laravel automatically discovers event listeners by scanning the Listeners directory for classes with public handle*/__invoke methods that have a class-typed first parameter (the event). This happens without any explicit Event::listen() registration. Previously, only explicitly registered listeners (via Event::listen AST calls) had their handle() marked as used. Auto-discovered listeners would be falsely reported as dead code. The detection mirrors Laravel's DiscoverEvents logic: - Public methods matching handle* or __invoke - First parameter must have a non-builtin class type-hint - Union types (e.g. EventA|EventB) are supported - Constructor is also marked when the class qualifies Placed last in the shouldMarkAsUsed chain so it only triggers for classes not already identified as Commands, Jobs, Middleware, etc.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.