Skip to content

Commit bb036da

Browse files
authored
Handle null class body in KotlinPrinter (#6805)
KotlinPrinter.visitClassDeclaration0 crashed with a NullPointerException when printing a class declaration with a null body. This happens when BlockStatementTemplateGenerator builds context for a context-sensitive template: it creates a stripped-down class via withBody(null) and prints it to generate the template context. The Java printer handles this fine (visit() is null-safe), but the Kotlin printer accessed getBody() without a null check.
1 parent cc39339 commit bb036da

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/internal/KotlinPrinter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ private J.ClassDeclaration visitClassDeclaration0(J.ClassDeclaration classDecl,
728728
visitContainer("where", typeConstraints.getPadding().getConstraints(), JContainer.Location.TYPE_PARAMETERS, ",", "", p);
729729
}
730730

731-
if (!classDecl.getBody().getMarkers().findFirst(OmitBraces.class).isPresent()) {
731+
if (classDecl.getBody() != null && !classDecl.getBody().getMarkers().findFirst(OmitBraces.class).isPresent()) {
732732
visit(classDecl.getBody(), p);
733733
}
734734
afterSyntax(classDecl, p);

rewrite-kotlin/src/test/java/org/openrewrite/kotlin/KotlinTemplateTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
import org.openrewrite.java.tree.J;
2323
import org.openrewrite.test.RewriteTest;
2424

25+
import org.openrewrite.java.JavaTemplate;
26+
import org.openrewrite.java.tree.Statement;
27+
import org.openrewrite.test.TypeValidation;
28+
2529
import java.net.URISyntaxException;
2630
import java.nio.file.Path;
2731
import java.util.List;
@@ -61,6 +65,45 @@ fun foo() {
6165
));
6266
}
6367

68+
@Test
69+
void addStatementToMethodInClass() {
70+
rewriteRun(
71+
spec -> spec.typeValidationOptions(TypeValidation.none())
72+
.recipe(toRecipe(() -> new KotlinVisitor<>() {
73+
@Override
74+
public J visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
75+
J.MethodDeclaration m = (J.MethodDeclaration) super.visitMethodDeclaration(method, ctx);
76+
if (m.getSimpleName().equals("configure")) {
77+
List<Statement> statements = m.getBody().getStatements();
78+
if (statements.stream().noneMatch(s -> s.toString().contains("println"))) {
79+
return JavaTemplate.builder("println(\"added\")")
80+
.contextSensitive()
81+
.build()
82+
.apply(getCursor(), statements.get(statements.size() - 1).getCoordinates().after());
83+
}
84+
}
85+
return m;
86+
}
87+
})),
88+
kotlin(
89+
"""
90+
class MyConfig {
91+
fun configure(value: Int) {
92+
val x = value + 1
93+
}
94+
}
95+
""",
96+
"""
97+
class MyConfig {
98+
fun configure(value: Int) {
99+
val x = value + 1
100+
println("added")
101+
}
102+
}
103+
"""
104+
));
105+
}
106+
64107
@Test
65108
void parserClasspath() {
66109
rewriteRun(

0 commit comments

Comments
 (0)