You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Elixir: def with a when guard is silently dropped from the graph; multi-clause defs collapse to the last clause #979
Class T L1-6
Function plain L2-2
Function multi L4-4
Function multi L5-5
guarded is gone. multi is emitted twice — once per clause — which is correct at parse time, but the built graph keeps only one multi node, with the last clause's line range.
Root cause
Guards._elixir_function_name_and_params (code_review_graph/parser.py:6563) iterates the children of a def's arguments node and only handles two shapes: call (the head) and identifier (zero-arity). With a guard, tree-sitter-elixir wraps the head in a binary_operator — guarded(x) when is_binary(x) parses as binary_operator(left: call, operator: "when", right: call) — so neither branch matches, the function returns (None, None), and _extract_elixir_constructs bails at the if fn_name is None: return False check (parser.py:6671). The function is skipped with no diagnostic.
Fix sketch: when the child is a binary_operator with operator "when", descend into its left (recursively — chained guards like def f(x) when g1 when g2 are legal Elixir and nest further) and treat that node as the head.
Multi-clause. The parser is fine here; the loss happens downstream. Each clause produces a NodeInfo with the same qualified name, and the graph layer dedups by qualified name, so the last clause wins — line_start/line_end/params all come from clause N instead of spanning the definition. Merging per qualified name at insert time (min line_start, max line_end) or keying function nodes by name/arity would fix the line numbers at least.
Why it matters
On a real Elixir/OTP codebase this is not an edge case — guards are idiomatic. Indexing an 847-file Elixir umbrella repo, every public function written as def foo(x) when is_binary(x) do ... is absent from the graph, so callers_of / callees_of for those functions return nothing and the CALLS edges pointing at them are dropped. Spot-check on that repo: 5 of 5 public functions in one module (pattern_from_url, acquire_permit, release_permit, report_throttle, get_throttle_state — all guard-clause defs) produced zero nodes.
Reopening: #980 closed this automatically but fixes only part of it. Guarded def clauses are now indexed and short-form bodies are walked. A multi-clause function still keeps the line range of its last clause, so that part stays open.
Activity
tirth8205 commentedon Nov 6, 2026
Reopening: #980 closed this automatically but fixes only part of it. Guarded
defclauses are now indexed and short-form bodies are walked. A multi-clause function still keeps the line range of its last clause, so that part stays open.fix(parser): a multi-clause Elixir function is one node spanning its …