fix: resolve Solidity qualified library calls Lib.fn() (AGE-5)#32
Merged
saldestechnology merged 2 commits intoJul 11, 2026
Conversation
Applying a modifier to a function (e.g. `function f() onlyOwner`) produced no edge in the code graph, so `ctx query callers <modifier>`, `impact`, and `v1.edges` could not answer access-control questions. Modifier *definitions* were already emitted as symbols; only the edge was missing. Add `extract_modifier_edges`, which walks each function's `FunctionAttribute::BaseOrModifier` attributes and emits a `calls` edge from the function to the modifier, resolving `target_id` against the modifier symbol so it participates in fan_in/impact traversal. Also covers constructor base-contract invocations. Includes a parser test asserting the resolved edge. Refs AGE-4
Qualified calls like `ChessPureLib.isKingInCheck(...)` were captured as edges but left unresolved (target_id NULL) whenever the bare function name existed in >=2 files: the parser discarded the `ChessPureLib.` qualifier and the resolver's unique-name step bails when the bare name is ambiguous. Because fan_in/fan_out/complexity/reachability count only resolved edges, a callee's metrics silently collapsed to 0 -- corrupting hotspots ranking, callers/impact, and any reachability closure on Solidity-primary repos. Capture the qualifier: for `Name.member(...)` the parser now stores the fully qualified name (e.g. "ChessPureLib.isKingInCheck") in the edge's `context`, keeping `target_name` as the bare name for fallback. Add a resolver Step 0 that matches an edge's `context` exactly against a symbol's `qualified_name` (Solidity library methods already carry it), placed before the substring LIKE step so the exact target wins and later NULL-only steps skip the row. This disambiguates the intended library method even when the bare name collides across files/languages. Same treatment applied to block-style calls. Adds an index-level test covering an ambiguous bare name resolved via the qualifier. Refs AGE-5
saldestechnology
force-pushed
the
johan/age-4-solidity-modifiers-are-not-modeled-in-the-graph-no-edges-no
branch
from
July 11, 2026 14:19
e14986a to
ac295b2
Compare
saldestechnology
force-pushed
the
johan/age-5-solidity-qualified-library-calls-libfn-go-unresolved-when
branch
from
July 11, 2026 14:19
a403010 to
c10de59
Compare
Base automatically changed from
johan/age-4-solidity-modifiers-are-not-modeled-in-the-graph-no-edges-no
to
main
July 11, 2026 15:13
saldestechnology
deleted the
johan/age-5-solidity-qualified-library-calls-libfn-go-unresolved-when
branch
July 11, 2026 15:14
saldestechnology
added a commit
that referenced
this pull request
Jul 11, 2026
…es + edges, providers) (#33) The AGE-2/3/4/5 PRs (#29-#32) shipped behavior changes without doc updates. Bring docs/website in line: - index/embed run in parallel by default; document --serial and demote -j/--parallel to a retained no-op (indexing, getting-started, code-intelligence help snapshots + synopsis) - ctx duplicates now fingerprints Solidity via the solang-parser lexer; drop the "skipped" caveats and set skipped_languages: [] (duplicates, code-intelligence, json-output, score) - Solidity modifier applications emit calls edges and qualified library calls Lib.fn() resolve (language-support) - round out provider docs: add Ollama to the embed providers table and offer --provider <local|openai|ollama> in similar/smart (code-intelligence, similar, smart)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Solidity qualified calls
LibraryName.fn(...)(e.g.ChessPureLib.isKingInCheck(...)) were captured as edges but frequently left unresolved (target_id = NULL) whenever the bare function name existed in ≥2 files (e.g. a Solidity library and a TypeScript mirror). Sincefan_in/fan_out/complexity/reachability count only resolved edges, the callee's metrics silently collapsed to 0 — corruptinghotspotsranking,query callers/impact, and any reachability closure. Higher severity than the sibling Solidity issues because it silently corrupts existing metrics rather than omitting a feature.Root cause (two drop points)
MemberAccessarm ofextract_calls_from_exprkept onlymember.nameand threw away theChessPureLibobject; the edge stored the bare name withcontext: None.resolve_edge_targets's unique-name step only resolves when the baretarget_namematches exactly one symbol; ambiguous names were left NULL. No step consulted the qualifier orqualified_name.Fix
src/parser/solidity.rs): forName.member(...)calls, store the fully qualifiedName.memberin the edge'scontext(kepttarget_name= bare name for fallback andget_incoming_edges). Complex/chained receivers stay unqualified. Same treatment for block-style calls.src/db/schema.rs): new Step 0 resolves an edge whosecontextequals a symbol'squalified_nameexactly (Solidity library methods already carryqualified_name = "ChessPureLib.isKingInCheck"), when unique. Ordered before the existing substring-LIKEstep so the exact match wins and latertarget_id IS NULLsteps skip the row — no regression to other languages' resolution (verified: the LIKE step keeps itstarget_id IS NULLguard).The optional same-language tiebreak for unqualified ambiguous names was deferred (would risk cross-language behavior changes; the exact-qualified step resolves the reported cases).
Tests
test_solidity_qualified_call_resolves_across_ambiguous_bare_name: two libraries defineisKingInCheck(ambiguous, COUNT=2) and a caller doesChessPureLib.isKingInCheck(...); asserts the edge resolvestarget_idto the correct library method, not NULL and not the other file's symbol.cargo fmt --all -- --check✅cargo clippy --all-targets -- -D warnings✅ (0 warnings)cargo test✅ (304 lib + all integration suites, 0 failures)Refs AGE-5. Depends on #29 (AGE-4).