Uh oh!
There was an error while loading. Please reload this page.
ADFA-3604: Re-enable R8 shrinking with keep rules for kotlin-analysis-api - #1596
Conversation
…-api Removes the blanket -dontshrink added in ADFA-996, which neutered R8 shrinking entirely after it broke release-build project init. Adds targeted keep rules for every class the bundled kotlin-analysis-api jar loads reflectively via IntelliJ plugin XML descriptors and ServiceLoader entries, since those are the paths R8 can't trace from bytecode reachability alone. Cuts release dex from 119.4 MB / 104,033 classes to 28.8 MB / 24,853 classes in a trial build. Not yet verified on a physical device. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
📝 WalkthroughWalkthroughR8 shrinking is re-enabled for the application, while consumer rules preserve Kotlin analysis and IntelliJ classes instantiated through plugin descriptors and ChangesR8 preservation configuration
Estimated code review effort: 2 (Simple) | ~15 minutes Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
subprojects/kotlin-analysis-api/consumer-rules.pro (1)
9-360: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument the maintenance/refresh process for this keep-rule list.
This file replaces a blanket
-dontshrinkwith ~350 hand-enumerated FQCN keep rules. That's the right tradeoff for size, but it's brittle against future upgrades of the bundled Kotlin Analysis API / IntelliJ platform jars: if a class referenced here is renamed or removed upstream, R8 will typically just drop the now-unresolvable keep rule (or warn) rather than fail the build, so breakage would only surface at runtime viaServiceConfigurationError/ClassNotFoundException— exactly the kind of regression the PR flags as still needing physical-device validation.Consider adding a short note (here or in the ticket) on how this list was derived (e.g., scanning
META-INF/services/*and plugin XML descriptors) and how to regenerate/diff it on future dependency bumps, so staleness is caught deliberately rather than discovered in the field.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@subprojects/kotlin-analysis-api/consumer-rules.pro` around lines 9 - 360, Document how the hand-maintained keep-rule list was generated, including scanning META-INF/services entries and plugin XML descriptors, and describe the steps to regenerate and diff it after Kotlin Analysis API or IntelliJ platform dependency upgrades. Add this maintenance note near the keep rules or in the associated tracking documentation, referencing the enumerated FQCN rules as the maintained artifact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@subprojects/kotlin-analysis-api/consumer-rules.pro`:
- Around line 9-360: Document how the hand-maintained keep-rule list was
generated, including scanning META-INF/services entries and plugin XML
descriptors, and describe the steps to regenerate and diff it after Kotlin
Analysis API or IntelliJ platform dependency upgrades. Add this maintenance note
near the keep rules or in the associated tracking documentation, referencing the
enumerated FQCN rules as the maintained artifact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3b2ba7a8-0354-4e65-9b01-6a35a8ec8d9c
📒 Files selected for processing (2)
app/proguard-rules.prosubprojects/kotlin-analysis-api/consumer-rules.pro
💤 Files with no reviewable changes (1)
- app/proguard-rules.pro
Review feedback on #1596: the 352-entry keep-rule list had no documented provenance. Adds the exact extraction/parsing steps used to generate it and how to regenerate and diff it after a Kotlin Analysis API or IntelliJ platform dependency bump. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
davidschachterADFA
commented
Jul 29, 2026
On-device verification (debug build,
This was a debug build rather than release, so it doesn't fully replace the release-build device test already noted in the PR description, but it's a second independent confirmation that the kotlin-analysis-api keep rules hold up for project init, diagnostics, and completion. Go-to-definition check still to follow. |
davidschachterADFA
commented
Jul 29, 2026
Follow-up on the go-to-definition item: reopened the same test project (debug build) and long-pressed a resolved symbol ( Checked why: So this is a pre-existing gap in the product (Kotlin go-to-definition was never hooked up to the editor UI), not something this PR's R8/keep-rule changes affect either way — there's no existing behavior here for the keep rules to have broken. Updated the test-plan checkbox to reflect that autocomplete and diagnostics were verified for Kotlin, and noted go-to-definition separately rather than leave it looking untested or falsely checked. |
Filed ADFA-4923 to track the missing Kotlin go-to-definition action. |
Uh oh!
There was an error while loading. Please reload this page.
* ADFA-5156: Roll back R8 shrinking to unbreak plugins Restores the blanket -dontshrink that ADFA-3604 (#1596) removed on 2026-07-29. This is a temporary rollback to restore plugin functionality; a targeted fix follows. Plugins are loaded parent-first through a stock DexClassLoader (PluginLoader.kt:92-116, parent passed at PluginManager.kt:603), so every kotlin.** class a plugin references resolves from the IDE's dex, not from the ~1058 stdlib classes the plugin bundles. R8 cannot see plugin call sites, so it strips every stdlib member the IDE itself does not call. The net effect is that a plugin can only call the subset of the Kotlin standard library that the IDE also calls; anything else throws NoSuchMethodError at runtime. Sketch to UI fails on every image load with "No static method maxOrNull([F)Ljava/lang/Float; in class ArraysKt". -dontobfuscate and -dontoptimize were already set, so restoring -dontshrink reduces R8 to a pass-through and returns the release build to the configuration shipped before ADFA-3604. isMinifyEnabled and isShrinkResources are deliberately left alone, keeping resource shrinking and the build wiring unchanged. Verified by dex-scanning both APKs (baseline pulled from a release install on Samsung RFCT704HEAL): kotlin/kotlinx method declarations 30,669 -> 45,371 ArraysKt/CollectionsKt/MapsKt/ FilesKt/SequencesKt facades absent -> present 10 sketch-to-ui stdlib call sites all stripped -> all present CompletableJob$DefaultImpls.plus stripped -> present Sketch to UI now loads an image and completes detection on-device with no NoSuchMethodError in logcat. APK size: 659,307,160 -> 706,829,817 bytes (+47.5 MB, +7.2%). Note: R8 was buying less than #1596 advertised. That PR measured dex at 28.8 MB / 24,853 classes, but the shipped APK is 85 MB / 78,757 classes -- the URGENT follow-ups (#1609, #1610) added -dontoptimize plus a set of keep rules that clawed most of it back. * ADFA-5156: Add R8 plugin-impact analysis tooling The ADFA-5156 failure mode is invisible at build time -- assemblePlugin is green, the manifest is fine, the .cgp is correct, and only on-device execution of a specific code path reveals that R8 stripped a stdlib member the plugin needs. These scripts make it measurable from build artifacts instead. scripts/r8-plugin-impact/ README.md what the bug is, how to run, how to read output, the known false positives, and the ADFA-5156 baseline numbers to measure future builds against dex-dump.sh extract + dexdump an APK or .cgp analyze-plugin-impact.py simulate parent-first resolution of every kotlin.*/kotlinx.* call site in each plugin's own code against two host dexes and diff the verdicts Three subcommands: impact (the before/after table), explain-method (trace one resolution chain, showing where it leaves the APK), explain-absent (inspect fall-throughs for the split-brain shape that caused the original bug). Documents three traps that produce wrong conclusions if analysis is done ad hoc, all of which bit during this investigation: - Methods inherited from the Android boot classpath read as missing, because java.util.* is not in the APK. Eight such false positives are enumerated. - Kotlin multifile facades (ArraysKt, StringsKt) declare nothing themselves; they extend a part class whose underscore count varies (StringsKt__StringsKt vs ArraysKt___ArraysKt). Checking a facade directly always fails. - D8 build-time synthetics ($$ExternalSyntheticBackport0 and friends) never exist in the host and always show as absent. Stdlib-only Python, no third-party dependencies. Run with uv run --no-project. * ADFA-5156: Apply spotless formatting to plugin-impact scripts * ADFA-5156: Point plugin-impact baseline at the deployed plugin set The first baseline measured a local folder of .cgp files that turned out to be a pre-rename snapshot -- 5 stale filenames and 3 plugins missing. Re-runs against the artifact from the last update-libs.yml deploy (26 plugins, 4,261 call sites) and documents how to obtain that artifact, so the next person does not measure the wrong set. Conclusion is unchanged: zero regressions, 67 real failures to 0.
Summary
classes*.dexexceeds 108 MB. The single biggest contributor turned out to be the bundled Kotlin Analysis API jar (used for in-editor Kotlin code intelligence): 43,951 classes / ~18.4 MB, ~42% of all dex bytecode.:apprelease (isMinifyEnabled = isAppModule), butapp/proguard-rules.prohad a blanket-dontshrinkadded in ADFA-996 after shrinking broke release-build project init — neutering shrinking entirely ever since.-dontshrinkand adds targeted-keeprules tosubprojects/kotlin-analysis-api/consumer-rules.profor every class the jar loads reflectively via IntelliJ plugin XML descriptors (Core.xml,CoreImpl.xml,JavaPsiPlugin.xml,analysis-api/*.xml) andMETA-INF/servicesServiceLoaderentries — the paths R8 can't trace from bytecode reachability alone.Trial results
Local release build (
:app:assembleV8Release), before vs after:org.jetbrains.kotlin.*(analysis API)Spot-checked R8's
usage.txtand the output dex directly:MainActivity,OnboardingActivity,CrashHandlerActivity, and the Kotlin LSP classes are all still present. Thecom.itsaky.androidide.*entries R8 removed are unused syntheticR$/BuildConfigclasses and dead private members, not core app code.Risk
ADFA-996's prior shrink attempt failed at runtime (release-build project init), not at build time — static analysis and a build-succeeds check don't rule that out here. No ARM device was available to install and exercise the shrunk APK before opening this PR, particularly Kotlin autocomplete/diagnostics (the exact feature the new keep rules protect).
Test plan
🤖 Generated with Claude Code