Skip to content

Recognize Laravel Macroable::mixin() registrations#256

Open
shuvroroy wants to merge 9 commits into
PHPantom-dev:mainfrom
shuvroroy:feat/laravel-mixin-support
Open

Recognize Laravel Macroable::mixin() registrations#256
shuvroroy wants to merge 9 commits into
PHPantom-dev:mainfrom
shuvroroy:feat/laravel-mixin-support

Conversation

@shuvroroy

Copy link
Copy Markdown

Summary

PHPantom already recovers Target::macro('name', $closure) registrations statically (and attaches facade macros to the concrete container-bound class). This PR extends the macro scanner to the other Macroable registration path: Target::mixin($object).

A mixin object's methods are closure factories — a public method foo() returns a Closure whose signature is the macro actually registered as Target::foo(...). We recover that shape from source without booting the app (Larastan boots and reflects the runtime $macros static; we parse the common literal form instead).

What it does

  • Recognizes Target::mixin(new X) and Target::mixin(X::class), resolving X to an FQN via the file's use statements.
  • For each public/protected method of X whose body returns a closure/arrow-fn, synthesizes a macro on Target named after the method, taking the returned closure's parameters and return type (mirroring Laravel's IS_PUBLIC | IS_PROTECTED; private/static/abstract/magic methods are skipped).
  • Reuses the existing facade-target expansion, so a mixin registered through a facade also attaches to the facade's concrete class.
  • Go-to-definition on a mixed-in macro jumps to the mixin method's own declaration.
  • Editing the mixin class (e.g. adding a helper method) refreshes the recognized macros — the mixin source file is tracked as an index dependency even though it contains no macro(/mixin( token itself.

The result: mixin-contributed methods autocomplete, hover (with the recovered signature and a macro-origin marker), resolve, and type-check on the target class, exactly like a Target::macro(...) registration.

Scope / limitations

  • Only literal new X / X::class arguments are handled; variable or computed targets are skipped, matching the existing macro() scope.
  • Still out of scope for macro() too: variable/computed name arguments and string/array callables in place of a closure (rare, no statically recoverable signature).
  • A mixin whose closures call methods on the rebound $this should carry an @mixin \Target docblock (the idiomatic Laravel pattern) so those $this->… calls resolve — this is handled by PHPantom's existing @mixin support, not this PR.

Testing

  • Unit (macros_tests.rs): mixin-call extraction for both new X and X::class, skipping non-literal args and relative self:: targets, and closure-signature synthesis (including skipping methods that don't return a closure, and non-target classes in the same file).
  • Integration (laravel_macros.rs): the mixin macro is surfaced in completion, resolves without diagnostics, go-to-definition lands on the mixin method, hover shows the recovered signature, and a $this-using mixin (with @mixin) resolves in completion + hover.
  • cargo test, clippy (lib + tests), and cargo fmt --check are clean; analyze --project-root examples/laravel reports only pre-existing unrelated errors.

Example

Adds examples/laravel/app/Support/CollectionMixin.php registered via DemoServiceProvider::boot(), exercised in Demo.php.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant