rewrite-kotlin
rewrite-kotlin copied to clipboard
Kotlin external classpath artifact fail to parse
I am using
- OpenRewrite v8.30.0
- Gradle plugin v8.30.0
- rewrite-kotlin v8.30.0
How are you running OpenRewrite?
Using openrewrite with kotlin/gradle plugin, single module
Following on from slack conversation at https://rewriteoss.slack.com/archives/C01A843MWG5/p1721744738864449?thread_ts=1721135504.974819&cid=C01A843MWG5
What is the smallest, simplest way to reproduce the problem?
Based on the rewrite starter recipe, I am trying to write a simple replacement that references the jar io.kotest:kotest-property-jvm, however it fails on parsing
package com.yourorg;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.*;
import org.openrewrite.java.search.UsesMethod;
import org.openrewrite.java.tree.J;
import org.openrewrite.kotlin.KotlinIsoVisitor;
import org.openrewrite.kotlin.KotlinTemplate;
@Value
@EqualsAndHashCode(callSuper = false)
public class MigrateUUIDArbUsage extends Recipe {
@Override
public String getDisplayName() {
// language=markdown
return "Convert Arb uuid usages`";
}
@Override
public String getDescription() {
return "Convert arb uuid usages.";
}
private static MethodMatcher MATCHER = new MethodMatcher("io.kotest.property.arbitrary.ArbsKt next(..)");
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(new UsesMethod<>("io.kotest.property.arbitrary.ArbsKt next(..)", null),
new KotlinIsoVisitor<ExecutionContext>() {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
// System.out.println(TreeVisitingPrinter.printTree(getCursor()));
J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
if (!MATCHER.matches(m)) {
return m;
}
if (m.getSelect() instanceof J.Identifier && ((J.Identifier) m.getSelect()).getSimpleName().equals("uuidArb")) {
maybeAddImport("io.kotest.property.Arb", false);
maybeAddImport("io.kotest.property.arbitrary.UUIDVersion", false);
maybeAddImport("io.kotest.property.arbitrary.next", false);
m = KotlinTemplate.builder("Arb.uuid(UUIDVersion.V4, false).next()")
.doBeforeParseTemplate(t -> System.out.println(t))
.imports(
"io.kotest.property.arbitrary.next",
"io.kotest.property.arbitrary.UUIDVersion",
"io.kotest.property.Arb")
.javaParser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true)
.classpath(
"kotest-property-jvm"
)
)
.build()
.apply(getCursor(), m.getCoordinates().replace());
}
return m;
}
});
}
}
package com.yourorg
import org.junit.jupiter.api.Test
import org.openrewrite.DocumentExample
import org.openrewrite.kotlin.Assertions
import org.openrewrite.kotlin.KotlinParser
import org.openrewrite.test.RecipeSpec
import org.openrewrite.test.RewriteTest
class ArbTransformTest: RewriteTest {
override fun defaults(spec: RecipeSpec) {
spec.recipe(MigrateUUIDArbUsage())
.parser(
KotlinParser.builder() //.parser(
//JavaParser.fromJavaVersion()
.classpath(
"kotest-property-jvm",
"kotest-property",
"arbs",
"junit-jupiter-api")
)
}
@DocumentExample
@Test
fun kotlinFoo() {
rewriteRun(
Assertions.kotlin(
"""
import io.kotest.property.arbitrary.next
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.smw.arbs.uuidArb
class TestTest {
@Test
fun arbTest() {
val uuid = uuidArb.next()
Assertions.assertEquals(uuid, uuid)
}
}
""".trimIndent(), """
import io.kotest.property.Arb
import io.kotest.property.arbitrary.UUIDVersion
import io.kotest.property.arbitrary.next
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
class TestTest {
@Test
fun arbTest() {
val uuid = Arb.uuid(UUIDVersion.V4, false).next()
Assertions.assertEquals(uuid, uuid)
}
}
""".trimIndent()
)
)
}
}
Error when running the test is
import io.kotest.property.arbitrary.next
import io.kotest.property.arbitrary.UUIDVersion
import io.kotest.property.Arb
import org.openrewrite.java.internal.template.__M__;
import org.openrewrite.java.internal.template.__P__;
class Template {
var o : Object =
/*__TEMPLATE__*/Arb.uuid(UUIDVersion.V4, false).next()/*__TEMPLATE_STOP__*/
;
}
java.lang.IllegalStateException: LST contains missing or invalid type information
Identifier->MethodInvocation->MethodInvocation->NamedVariable->VariableDeclarations->Block->MethodDeclaration->Block->ClassDeclaration->CompilationUnit
/*~~(Identifier type is missing or malformed)~~>*/Arb
at org.openrewrite.kotlin.Assertions.assertValidTypes(Assertions.java:235)
at org.openrewrite.kotlin.Assertions.validateTypes(Assertions.java:56)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:508)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:132)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:127)
at com.yourorg.ArbTransformTest.kotlinFoo(ArbTransformTest.kt:27)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
The artifact is included in the project via
testRuntimeOnly("io.kotest:kotest-property:5.9.1")
If I add spec.typeValidationOptions(TypeValidation.none()) to the test, it passes, ideally would like to avoid this.
Are you interested in contributing a fix to OpenRewrite?
Happy to help where I can