Skip to content

KotlinTypeMapping: remapKotlinBuiltin not applied to method parameter types #7427

@timtebeek

Description

@timtebeek

Summary

MethodMatcher patterns that reference Java built-in types (e.g. String, Throwable) do not match equivalent Kotlin constructor/method invocations, because KotlinTypeMapping.methodInvocationType records parameter types as kotlin.String / kotlin.Throwable instead of the remapped java.lang.String / java.lang.Throwable.

Reproduction

Given Kotlin source:

import com.fasterxml.jackson.core.JsonGenerationException
import com.fasterxml.jackson.core.JsonGenerator

class Test {
    fun example(gen: JsonGenerator, cause: Throwable) {
        throw JsonGenerationException(\"message\", cause, gen)
    }
}
[kotlin.String, kotlin.Throwable, com.fasterxml.jackson.core.JsonGenerator]

So a MethodMatcher like:

new MethodMatcher(
    \"com.fasterxml.jackson.core.JsonGenerationException <constructor>(String, Throwable, com.fasterxml.jackson.core.JsonGenerator)\"
).matches(newClass) // => false

...returns false on Kotlin, even though the equivalent Java source matches fine. This breaks any recipe that relies on MethodMatcher / ReorderMethodArguments / etc. for Kotlin sources when the signature references Java built-ins.

  • Downstream impact example: https://github.com/moderneinc/customer-requests/issues/2235 — the Jackson 2→3 migration's argument-reordering for JsonGenerationExceptionStreamWriteException does not fire on Kotlin code and we had to add a downstream workaround in rewrite-jackson (ReorderJsonGenerationExceptionArguments) that accepts both kotlin.String and java.lang.String (and the Throwable equivalents).

Root cause

In rewrite-kotlin/src/main/java/org/openrewrite/kotlin/KotlinTypeMapping.kt, the methodInvocationType function (around line 866–1010) builds parameter types like this (around line 992):

for (p in function.valueParameters) {
    val t = type(p.returnTypeRef)
    paramTypes.add(t)  // <-- no remapKotlinBuiltin applied
}

...but not to method parameter types in methodInvocationType, nor (likely) to the method return type or to field types. A comprehensive pass is probably needed.

Proposed fix

Apply remapKotlinBuiltin to each parameter type before adding it to paramTypes in methodInvocationType. Audit the rest of that function (return type, thrown exceptions, receiver type) for the same gap. Also audit variableType and related functions for the same class of bug on field/property types.

How to verify the fix

Add a test in rewrite-kotlin that parses a Kotlin constructor call taking a String / Throwable and asserts the resulting JavaType.Method.parameterTypes contain java.lang.String / java.lang.Throwable rather than kotlin.String / kotlin.Throwable.

End-to-end, once this lands and propagates:

  1. In rewrite-jackson, revert the workaround recipe ReorderJsonGenerationExceptionArguments back to the three standard ReorderMethodArguments entries in src/main/resources/META-INF/rewrite/jackson-2-3.yml.
  2. The two Kotlin tests (reorderThreeArgsKotlin, reorderTwoArgsKotlin) in ReorderStreamWriteExceptionArgumentsTest should still pass.

Context for whoever picks this up

  • Upstream PR aligning Kotlin & Java type model: Align Kotlin type model with Java parser output #7364
  • The remap helper already exists: KotlinTypeUtils.remapKotlinBuiltin — just needs to be invoked in more places.
  • Downstream workaround that demonstrates the gap (and should be removed once this lands):
    • rewrite-jackson/src/main/java/org/openrewrite/java/jackson/ReorderJsonGenerationExceptionArguments.java
    • Note the isString / isThrowable helpers there accept both kotlin.* and java.lang.* FQNs precisely to paper over this bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions