Fix TypeTable round-trip for Kotlin top-level functions#7422
Draft
steve-aom-elliott wants to merge 1 commit intomainfrom
Draft
Fix TypeTable round-trip for Kotlin top-level functions#7422steve-aom-elliott wants to merge 1 commit intomainfrom
steve-aom-elliott wants to merge 1 commit intomainfrom
Conversation
Three bugs in TypeTable caused Kotlin top-level extension functions (e.g. `jacksonObjectMapper()` from `jackson-module-kotlin`) to lose method type attribution when their classpath was sourced from a synthesized TypeTable rather than the original jar: 1. Writer filtered out `ACC_SYNTHETIC` methods. Kotlin extension functions compile to `public static final synthetic` on a `*Kt` facade class, so they were being dropped. Filter on `ACC_PRIVATE` only. 2. Writer did not capture `InnerClasses` attributes. Kotlin FIR silently fails to resolve methods on classes whose `@kotlin.Metadata.d1` references inner classes (lambdas, etc.) that are not declared in the class's `InnerClasses` attribute. Serialize `visitInnerClass` entries into a new `innerClasses` TSV column and replay them on the reader. 3. Writer did not preserve `META-INF/*.kotlin_module` resources, which the Kotlin compiler uses to map package names to facade classes. Store them as resource rows (`classAccess=-2` sentinel, base64 content) and expose them through a new `ResourceConsumer` callback on the reader.
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.
Summary
Three interlocking bugs in
TypeTablecaused Kotlin top-level functions (top-level regular functions and extension functions) to lose method type attribution whenKotlinParserreceived a classpath sourced from a TypeTable-synthesized directory (asmoddoes for downloaded LSTs) rather than the original jar. The symptom:J.MethodInvocation.getMethodType()returnsnullfor calls likejacksonObjectMapper()(fromjackson-module-kotlin), andMethodMatcher/UsesMethodtherefore cannot match them.The three fixes
ACC_SYNTHETICmethods were filtered out. Kotlin extension functions compile topublic static final syntheticon a*Ktfacade class, so they were being dropped at write time. Now filter onACC_PRIVATEonly (and skip<clinit>), matching what's needed for type attribution.InnerClassesattribute was not captured. Kotlin FIR silently fails to resolve methods on a class whose@kotlin.Metadata.d1protobuf references inner classes (lambdas, companion objects, etc.) unless those inner classes are declared in the class'sInnerClassesattribute. The Writer'sClassVisitordidn't overridevisitInnerClass, so every round-tripped class came out with an emptyInnerClassesattribute. Now serialize each entry asname,outerName,innerName,accessinto a newinnerClassesTSV column, and replay them on the Reader side before any other class events so ASM writes them back out.META-INF/*.kotlin_moduleresources were dropped. The Kotlin compiler uses these files to map package names to their facade classes (com.fasterxml.jackson.module.kotlin→ExtensionsKt). Without it, the resolver can't find the top-level function's owner. Store.kotlin_modulefiles as resource rows using aclassAccess = -2sentinel with base64-encoded content in theconstantValuecolumn, plumbed through a newResourceConsumercallback onReader.read()so callers can persist them alongside the synthesized.classfiles.Tests
MethodMatcherTest#libraryTopLevelFunctionPopulatesMethodType— asserts method type is non-null forjacksonObjectMapper().MethodMatcherTest#usesMethodMatchesLibraryTopLevelFunction— end-to-endUsesMethodmatch on the Kotlin top-level extension function.TypeTableTypeAnnotationsTest#columnOrderCorrect— updated for the added column.Both Kotlin tests use
KotlinParser.builder().classpath(\"jackson-module-kotlin\"), which resolves via the shipped TypeTable — exactly the code path that was broken.Test plan
./gradlew :rewrite-java:test --tests "org.openrewrite.java.internal.parser.*"./gradlew :rewrite-kotlin:test --tests "org.openrewrite.kotlin.MethodMatcherTest"