Repository navigation
fix(resolution): don't bind a delegating call to its own enclosing method - #1939
danusha2345 wants to merge 1 commit into
Conversation
13181aa to
723b53c
Compare
|
Rebased onto main. The Java and TS self-loop cases now pass on main (#2166, #2169), so they're dropped. Still failing on main and covered here: Scala 🤖 Generated with Claude Code |
723b53c to
da6fc96
Compare
|
Rebased onto main (34ede4d). Two more cases now pass on main and are dropped together with their tests: the Scala receiver that shares a word with the enclosing class (#2221 — the word-overlap branch now refuses the caller itself, so this PR's check there is removed), and Swift's 🤖 Generated with Claude Code |
da6fc96 to
5094435
Compare
|
Rebased onto main (6421644). One more piece is covered by main now and is dropped: the Go exemption in The Go case stays in the recursion test as a control; it passes on main and here. What remains is unchanged: in strategy 3's single-candidate branch, a call through an explicit receiver that is not Checked that no real recursion is lost against main: |
…thod matchMethodCall's name-only Strategy 3 single-candidate branch matched `other.m()` written inside `m()` back to `m` itself whenever `m` is the only method of that name: Scala's `wrapped.unbind(v)` inside WrappedMapping.unbind. An explicit receiver that names another object can't be the enclosing method's own instance, so that self-loop is the one guess known to be wrong — return no edge. (The receiver/class word-overlap branch already refuses the caller itself, colbymchenry#2221.) Real recursion is kept: `this.`/`self.`/`super.`/`cls.`/`Self::` receivers and bare calls (never reach Strategy 3). Go's named method receiver (`func (r *T) m()` calling `r.m()`) is resolved on its declared type before Strategy 3 (colbymchenry#2361), so it needs no exemption here; the test still pins it. Strategies 1/2 (explicit class-name receiver) are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5094435 to
ac21e4b
Compare
Problem
matchMethodCall's strategy 3 guesses the target from the method name: first the single same-language method with that name, then the class whose name shares a word with the receiver. A delegating wrapper calls a method with its own name on another object, so the guess lands on the enclosing method itself, and the graph gets a self-loop.request.getHeaders()insideAhcWSRequest.getHeaders()(Play): "request" overlaps "AhcWSRequest".cache.getIfPresent(k)insideNamedCaffeineCache.getIfPresent(k): the only method with that name.callers/impactthen report the method as recursive, and the edge to the real target is missing.Fix
In strategy 3 only (both branches), a candidate that is the calling method itself is rejected when the call has an explicit receiver naming another object, and the call stays unresolved.
Real recursion is kept:
this,self,Self,superorcls;r.m()insidefunc (r *T) m(): since fix(go): resolve unexported receivers and nested modules within the right package (#2323, #2322) #2361 it is resolved on its declared type before this path is reached, so the exemption this PR used to carry for it is dropped.Strategies 1 and 2 are unchanged, so
ClassName.method()recursion is still resolved.Measured
Twelve projects were indexed with
main(ba3c21e) and with this branch: Kotlin ×3, C, Rust ×2, Go, Python ×2, PHP, C#, and playframework (Java + Scala). Node counts are identical, no edges were gained, and every lost edge is acallsedge whose source equals its target:request.get/delete/headinAhcWSRequest,cache.*,underlying.*,delegate.*Log.d/i/w/einside aLogxwrapper,socket.connectpeer.createOffer,serverSocket.close,_state.update_innerWriter.Writehandle.stopdelegating to the inner handleloader.list_templatesgonet.ListenTCP; the realr.sendBatchAttemptrecursion is keptref.setAccessibleI hand-checked all of them and found no real recursion. One trade-off: recursion through another instance of the same type (
left.visit()insideNode.visit) is now unresolved when it reaches strategy 3. It didn't appear in any of the twelve projects, and no edge is better than a wrong one.Tests
Four new cases in
__tests__/resolution.test.ts:main.this.depth(), baresize(), Go named receiver) passes before and after. It fails if the Go exemption is removed.The related suites pass (898/898). The full suite has no failures from this change.
🤖 Generated with Claude Code