fix(erlang): give same-name different-arity functions separate arity-qualified nodes (#1610) - #1615
Conversation
…qualified nodes (#1610) Arity is part of an Erlang function's identity: f/1 and f/2 are unrelated definitions. The extractor merged consecutive same-name fun_decls regardless of arity, so both landed in one node (or two nodes with colliding qualified names when interleaved), the wrong -spec/signature/span was attributed, the everyday f/N -> f/N+1 delegation became a self-loop, and -export([f/1]) marked every arity exported. - Each (name, arity) group now gets its own node; qualifiedName carries the canonical spelling (mod::f/1). Node names stay bare for search. - -export and preceding -spec attribution are per-arity. - Call/fun refs carry the call-site arity (f/1, mod::f/2, fun mod:f/1, gen_server handle_call/3 + handle_cast/2, static MFA lists); the matcher resolves them only to a def of exactly that arity, same-file first, and refuses to guess a sibling arity (silent beats wrong). Arity-less dynamic MFA refs resolve only when a single arity exists. - The behaviour dispatch synthesizer selects the implementer node of the site's arity, and erlangArityAt now skips <<binary>> literal commas per its own docstring (#1358) - dispatch sites passing binaries no longer miscount. - Explore/node symbol lookups accept the written mod:fn/3 spelling against the new arity-qualified names. Cowboy: nodes 3668 -> 3748 (+80 arity splits, no explosion), behaviour dispatch edges 38 -> 44, cowboy_req header/2 and header/3 split with the right specs and a real /2 -> /3 delegation edge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LxZj6W6Y1SHXwvpT3uwJpK
|
I reviewed and reproduced two remaining correctness gaps in this patch:
The node/edge shape also needs an I pushed a focused follow-up commit that fixes all three points and adds permanent end-to-end regressions:
Validation after the final change: |
|
Verified this branch end-to-end — the three shapes are fixed, and the One small thing: arity is counted with f(A, % why
B) % read as f/3 — the edge is silently droppedOnly rebar3 is affected in the projects I checked (2 real edges). I put a patch and a regression test for it in #1619, targeting this branch. |
Fixes #1610. Also fixes #1358 (the
<<binary>>arity miscount in behaviour dispatch, reported separately and hit by the same code path).Problem
Arity is part of an Erlang function's identity —
f/1andf/2are unrelated top-level definitions — but the extractor merged consecutive same-namefun_decls regardless of arity. Reproduced on main exactly as reported:f(X) -> …. f(X, Y) -> ….→ one node spanning both, with the first definition's signature;f/1, g/0, f/2→ two nodes with identicalqualified_name;cowboy_req'sheader(Name, Req) -> header(Name, Req, undefined).→ a self-loopheader → header, with the-specfor/3swallowed by the merged span;-export([f/1])marked every arity exported.Fix
qualifiedNamecarries the canonical spelling —mod::f/1— while the node name stays bare so search and bare-name matching are unchanged.-exportand-specare per-arity.-export([f/1])exports exactlyf/1; a spec sitting between two arities attaches to the arity its signature names.f/1, remotemod::f/2,fun f/1/fun mod:f/1values,gen_serverdispatch (handle_call/3,handle_cast/2), and spawn/apply MFA lists (spawn_link(?MODULE, work, [A, B])→work/2).<<1,2,3>>binary-literal commas per its own docstring (Erlang: erlangArityAt doesn't skip <<binary>> literals (contrary to its docstring), so binary-arg dispatch sites get an inflated arity and the behaviour-callback edge is dropped or mis-linked — verified #1358) —Mod:decode(<<1,2,3>>, Opts)counts 2, not 4.codegraph_explore/codegraph_nodeaccept the writtenmod:fn/3spelling against the new arity-qualified names (the issue's measuredcowboy_stream_h:request_process/3shape).Validation
Minimal fixtures (all three reported shapes) now index as
gap::f/1+gap::f/2, distinctinter::f/1/inter::f/2, and a realdeleg::header/2 → deleg::header/3edge with no self-loop.Cowboy (fresh
--depth 1clone, this build vs unmodified main build):cowboy_req::headerheader/2(420–421, its own spec) +header/3(424–425, its spec)header/2 → header/3callsedges drop 6,059 → 5,656: a sample of every removed pair shows the false-positive class the issue predicted — out-of-repo/BIF calls (length/1,error/1,quicer:*) that previously name-matched onto unrelated same-named in-repo functions now stay unresolved.Tests: new arity coverage in extraction + a new arity-resolution integration suite + a #1358 binary-literal behaviour test; updated existing Erlang expectations to the arity-carrying spellings. Full suite: 3,018 passed, 0 failed.
No migration: an existing Erlang index picks the new shape up on its next re-index (
codegraph sync/ re-init).Erlang is wasm-only (not in the native kernel), so there is no kernel-parity surface.
🤖 Generated with Claude Code
https://claude.ai/code/session_01LxZj6W6Y1SHXwvpT3uwJpK