Repository navigation
Conversation
|
Checked 9a41129 against Build and tests: Edge diff,
One regression. In a private Kotlin project, five test methods call a field typed as the concrete class: private lateinit var probe: HttpProbeImpl // implements the Probe interface
fun testA() { probe.probe("relay", "drone", "secret") }
fun testB() { … probe.probe(…) … }
fun tearDown() { probe.close() }
fun otherTest() {
val fake = object : Probe { override fun probe(…) = …; override fun close() = Unit }
…
}
Suggested guard: treat members of an anonymous class that sits inside a function the way Everything else matches the numbers in the description. Nice split of #1872. |
|
Thanks for the detailed edge comparison and the concrete Kotlin example. I reproduced the name-only fallback in a focused regression test: before the fix, I pushed
I cannot access the private Kotlin corpus. Could you recheck the five |
|
Verified 4fedc76 on the same private Kotlin app, plus two others.
LGTM from my side. |
|
I repeated the post- The private Kotlin repro is fixed per the recheck above. I found one separate, source-confirmed false edge in this public corpus: Focused |
|
Reproduced with the three real files at
My guess is that your corpus doesn't include #1933 already covers this: once the receiver's declared type is known and isn't a project type, it emits no edge. With both PRs applied, the result is the same as A narrower guard could also go in #1927, independent of #1933: don't let an |
|
Follow-up to the
These are independent of #1927 and #1933, so this PR's existing commits remain unchanged. Each new PR has a focused regression test, a passing build, and a passing standalone full suite. |
|
The three-file AOSP reproduction still shows a false edge on this PR alone when |
4fedc76 to
58c04ea
Compare
|
Rebased this PR onto #1933 ( |
Integrate Java/Kotlin anonymous inheritance follow-up from upstream colbymchenry#1927
inferJavaFieldReceiverType reads a field's type from its signature, in the Java shape `Type name`. Kotlin properties are indexed without a signature, and primary-constructor properties (`class A(private val repo: Repo)`) are not indexed at all, so every Kotlin `prop.method()` got no type and fell through to name-only guessing: the interface method, or any same-named method elsewhere (`probe.close()` on a `lateinit var probe: HttpProbe` resolved to an unrelated class's `close`). For Kotlin the type is now read from the declaration: the property's own lines (`name: Type`, or `name = Type(…)`), or the class header before its first member for a constructor property. A nested type keeps its outer type (`HardwareLock.Lease` → `HardwareLock::Lease`), so it matches that `Lease` and not another class's. resolveMethodOnType still validates the method. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion tree-sitter-kotlin has no `fun interface` (Kotlin 1.4 functional interfaces). The declaration parsed as a broken function, and when a doc comment followed it, error recovery swallowed the NEXT declaration too: an interface and its methods went missing, surfacing as top-level functions, or a class vanished with its members. The Kotlin extractor's preParse now blanks the `fun` of a `fun interface` declaration (three spaces for three letters, so offsets hold); the kernel receives the same bytes through the preParse hoist and no longer defers these files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nguessed Two more receivers the Kotlin resolver could not type: - A local or property bound to a call (`val lease = HardwareLock.tryBegin()`, `private val schema = Checker.load()`) is typed by the callee's declared return type, from its signature. A return type nested in the callee's owner keeps it (`Lease` in `HardwareLock` → `HardwareLock::Lease`). - A receiver whose type the project does not declare (`Regex`, `Properties`, a call on `Executors`) now gets no edge. The name-only fallback used to bind it to any project method of the same name: a `regex.find()` to an unrelated `find`, `socket.connect()` to a `connect` elsewhere, a `close()` to itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…railing-lambda constructors
More Kotlin receivers the resolver could not type, found on real apps:
- A `val` property is indexed as a `constant` and a companion-object
property as a `variable`; the property lookup only took `field`.
- `var mode = Mode.ON` is typed by its enum (project enums only; `Limits.MAX`
is an Int).
- `val t = Thread { … }` is a constructor too (trailing lambda, no parens).
- `val old = current ?: return` / `current!!` / `val x = current` take the
aliased value's type; `requireNotNull(x)` / `checkNotNull(x)` take x's.
- A typed parameter of the enclosing function or overridden callback
(`onOpen(webSocket: WebSocket, …)`) is used when nothing else names one.
- Known stdlib factories (`listOf`, `mutableMapOf`, `lazy`, `thread`, …)
return a library type; any other library function leaves the type unknown.
A library type still gets no edge: `thread.join()`, `process.destroy()`,
`webSocket.send()` no longer bind to project methods (or a test fake) of the
same name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Kotlin call through a receiver chain (`engine.pump.drain()`, `this.engine.drain()`, `a?.b?.c()`) was extracted as the bare method name, so it could only be name-guessed: a same-named method in the caller's file, or any project method when the chain ended in a library type (`runtime.reconnectTask?.cancel()` on a `ScheduledFuture`). The extractor (wasm path and kernel, in parity) now keeps a chain of up to four identifier segments. The resolver types the first segment as a single receiver (`this` is the enclosing class, a type name its object or companion), then each next segment as a property or enum entry declared in the class of the type before it, read from that class's own file. A typed chain resolves on its type; a chain through a library type gets no edge unless the project declares an extension of that name on a library type; an untyped chain resolves as the bare method name, exactly as before. A constructor call with type arguments (`Crate<Int>()`, `mutableListOf<T>()`) now types its value too. The alias test now picks the anonymous object's `onOpen` and ignores synthesized override edges, so it holds once object-literal members are extracted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nonymous objects A receiver (or chain segment) that the enclosing class does not declare is looked up in its project supertypes, read from each class header (breadth- first, at most four levels); a library or ambiguous supertype is not walked, so the receiver stays unknown and keeps the name-only resolution. The local declaration scan continues from a function nested in another (an anonymous object's member, a local function) into the outer function above it, skipping sibling functions whose locals are not visible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
12aec01 to
fb7ff1d
Compare
Summary
Preserve anonymous Java classes and Kotlin object-literal members in both extraction backends, resolve nested supertypes within their source/package context, and resolve Kotlin calls through declared property types. Missing external types and ambiguous anonymous owners remain unresolved instead of creating unrelated edges.
This branch includes the Kotlin receiver work from #1933 with its original authorship. It is tested independently on current upstream; the preferred merge order or treatment of overlapping #1933 commits remains a maintainer decision.
Validation
6560052a6f856855d3f71eee838fd66ccfa4285d; tested headfb7ff1df904955bcdec12da26cf8638060603f69.5685cc97ba8ed8e08b81658b526b46485c3c4fe3e0ea2d4307f2d27855445e25).