Repository navigation
fix(java): resolve receivers on their declared type, leave library types unguessed - #1942
Open
danusha2345 wants to merge 1 commit into
Open
danusha2345 wants to merge 1 commit into
danusha2345 wants to merge 1 commit into
Conversation
This was referenced Sep 24, 2026
danusha2345
force-pushed
the
fix/java-receiver-type
branch
from
September 27, 2026 15:11
35a787b to
0b4bd03
Compare
Contributor
Author
|
Rebased onto main after the resolution wave. 7 of this PR's 12 cases now pass on main (#2126, #2166, #2169, #2171, #2177), so their code and tests are dropped: the local-variable regex (main's version with type arguments and for-each is kept) and
🤖 Generated with Claude Code |
danusha2345
force-pushed
the
fix/java-receiver-type
branch
4 times, most recently
from
October 7, 2026 11:53
86f3552 to
5a22e2a
Compare
…pes unguessed
Receivers the field lookup missed are typed: `Outer.this.f`, and a field
of an outer class read inside an inner or anonymous class (the lookup
only read the tightest enclosing class, so `mStore.save()` inside a
`new Runnable() {…}` went to a name-only guess). A chain of fields
(`owner.ctx.getResources()`) is read hop by hop, and a hop whose type is
a library class gets no edge instead of a same-named project method.
A type is read with the package or outer class written in source and
with the file's imports, so `import java.util.Iterator` is not taken for
a same-named type nested in another package of the project, and an
imported nested type (`import p.Http.Cookie`) is the one the import
names. Among same-named candidates no import pins, a Java call prefers
the Java declaration over a Scala or Kotlin one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
danusha2345
force-pushed
the
fix/java-receiver-type
branch
from
October 7, 2026 16:12
5a22e2a to
80b7d4e
Compare
This branch has not been deployed
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.
Problem
Java already types a call receiver from a local declaration or a plain field. Two gaps remain.
parcel.readInt()on anandroid.os.Parcel→ a projectVersionedParcel.readInt;mHandler.post(...)orlist.size()→ any projectpost/size;Log.e(...)→ a projectFalsingLog.e.this.fandOuter.this.f;Map<String, Foo> byName);this.mOwner.mRepo.save()).On decompiled Android SystemUI (3,421 Java files),
mainhas about 21.8k call edges whose receiver's declared type is a library class but that land on a project method. Another ~2.9k have a project-class receiver but go to an unrelated class. In playframework's Java sources (790 files) the numbers are ~1.7k and 125.Fix
All changes are in
src/resolution/name-matcher.ts. The extractor already emits the full receiver text, so the kernel and extraction version are unchanged.A declared type is read for every receiver shape above. A chain is typed one hop at a time, and each hop's field type is read with its own file's imports.
A written qualifier is kept:
Map.Entryandplay.api.mvc.BodyParser<B>stay as written, andimport p.Http.Cookiepins that exact nested class.When the declared type is a library class, the call gets no edge. A type counts as a library class when:
import java.util.Iteratornext to a projectUByteArray.Iterator);A short all-caps name (
T,VH) is taken for a type parameter and left alone.A static call on an imported or
java.langlibrary class (Log.d,TextUtils.isEmpty) is left unresolved the same way.When no import decides between same-named types, a Java call prefers the Java declaration over a Scala or Kotlin one (
play.data.Formvsplay.api.data.Form).This is the Java counterpart of the Kotlin receiver typing in #1933. The two share an idea but not code yet:
JAVA_EXTERNAL_TYPEhere,KOTLIN_EXTERNAL_TYPEthere. Whichever lands second will need a small textual merge ininferJavaFieldReceiverType, whose Java/Kotlin field block this PR narrows to Kotlin.Measured
Each corpus was indexed with
main(ba3c21e) and with this branch. Node counts are identical.Every gained edge is a typed resolution at 0.9. I hand-checked samples against source; every sampled edge was correct:
Indexing time on SystemUI isn't higher.
Known limits
PARSER.parseFrom→Parserrather thanAbstractParser. This is the same choice as for Kotlin.records aren't indexed as types, an existing extractor gap. A call on a record-typed receiver now gets no edge instead of a guess.Tests
The new
__tests__/java-receiver-type.test.tshas 12 cases: 8 fail onmain, and 4 are regression guards. The Java-over-Scala guard also fails if the tie-break is removed. The full suite passes: 275 files, 4,730 tests.🤖 Generated with Claude Code