fix(l4): join the SDG port lattice to the statement ddg - #230
Merged
Conversation
The L4 ports and the param_in/param_out/summary edges between them were emitted, but no dependence edge ever touched a port: a formal_in had out-degree zero, so the SDG was two disjoint graphs. Every interprocedural value question then degenerated to an empty answer indistinguishable from 'no flow exists', which is why the SDK refuses slice_forward, paths_between, flows_to_call and flows_to_argument on a Java graph today. SdgPortEdges adds the four missing edge classes, each a re-rooting of something the statement graph already states, so the pass stays pure and engine-free: @formal_in:k -> use mirrors the @entry definition of parameter k return -> @formal_out the statements that hand a value back statement -> actual_in:i the statement that evaluates the arguments actual_out -> statement the statement that consumes the result A call's own body node carries no dependence edges, so the actuals attach to the innermost statement containing the call — or to the call itself for a bare-call statement, where the two share an addressing anchor. That attachment is deliberately coarse: L4 may add reach, never drop it, and the per-argument binding is recoverable from the statement's own incoming edges. Runs after SummaryPass, so summaries are still computed from the statement-level ddg alone. No schema surface changes: no new node kind, edge type or field, and prov stays the closed {ssa, points-to} enum, so the graph contract holds at 2.0.0. On daytrader8 at -a 4: 0 -> 5,108 ddg edges touching a port, and formal_in ports with out-degree zero fall from 1,176 to 140 — all 140 parameters that no statement reads (methods whose body is a single throw, and one unread argument). Output validates against analysis.v2.schema.json and two runs are byte-identical. Closes #227
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.
Closes #227
What
SdgPortEdgesadds the four edge classes that were missing between the port lattice and the statement graph — the same shape codeanalyzer-python#115 and codeanalyzer-typescript#80/#81 landed:@formal_in:k → use@entrydefinition of parameterkreturn → @formal_outstatement → <call>/actual_in:i<call>/actual_out → statementEach is a re-rooting of something the statement
ddgalready says, so the pass is pure and engine-free. It runs afterSummaryPass, so summaries are still computed from the statement-levelddgalone.A call's own body node carries no dependence edges, so actuals attach to the innermost statement containing the call, or to the call itself for a bare-call statement (
foo(x);, where statement and call share an addressing anchor). The attachment is deliberately coarse — every actual of a site is fed by the one statement containing it, not by the reaching definition of that particular argument. L4 may add reach, never drop it, and the precise binding is recoverable from the statement's own incoming edges.No contract change
No new node kind, edge type or field;
provstays the closed{ssa, points-to}enum. The graph contract holds at 2.0.0.Verified — daytrader8 at
-a 4formal_inwith out-degree 0The 140 that remain are parameters no statement reads —
investmentReturn,orderCompletedandpingTwoPhaseare single-throwbodies, andremoveHoldingnever readsorderID.Output validates against
analysis.v2.schema.json; two runs are byte-identical; every new endpoint is a body node of its own callable, so all 5,108 reach the Neo4j projection../gradlew test: 514/515 pass, 4 skipped. The one failure isCodeAnalyzerIntegrationTest("Could not find a valid Docker environment"), which fails identically onmainhere.Known gap
Only the AST L3 engine roots parameter flow at
@entry;--l3-engine walakeepsNormalStatementendpoints only, so it has no such edge to mirror and itsformal_inports stay unattached. The other three classes are engine-independent.Propagation
codeanalyzer-javapin moves to the release carrying this: the port-edge probe passes on its own, so the gate onslice_forward/paths_between/flows_to_call/flows_to_argumentcan lift with no SDK code change, and any committed Java-a 4fixtures need regenerating (ddg roughly doubles).