feat(code-graph): type-flow resolution and ast-driven walking for ssa
What does this MR do and why?
Part of #456 (closed), #457 (closed). Depends on !887 (merged), Relates to orbit#3 (closed). Extends the v2 code graph pipeline with three major capabilities: AST-driven SSA construction per Braun et al., type-flow chain resolution for Java/Kotlin, and expression chain extraction/resolution for multi-hop method calls.
AST-driven SSA walker (Braun et al. CC 2013)
The DSL parser now retains the tree-sitter AST. The FileWalker walks it inline, creating SSA blocks for branches, loops, and scopes exactly as the paper describes:
- Branch arms get separate blocks, merging at a join point with phi nodes
- Loop headers are unsealed until the back-edge is added, then sealed
- Nested branches propagate correctly (inner merges flow to outer merges)
This replaced an earlier flat walker (byte-range heuristics) with the paper's actual protocol — net negative lines.
Type-flow chain resolution
ChainMode::TypeFlow is now functional for Java/Kotlin. When a variable has a declared type or is assigned from a method with return_type metadata, member access chains resolve through the type hierarchy:
// 4-hop chain — each step resolves via return_type
pool.getConnection().getDb().execute().fetchAll();
// Implicit this — bare helper() resolves as this.helper()
helper();
// super — resolves through parent class
super.baseMethod();
// Return type propagation through binding
UserService svc = getService(); // getService returns UserService
svc.query(); // resolves to UserService.queryExpressionStep chain extraction
References with receivers produce structured ExpressionStep chains instead of flat name strings. The chain builder is fully language-agnostic — driven by per-language ChainConfig (ident node kinds, this/super kinds, field access patterns, constructor patterns). The resolver walks chains left-to-right, threading the resolved type through each step, with compound SSA key fallback for Python instance attributes.
What's new
MemberIndexwithsuper_typesBFS for inherited member lookupResolutionRulesholdsOption<LanguageSpec>— single source of truth, no config duplicationinstance_attr_prefixesonBindingRule—self.Xwritten to class scopeReceiverExtract(Field / FieldChain) onReferenceRuleChainConfigonLanguageSpecfor chain buildingextract_rhs_nameunwraps call expressions via language spec rules- Java:
field_declaration,catch_formal_parameter,switch_statement,ternary_expression - Kotlin:
companion_object→DefKind::Class,ChainConfig - Python:
ChainConfig,receiver_chainfor attribute calls
Test coverage — 38/38 suites passing
- 9 conditional binding tests (if/else phi, try/except, trivial collapse, nested, elif, reassignment-kills-phi, no-else, false positives, no-duplicates invariant)
- 10 Java type-flow tests (typed locals, inheritance,
this,super, implicit this, return type propagation, chained calls, 4-hop deep chain, diamond inheritance, cross-contamination check) - 2 Java cross-file type-flow tests
- 3 Python expression chain tests (value-flow alias, cross-file import chain)
- All 35 original suites still passing