Repository navigation
Elixir: four extraction defects outside the #1239 D1-D8 list (two recorded as working today) #1729
Description
Summary
While auditing Elixir extraction against a real 829-file Phoenix application, I found four defects that are not in the D1–D8 list of #1239 / docs/elixir-lsp/PLAN.md. Two of them contradict things that plan records as working today, so I am raising them here before they cost @holsee debugging time.
I also have a fork with a broader Elixir grammar-layer rewrite. I am not proposing that upstream — see "Overlap" at the bottom. This issue is about the four defects and about making my other work available if it is useful.
The four defects
1. first_string_arg is never populated for any Elixir call
tree-sitter-elixir attaches no field name to a call's arguments node — its whole field set is key, left, operand, operator, quoted_start, quoted_end, right, target, value. handle_calls() reads ts_node_child_by_field_name(node, "arguments"), which is therefore always null for Elixir.
Consequence: route paths, HTTP/async service URLs and config keys are all dead for Elixir, silently. extract_defs.c has always carried a positional fallback (elixir_call_args()) for exactly this reason; the call side never got one.
→ PR #1721 (open, 54 lines, additions only).
2. Phoenix channel extraction is unreachable in both branches
PLAN.md §1.2 lists "Phoenix channels/PubSub (works today) — extract_channels.c:875-970". It does not work — it has never emitted a single Channel node:
- the emit path (
elixir_process_call) reads the same nonexistentargumentsfield, soelixir_emit_second_arg()returns early every time - the listener path is dispatched by
strcmp(kind, "def") == 0, and there is nodefnode type in the grammar — Elixir definitions arecallnodes.elixir_process_function_def()is dead code, and it also readsnameandparametersfields the grammar does not define.
Fixed and verified against Phoenix.PubSub.broadcast/subscribe, bare push/broadcast, and two handle_in clauses including a guarded one.
3. Phoenix routers mint zero Route nodes
PLAN.md §1.2 lists "Phoenix/Oban/Broadway service patterns (work today)". Oban and Broadway do. Phoenix routes do not.
Every entry in route_reg_suffixes is prefixed . or :: (.get, ::get, .MapGet) because it is matched against the tail of a qualified callee. Phoenix registers with bare macros:
get "/wallets", WalletController, :indexso the callee is exactly get and cbm_service_pattern_route_method() returns NULL. The resolved-QN route-library table cannot help either — Phoenix.Router lives in deps/ and never resolves in-tree.
Fix adds an exact-match bare table (get, post, put, patch, delete, head, options, live, resources, forward), gated to Elixir and consulted before resolution. Exact and not suffix on purpose: a suffix rule would classify widget, target and budget as GET routes. extract_handler_arg() also needed to accept Elixir's alias/dot handler node, without which no route gets a HANDLES edge.
Depends on #1721 for the path argument.
4. Elixir functions carry no complexity, fingerprint or line count
Every Elixir Function ships complexity = 0, cognitive = 0, lines = 0 and no MinHash fingerprint, so Elixir is invisible to complexity/bottleneck queries and never participates in SIMILAR_TO — while the query_graph tool description states that "every Function and Method node carries queryable complexity properties".
cbm_compute_complexity() matches on node type, and Elixir has no branching node types: if, unless, case, cond, with, for, try and receive are ordinary call nodes distinguished by the identifier in callee position, and every arm is a stab_clause. That is also why elixir_branch_types = {"call"} in lang_specs.c has never been usable — it would score every function call as a decision.
Measured effect
Fresh index of an 829-file Phoenix application, plus elixir-lang/elixir (6,346 .ex functions) for the complexity numbers:
| before | after | |
|---|---|---|
| Route nodes | 0 | 180 |
| HANDLES edges | 0 | 153 |
Functions with complexity > 0 — elixir-lang/elixir |
4,002 (63%) | 4,753 (75%) |
Functions with complexity > 0 — Phoenix app |
2,023 (49%) | 2,500 (61%) |
| Functions with a fingerprint | 7 / 4,504 | most |
For scale, the TypeScript and Python sources in that same Phoenix repo score 20 of 386 (5%).
Overlap with #1239 — and an offer
My fork also carries a grammar-layer rewrite that overlaps @holsee's D1–D8 almost item for item: guarded def heads (D1), enclosing-function attribution (D2), name/arity identity (D3 — resolved as an arities def field, keeping the QN string format unchanged, which is the option PLAN.md flags as preferable), the full def* family (D4), imports nested in defmodule (D5), nested module QNs (D6), and stronger Elixir test contracts (D8 — 18 extraction tests).
I am deliberately not opening PRs for any of that. @holsee has been staging this since July across 15+ branches and it would be a competing implementation, which helps nobody.
If it is useful as reference material — a second implementation to diff against, or tests to lift — it is at henry-hz/codebase-memory-mcp, branch fix/elixir-routes-channels-complexity-heex. Take anything, or ignore it entirely; no attribution needed. One caveat if you do look: the dotted-module import resolution in pass_pkgmap.c there has no test and touches a candidate-ordering path shared with Lua and R, so treat that part as unproven.
Proposed delivery
Four small PRs, each independent except where noted, all signed off and gated:
- fix(elixir): populate first_string_arg for Elixir calls #1721 —
first_string_arg(open) - channels — independent
- complexity + fingerprint + lines — independent
- Phoenix routes — after fix(elixir): populate first_string_arg for Elixir calls #1721
Happy to reorder, split further, fold any of them into @holsee's phases instead, or drop them if they conflict with the staged plan. Also happy to hold 2–4 until there is appetite.
Separately: .heex / .eex templates are not indexed at all today, so the LiveView template layer is invisible. That needs a vendored grammar, which CONTRIBUTING says requires prior approval — I have it working locally and will open a separate issue rather than assume.
Activity
DeusData commentedon Oct 25, 2026
Thank you for separating the four Elixir defects and the overlapping work. Delivery order and coordination with #1239 need maintainer direction before further contributions are invited. Sorry for the delay; this is waiting on maintainer follow-up, and I’ll follow up soon.
DeusData commentedon Oct 27, 2026
Defect 2 (Phoenix channel extraction) is fixed on main by aaf9021 via #1730. Thank you, Henry, for tracing it to both the missing arguments field and the def node type the grammar never produces. Defect 1 landed earlier via #1721 (ffb5ebe). Defect 4 is still open in #1731, and defect 3 (Phoenix routes) has no PR yet, so this issue stays open for those.