Repository navigation
fix(kotlin): a property carries its visibility, and a private class hides its members - #1761
danusha2345 wants to merge 2 commits into
Conversation
|
Merged current |
|
Merged current |
|
Merged current |
|
Merged |
9ca360e to
f9ede97
Compare
|
Rebased onto main. A bare 🤖 Generated with Claude Code |
f9ede97 to
f22f28b
Compare
|
Rebased onto main (34ede4d). Since #2209 a call from production code never reaches a test file's symbol, so the private-class case as written ( 🤖 Generated with Claude Code |
fa5c083 to
0032b0e
Compare
1090ed3 to
113bebc
Compare
`private val` / `private var` at class or object scope were indexed with no visibility, so colbymchenry#1745's Kotlin rule — which declines a `private fun` in another file — read every property as public. On a Kotlin + JS + Go app 24 cross-file calls landed on private properties: a validator's `token(...)` onto another class's `@Volatile private var token`, and JS, Go and Python callers onto Kotlin test fixtures' private fields. Both extractors read the `modifiers` child the way functions already do; the parity fixture gains a `private val` and an `internal var`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`private class Clock(var value: Long) { fun now() = value }` in a test:
the method is public, the class is not, so nothing outside the file
can name `now` — three `now()` calls in the app's gimbal control still
resolved onto it after the property fix. A candidate whose enclosing
class/object in its file is `private` is declined for the languages
where `private` is file-local; found by line range, memoised per node.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
113bebc to
2367ce7
Compare
…mchenry#2972; 10 landed PRs yield to main; EXTRACTION_VERSION 56) Main landed ten more of our PRs as our own commits with the maintainer's additions (colbymchenry#2923 ← colbymchenry#1936, colbymchenry#2924 ← colbymchenry#1951, colbymchenry#2925 ← colbymchenry#1939, colbymchenry#2930 ← colbymchenry#2921, colbymchenry#2940 ← colbymchenry#1736, colbymchenry#2942 ← colbymchenry#1947, colbymchenry#2950 ← colbymchenry#1952, colbymchenry#2961 ← colbymchenry#1954, colbymchenry#2965 ← colbymchenry#1942, colbymchenry#2972 ← colbymchenry#1933) and the module-path half of colbymchenry#2308 (colbymchenry#2955). Where the integration carried our version, main's wins: the enclosing-scope member pick and its tests, the Go and Java receiver typers, the delegating-call self-loop rule, the duplicated-module copy confidence, the C #if collapse, the module-path resolution of Rust paths, the trail/path hardening in utils.ts. Kept beside main: colbymchenry#1875's Verilog hooks and status fields, colbymchenry#2839's implementations command, colbymchenry#1923, colbymchenry#2922, colbymchenry#2258, colbymchenry#1761, colbymchenry#1583, the bare-call half of colbymchenry#2308 (rust-use-bindings.ts). CHANGELOG is main's plus the open PRs' bullets. EXTRACTION_VERSION 56: the C #if group handling (colbymchenry#2940) and the kernel change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…stay in their file A Kotlin property was indexed without its visibility modifier, so the Kotlin file-local rule (#1745), which declines a private fun in another file, read every property as public: a call like token(...) could link to another file's @volatile private var token, and JavaScript, Go or Python callers to a Kotlin test fixture's private val. A public member of a private class or object was reachable from other files too, though nothing outside its file can name it. Both extractors (wasm and the native kernel) now read a property's modifiers the way they read a function's, and a candidate inside a private Kotlin class or object is declined from another file. That second rule is Kotlin's alone: a Scala private[pkg] class, or one with a private constructor, is its package's, and a C# private nested class serves every file of its partial class. Applied to every language where private is file-local, as the PR had it, it removed 742 edges on http4s (right ones among them, like stream.receiveHeaders() on a private[h2] class H2Stream), 91 on scalachess and 10 on serilog (9 of them right typed edges). Validation: - cross-file-visibility.test.ts: 2 cases, red on main, green here; the kernel parity fixture gains a private val and an internal var. - Kernel parity (kotlin), 0 diffs: okhttp 588/619 files, mihon 891/940, nowinandroid 340/350, SystemUI's Kotlin 188/198 byte-identical, the same files deferred to wasm as with main's kernel; torture 1/1. - A/B against main 01e0ac3 (with the Kotlin receiver typing of #1933): okhttp -274, mihon -177, SystemUI -94, every one a call from another file onto a private Kotlin property or a member of a private class or object (okhttp's private inner AndroidQuery.enqueue and RealWebSocketTest's private TestStreams, mihon's private IntentFilter filter that collections' filter { } reached, SystemUI's private MyExecutor.execute); nothing added. nowinandroid, jextract, click and gin identical; against main 4eb8c2a, http4s, scalachess and serilog were identical too. - Cost (mihon, median of 3 interleaved indexes, on main 4eb8c2a): CPU 25.7 s on main vs 25.5 s, wall 8.2 s on both. Original PR #1761 by @danusha2345. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @danusha2345! This landed in #3010, with you as the commit author. Reading a Kotlin property's visibility, and keeping calls out of private classes, removed a few hundred cross-file links per Android repo that only matched by name. We kept your extractor and kernel changes as they were. We scoped the private-class rule to Kotlin, because in Scala and C# a private class can still be reached from other files of its package or partial class, and we rewrote the CHANGELOG entry. |
…n on it A Kotlin import from outside the project owns its name (#2196), so Modifier.fillMaxSize() after import androidx.compose.ui.Modifier never lands on a same-named project method. That rule returns before any other strategy, so a project extension on the imported type, Compose's fun Modifier.pad() (indexed as Modifier::pad), could not be reached by Modifier.pad() either, nor Color.fromHex() on a fun Color.Companion.fromHex(). Inside the rule, a Kotlin Type.member call now resolves to a project extension Type::member that the calling file can see (same file or package, or imported by name or with .*, as for other top-level Kotlin declarations) and whose own file imports the same type. Anything else stays unlinked, as before. Validation: - kotlin-extension-on-imported-type.test.ts: 2 cases, red on main, green here. - A/B against main 13f983d (with the Kotlin receiver typing of #1933 and #1761's private rule): mihon +26, all Compose Modifier extensions the project declares (secondaryItemAlpha 15, clickableNoIndication 5, selectedBackground 2, two scrollbars, keepInSection), nowinandroid +2 (Modifier.notificationDot, DeviceConfigurationOverride.WindowInsets), all right; okhttp, SystemUI, jextract, click and gin identical. The same sites as against main 4eb8c2a, before #1933. - Cost (mihon, median of 3 interleaved indexes, on main 4eb8c2a): CPU 25.7 s on main vs 25.6 s, wall 8.2 s vs 8.4 s. Original PR #2258 by @danusha2345. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…when two share a name When several classes share a name, resolveMethodOnType picks the one the call file imports by matching the import's path against the candidate's file path (com/example/b/FooConverter.kt). That holds for Java, where a public class names its file, but a Kotlin class often lives in a file named otherwise (FooConverter in Converters.kt), so no candidate matched and the call went to whichever class came first. The imported name is now matched against each candidate's qualified name first: import com.example.b.FooConverter expects the method com.example.b::FooConverter::convert, which the package directive gives every JVM declaration whatever its file is called. The file-path match stays as the fallback. The Java calls this once fixed, a Java file calling a Kotlin class it imports (okhttp's Java tests and mockwebserver3.MockWebServer, SystemUI's BlurUtils), are now resolved on main by the receiver's declared type (#1942), so on today's main the change shows in Kotlin. From #539 we take only this change and its test. Its other two parts, indexing Kotlin class properties and reading Kotlin imports without a trailing semicolon, have since landed on main another way. Validation: - resolution.test.ts: the Kotlin same-name case (#314's shape in Converters.kt files) is red on main, green here. - A/B against main 40f5851 (with the Java receiver typing of #1942 and the Kotlin changes of #1933, #1761 and #2258): no edge changes on okhttp, SystemUI, nowinandroid, mihon, jextract, spring-modulith, Minestom, spring-ai, kestra-java, playframework, click or gin; none of them has the test's shape on a resolved call. Against main 4eb8c2a, before #1942, it moved the 8 Java calls above onto the Kotlin class their file imports; main now reaches them at 0.9. - Cost (mihon, median of 3 interleaved indexes, on main 4eb8c2a): CPU 25.7 s on main vs 25.2 s, wall 8.2 s vs 8.3 s. Original PR #539 by @arttttt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up to #1745 (the Kotlin / Go / Rust file-local rule, #1731). Two commits, off
mainatcd4e65b.What
A Kotlin property records its visibility modifier.
private val/private var/internalat class or object scope were indexed with novisibility, so the Kotlin rule inisVisibleAcrossFiles— which declines aprivate funin another file — read every property as public. Both the WebAssembly extractor and the native kernel now read themodifierschild the way they already do for functions; the parity fixture gains aprivate valand aninternal var.A member of a
privateclass or object is file-local too.private class Clock(var value: Long) { fun now() = value }in a test: the method is public, the class is not, so nothing outside the file can namenow. For the languages whereprivateis file-local (Kotlin, Java, C#, Swift, Scala, Dart, PHP) a candidate whose enclosing class/object/interface/enum in its file isprivateis declined — by line range among the file's nodes, memoised per node.Applied where #1745 applies, after the whole pipeline settles, so a rejection leaves the reference unresolved.
Measured
A Kotlin + JS + Go Electron/Android app (114 Kotlin files),
mainatcd4e65bvs this branch, wasm arm, edge rows keyed withresolvedBy: LOST 57 / GAINED 0.token(...)onto another class's@Volatile private var token; JSnow()/bytes()/gate()callers (renderer, a Python tool, the Go signaling server) onto Kotlin test fixtures'private vals;changed,handler,resources,onStatus,listener,moving.now()calls in the gimbal control onto the test'sprivate class Clock, and 30send/cancel/close/requestcalls fromTelemetryUplink.kt/WebRtcTransport.kt(instance-method resolution) ontoTelemetryUplinkTest.kt'sprivate class FakeWebSocket/ServerSocketListener.A second Kotlin app (FreeFCC, 1,726 nodes): 0 / 0.
pulpRust, Python and C corpora: untouched (the rule is gated to theprivate-is-file-local languages).Tests
cross-file-visibility+2 (aprivate varand aninternal valcarry their modifier and the private one is declined; a public fun of a private class is declined),kernel-kotlin-parity/kernel-grammar-parityon the rebuilt kernel,resolution198/198,frameworks-integration;tscclean. Full suite on Linux: the viewer-lesscodegraph uifiles, plus the three store-action tests that fail onmainsince #1759 and that #1760 fixes.🤖 Generated with Claude Code