Skip to content

Resolve atom-dispatched use chains across LSP features - #92

Merged
JesseHerrick merged 3 commits into
mainfrom
atom-dispatch-using
Sep 7, 2026
Merged

Resolve atom-dispatched use chains across LSP features#92
JesseHerrick merged 3 commits into
mainfrom
atom-dispatch-using

Conversation

@JesseHerrick

@JesseHerrick JesseHerrick commented Sep 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Resolve Phoenix-style atom dispatch such as use MyAppWeb, :controller
  • Preserve dispatch atoms and options through nested use chains
  • Support completion, aliases, callbacks, definitions, references, and hover
  • Follow quoted local helpers such as unquote(html_helpers())
  • Scope dispatch parsing correctly in multi-module files
  • Support quoted and tuple dispatch atoms

The Phoenix entrypoint form injects nothing itself. It dispatches on an
atom to a sibling function whose body is a `quote do`:

    defmacro __using__(which) when is_atom(which), do: apply(__MODULE__, which, [])
    def controller do
      quote do
        import Plug.Conn
      end
    end

`parseUsingBody` saw an empty body and gave up, so nothing injected by
these blocks resolved. That is 126 `use` sites in Plausible and 305 in
our own monorepo.

Nothing here is inferred. The consumer writes a literal atom, `__MODULE__`
is the file already being parsed, and the target is a `def` of that name in
that file. `usingDispatchParam` gates on apply/3 targeting `__MODULE__` and
dispatching on the clause's own parameter; `parseDispatchBodies` then parses
each `def name do quote do ... end end` into its own `usingBody`, keyed by
name. `entry.bodyFor(which)` selects one at lookup time from the literal
atom, so targets never merge — a `:controller` consumer cannot see `:view`'s
imports. An atom naming no target injects nothing.

Every gate that fails returns what it returns today, so this only adds
resolutions.

The token walker cannot evaluate conditionals, so a `use` inside a
compile-time branch (`on_ee do use X end`) is included unconditionally.
That over-includes candidate names and never removes one, matching how
the indexer already attributes a bare call to every used module.

`findModulesWhoseUsingImports` now scans dispatch bodies too, so
find-references reaches call sites that got their import this way.

No IndexVersion bump: this is all LSP-layer extraction, and the parser
output and store schema are unchanged.
@JesseHerrick
JesseHerrick merged commit c3e0a5b into main Sep 7, 2026
4 checks passed
@JesseHerrick
JesseHerrick deleted the atom-dispatch-using branch September 7, 2026 22:27
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