feat(resolution): inherited this.X, Java/Kotlin cross-file method refs, Swift type scoping (#810)
Three callback-registration shapes deferred from #756/#808, one arc: 1. INHERITED this.X (TS/JS + every this.-routed language): a `this.<member>` registration whose member isn't on the enclosing class defers to a second pass (resolveDeferredThisMemberRefs — in-memory like deferredChainRefs, runs after implements/extends edges persist, same lifecycle as the #750 conformance pass) and resolves up the supertype chain, depth-capped BFS, validated targets only. `bus.on("submit", this.handleSubmit)` in a subclass links to FormBase::handleSubmit; same-named methods on unrelated classes never match. this.-prefixed candidates skip the extraction name gate (an inherited member can't be in definedHere). 2. JAVA/KOTLIN qualified method refs: `Handlers::onMessage` / `OtherClass::handle` emit QUALIFIED names resolved by the scoped suffix-matcher — cross-file capable, gated on the scope name being a same-file type or an imported name (dotted JVM imports now contribute their last segment). `this::m` and `super::m` route through the class-scoped resolver (super rides the supertype pass). References through a VARIABLE (`subscriber::onNext`) deliberately produce nothing — receiver type is unknowable; RxJava's baseline bare capture was resolving these to same-named same-file methods (a test method "registering" an anonymous class's onNext) — the rework drops 18 such wrong edges and keeps the 7 genuine Type::method refs RxJava's main tree actually has. 3. SWIFT enclosing-type scoping (implicit self): bare callback names match methods only of the from-symbol's own type (extension/nested scopes reconciled by suffix), and top-level code never matches methods. Alamofire: −44 wrong edges (parameters like `request`/`data`/`retrier` resolving to same-named methods on unrelated protocols), all verified; the same-class param collision (`task`) remains and is documented. New ResolutionContext.getNodeById lets matchers derive the from-symbol's class scope. Controls: redis/fmt fnref edges byte-identical; excalidraw stable; typeorm +4 genuine inherited-getter dependencies; zero calls edges changed on any of 7 A/B repos; nodes identical everywhere. Kotlin companion-object members extract unqualified (pre-existing) so `Type::companionFn` stays silent rather than guessing — documented. Full suite 1389 passed. EXTRACTION_VERSION 20 → 21 (re-index to benefit). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
38eb4e688c
commit
38095aa95b
@@ -171,25 +171,39 @@ Index cost on redis: +6% time, +5% db size.
|
||||
without local-scope tracking — the data-flow frontier deliberately left
|
||||
uncovered. ~1-2 per 20 sampled edges on callback-heavy repos; the file-level
|
||||
dependency is real in every observed case.
|
||||
- **Swift single same-named method collisions** (`request(self, didFailTask:
|
||||
task…)` where one `task` method exists): the overload-family rule only
|
||||
refuses when ≥2 same-named methods share the file. Alamofire-style
|
||||
API-mirrored param naming keeps a residual; needs same-type scoping (v2).
|
||||
- **Swift same-class param collisions** (`eventMonitor?.request(self,
|
||||
didFailTask: task…)` where the enclosing type ALSO has a `task` method):
|
||||
enclosing-type scoping (implicit self — methods match only the from-symbol's
|
||||
own type, top-level bare ids never match methods) eliminated the CROSS-class
|
||||
collision class on Alamofire (−44 wrong edges), but a parameter named after
|
||||
a method of the SAME type is statically indistinguishable from an
|
||||
implicit-self method value. Residual, documented.
|
||||
- **Pascal paren-less calls** (`Result := DoInitialize`): captured as
|
||||
references (Pascal can't distinguish a procedure VALUE from a paren-less
|
||||
CALL without types). The dependency direction is correct and these calls
|
||||
were previously invisible entirely (#791) — strictly more truth, imperfect
|
||||
label.
|
||||
- **Java/Kotlin cross-file method refs** (`OtherClass::method` without the
|
||||
defining class imported as a simple name): gated away; same-file and
|
||||
`this::m` forms work.
|
||||
- **Java/Kotlin method refs through a VARIABLE** (`subscriber::onNext`,
|
||||
`m::run0`): receiver type unknown statically — deliberately no edge (the
|
||||
obj.method class). RxJava's baseline bare capture was resolving these to
|
||||
same-named same-file methods (a test method "registering" an anonymous
|
||||
class's `onNext`); the qualified rework drops them. `Type::method` resolves
|
||||
cross-file (scope gated on same-file types ∪ imported names, incl. the last
|
||||
segment of dotted JVM imports); `this::m` / `super::m` ride the
|
||||
class-scoped + supertype path.
|
||||
- **Kotlin companion-object members** extract UNQUALIFIED (node `handle`, not
|
||||
`KtHandlers::Companion::handle` — pre-existing extraction shape), so
|
||||
`KtHandlers::handle` refs to companion members stay silent rather than
|
||||
guess. Fix belongs in kotlin companion extraction.
|
||||
- **Swift cross-file bare references**: Swift sees module-wide symbols without
|
||||
imports, so cross-file bare callbacks only resolve when repo-unique.
|
||||
imports, so cross-file bare callbacks only resolve when repo-unique
|
||||
(functions; methods are enclosing-type-only). Cross-TYPE `#selector`
|
||||
targets (rare — target-action is normally self) are scoped away too.
|
||||
- **PHP string callables**, **Ruby bare symbols** outside `method(:sym)`,
|
||||
**`obj.method` member values** where `obj` isn't `this`/`self`: deferred.
|
||||
- **TS/JS `this.X` to inherited members**: the class-scoped resolver matches
|
||||
the enclosing class's OWN members only — `this.handleClick` defined on a
|
||||
superclass yields no edge (would need the supertype walk; deliberate v1).
|
||||
Reading a getter into a local (`const s = this.snapshot`) produces a
|
||||
- **`this.X` inherited members resolve through the supertype pass**
|
||||
(`resolveDeferredThisMemberRefs`, depth-capped BFS over implements/extends,
|
||||
runs after edges persist — same lifecycle as the #750 conformance pass).
|
||||
Reading a getter into a local (`const s = this.snapshot`) still produces a
|
||||
references edge to the getter — a true dependency with an imperfect
|
||||
"registration" flavor.
|
||||
|
||||
Reference in New Issue
Block a user