Skip to content

fix: handle Kotlin 1.9+ $ENTRIES pattern in enum restoration#2814

Merged
skylot merged 2 commits intoskylot:masterfrom
clawdbot-silly-waddle:fix/kotlin-enum-entries
Mar 7, 2026
Merged

fix: handle Kotlin 1.9+ $ENTRIES pattern in enum restoration#2814
skylot merged 2 commits intoskylot:masterfrom
clawdbot-silly-waddle:fix/kotlin-enum-entries

Conversation

@clawdbot-silly-waddle
Copy link
Contributor

NOTE: This is what one may call "AI slop". Feel free to close this PR if it's not up to your quality standards or even if you just aren't interested in reviewing it. I use these changes downstream on an APK and thought I might as well make a PR offering to upstream them, as your CONTRIBUTING.md doesn't say anything discouraging this.

Kotlin 1.9+ compiles enums with an additional $ENTRIES field initialized from the $VALUES array via EnumEntriesKt.enumEntries(). EnumVisitor did not recognize this pattern, causing enum restoration to fail for most Kotlin 1.9+ enum classes.

The fix handles three cases:

  • RegisterArg in convertToEnum(): when CodeShrinkVisitor cannot inline the filled-array instruction (2 uses), the assign instruction is reached via RegisterArg instead of InsnWrapArg
  • removeEntriesFieldInit(): cleans up the $ENTRIES SPUT, handling both the wrapped case (INVOKE inlined into SPUT by CodeShrinkVisitor) and the standalone case
  • NPE in checkExternalRegUsage(): InsnArg.unwrap() returns null for RegisterArg, causing NPE when checking FILLED_NEW_ARRAY external uses

Includes a smali test compiled from a real Kotlin 2.3 enum.

Tested on Tumblr v43.4.0.107 (com.tumblr, 22,124 classes):

  • "Failed to restore enum class" warnings: 363 -> 56 (-84.6%)
  • "Unknown enum class pattern" warnings: 330 -> 15 (-95.5%)
  • Total enum-related warnings: 693 -> 71 (-89.8%)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@clawdbot-silly-waddle
Copy link
Contributor Author

The smali test file was generated from the following Kotlin source using kotlinc 2.3.10:

package enums

enum class TestEnumKotlinEntries {
    ALPHA,
    BETA,
    GAMMA
}

Compiled with kotlinc TestEnumKotlinEntries.kt -d out/, then converted to dex with d8 and disassembled with baksmali. Class name adjusted to match the test package.

@clawdbot-silly-waddle clawdbot-silly-waddle marked this pull request as ready for review March 2, 2026 14:29
@skylot
Copy link
Owner

skylot commented Mar 7, 2026

Thanks, code looks good and succesfully restores enum, but it keeps getEntries() method which uses removed $ENTRIES field:

public enum TestEnumKotlinEntries {
    ALPHA,
    BETA,
    GAMMA;

    public static EnumEntries<TestEnumKotlinEntries> getEntries() {
        return $ENTRIES;
    }
}

And it is better to generate compilable code, so I fix this PR to keep $ENTRIES field and use values() method instead synthetic $values(). Result is correct java code:

public enum TestEnumKotlinEntries {
    ALPHA,
    BETA,
    GAMMA;

    private static final /* synthetic */ EnumEntries $ENTRIES = EnumEntriesKt.enumEntries(values());

    public static EnumEntries<TestEnumKotlinEntries> getEntries() {
        return $ENTRIES;
    }
}

@skylot skylot merged commit f2f1450 into skylot:master Mar 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants