diff --git a/src/main/java/org/openrewrite/kotlin/KotlinVisitor.java b/src/main/java/org/openrewrite/kotlin/KotlinVisitor.java
index 6468de0ac..6b581f810 100644
--- a/src/main/java/org/openrewrite/kotlin/KotlinVisitor.java
+++ b/src/main/java/org/openrewrite/kotlin/KotlinVisitor.java
@@ -276,8 +276,7 @@ public J visitProperty(K.Property property, P p) {
pr = pr.withVariableDeclarations(visitAndCast(pr.getVariableDeclarations(), p));
pr = pr.getPadding().withReceiver(visitRightPadded(pr.getPadding().getReceiver(), p));
- pr = pr.withGetter(visitAndCast(pr.getGetter(), p));
- pr = pr.withSetter(visitAndCast(pr.getSetter(), p));
+ pr = pr.withAccessors(visitContainer(pr.getAccessors(), p));
return pr;
}
diff --git a/src/main/java/org/openrewrite/kotlin/internal/KotlinPrinter.java b/src/main/java/org/openrewrite/kotlin/internal/KotlinPrinter.java
index 59c8fa4f9..8d89ea6e7 100755
--- a/src/main/java/org/openrewrite/kotlin/internal/KotlinPrinter.java
+++ b/src/main/java/org/openrewrite/kotlin/internal/KotlinPrinter.java
@@ -395,14 +395,7 @@ public J visitProperty(K.Property property, PrintOutputCapture
p) {
delegate.visitContainer("where", property.getTypeConstraints().getPadding().getConstraints(), JContainer.Location.TYPE_PARAMETERS, ",", "", p);
}
- if (property.isSetterFirst()) {
- visit(property.getSetter(), p);
- visit(property.getGetter(), p);
- } else {
- visit(property.getGetter(), p);
- visit(property.getSetter(), p);
- }
-
+ visitContainer(property.getAccessors(), p);
afterSyntax(property, p);
return property;
}
diff --git a/src/main/java/org/openrewrite/kotlin/internal/KotlinTreeParserVisitor.java b/src/main/java/org/openrewrite/kotlin/internal/KotlinTreeParserVisitor.java
index a535a1478..2cf3fef07 100644
--- a/src/main/java/org/openrewrite/kotlin/internal/KotlinTreeParserVisitor.java
+++ b/src/main/java/org/openrewrite/kotlin/internal/KotlinTreeParserVisitor.java
@@ -2811,13 +2811,10 @@ public J visitProperty(KtProperty property, ExecutionContext data) {
List modifiers = mapModifiers(property.getModifierList(), leadingAnnotations, lastAnnotations, data);
TypeTree typeExpression = null;
List> variables = new ArrayList<>();
- J.MethodDeclaration getter = null;
- J.MethodDeclaration setter = null;
JRightPadded receiver = null;
JContainer typeParameters = property.getTypeParameterList() != null ?
JContainer.build(prefix(property.getTypeParameterList()), mapTypeParameters(property.getTypeParameterList(), data), Markers.EMPTY) : null;
K.TypeConstraints typeConstraints = null;
- boolean isSetterFirst = false;
Set prefixConsumedSet = preConsumedInfix(property);
modifiers.add(new J.Modifier(
@@ -2867,18 +2864,6 @@ public J visitProperty(KtProperty property, ExecutionContext data) {
typeExpression = (TypeTree) requireNonNull(property.getTypeReference()).accept(this, data);
}
- if (property.getGetter() != null) {
- getter = (J.MethodDeclaration) property.getGetter().accept(this, data);
- }
-
- if (property.getSetter() != null) {
- setter = (J.MethodDeclaration) property.getSetter().accept(this, data);
- }
-
- if (getter != null && setter != null) {
- isSetterFirst = property.getSetter().getTextRange().getStartOffset() < property.getGetter().getTextRange().getStartOffset();
- }
-
J.VariableDeclarations variableDeclarations = new J.VariableDeclarations(
Tree.randomId(),
endFixPrefixAndInfix(property), // overlaps with right-padding of previous statement
@@ -2898,7 +2883,16 @@ public J visitProperty(KtProperty property, ExecutionContext data) {
.withPrefix(prefix(whereKeyword));
}
- if (getter != null || setter != null || receiver != null || typeConstraints != null) {
+ List ktPropertyAccessors = property.getAccessors();
+ if (!ktPropertyAccessors.isEmpty() || receiver != null || typeConstraints != null) {
+ List> accessors = new ArrayList<>(ktPropertyAccessors.size());
+ PsiElement lastChild = findLastChild(property, c -> !isSpace(c.getNode()) && !isSemicolon(c));
+
+ for (KtPropertyAccessor ktPropertyAccessor : ktPropertyAccessors) {
+ J.MethodDeclaration accessor = (J.MethodDeclaration) ktPropertyAccessor.accept(this, data);
+ accessors.add((lastChild == ktPropertyAccessor) ? padRight(accessor, Space.EMPTY) : maybeTrailingSemicolon(accessor, ktPropertyAccessor));
+ }
+
return new K.Property(
randomId(),
deepPrefix(property),
@@ -2906,9 +2900,7 @@ public J visitProperty(KtProperty property, ExecutionContext data) {
typeParameters,
variableDeclarations.withPrefix(Space.EMPTY),
typeConstraints,
- getter,
- setter,
- isSetterFirst,
+ JContainer.build(accessors),
receiver
);
} else {
@@ -3671,14 +3663,12 @@ private J.Block convertToBlock(KtExpression ktExpression, ExecutionContext data)
private JRightPadded maybeTrailingSemicolon(J2 j, KtElement element) {
PsiElement maybeSemicolon = findLastNotSpaceChild(element);
- boolean hasSemicolon = maybeSemicolon instanceof LeafPsiElement && ((LeafPsiElement) maybeSemicolon).getElementType() == KtTokens.SEMICOLON;
-
- if (hasSemicolon) {
+ if (isSemicolon(maybeSemicolon)) {
return new JRightPadded<>(j, prefix(maybeSemicolon), Markers.EMPTY.add(new Semicolon(randomId())));
}
maybeSemicolon = PsiTreeUtil.skipWhitespacesAndCommentsForward(element);
- if (maybeSemicolon instanceof LeafPsiElement && ((LeafPsiElement) maybeSemicolon).getElementType() == KtTokens.SEMICOLON) {
+ if (isSemicolon(maybeSemicolon)) {
return new JRightPadded<>(j, deepPrefix(maybeSemicolon), Markers.EMPTY.add(new Semicolon(randomId())));
}
diff --git a/src/main/java/org/openrewrite/kotlin/tree/K.java b/src/main/java/org/openrewrite/kotlin/tree/K.java
index bc461145c..a1279543f 100644
--- a/src/main/java/org/openrewrite/kotlin/tree/K.java
+++ b/src/main/java/org/openrewrite/kotlin/tree/K.java
@@ -41,6 +41,7 @@
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -1503,16 +1504,57 @@ public List getTypeParameters() {
@Nullable
TypeConstraints typeConstraints;
- @Nullable
- J.MethodDeclaration getter;
+ // A replacement of `getter`,`setter` and `isSetterFirst`
+ JContainer accessors;
@Nullable
- J.MethodDeclaration setter;
+ JRightPadded receiver;
- boolean isSetterFirst;
+ // For backward compatibility, handle removed fields `getter`, 'setter' and `isSetterFirst` which has been relocated to `accessors`
+ // Todo, Remove when all kotlin LSTs have been rebuilt.
+ @Deprecated
+ @JsonCreator
+ public Property(UUID id,
+ Space prefix,
+ Markers markers,
+ JContainer typeParameters,
+ VariableDeclarations variableDeclarations,
+ @Nullable K.TypeConstraints typeConstraints,
+ @Nullable @JsonProperty("getter") J.MethodDeclaration getter,
+ @Nullable @JsonProperty("setter") J.MethodDeclaration setter,
+ @Nullable @JsonProperty("isSetterFirst") Boolean isSetterFirst,
+ JContainer accessors,
+ @Nullable JRightPadded receiver
+ ) {
+ this.id = id;
+ this.prefix = prefix;
+ this.markers = markers;
+ this.typeParameters = typeParameters;
+ this.variableDeclarations = variableDeclarations;
+ this.typeConstraints = typeConstraints;
- @Nullable
- JRightPadded receiver;
+ if (getter != null || setter != null || isSetterFirst != null) {
+ List> rps = new ArrayList<>(2);
+
+ // handle old LST removed fields `getter`, 'setter' and `isSetterFirst` which has been relocated to `accessors`
+ if (setter != null) {
+ rps.add(new JRightPadded<>(setter, Space.EMPTY, Markers.EMPTY));
+ }
+
+ if (getter != null) {
+ rps.add(new JRightPadded<>(getter, Space.EMPTY, Markers.EMPTY));
+ }
+
+ if (Boolean.FALSE.equals(isSetterFirst)) {
+ Collections.reverse(rps);
+ }
+ this.accessors = JContainer.build(rps);
+ } else {
+ this.accessors = accessors;
+ }
+
+ this.receiver = receiver;
+ }
@Nullable
public Expression getReceiver() {
@@ -1562,7 +1604,7 @@ public JContainer getTypeParameters() {
public Property withTypeParameters(@Nullable JContainer typeParameters) {
return t.typeParameters == typeParameters ? t : new Property(t.id, t.prefix, t.markers, typeParameters,
- t.variableDeclarations, t.typeConstraints, t.getter, t.setter, t.isSetterFirst, t.receiver);
+ t.variableDeclarations, t.typeConstraints, t.accessors, t.receiver);
}
@Nullable
@@ -1573,7 +1615,7 @@ public JRightPadded getReceiver() {
@Nullable
public Property withReceiver(@Nullable JRightPadded receiver) {
return t.receiver == receiver ? t : new Property(t.id, t.prefix, t.markers, t.typeParameters,
- t.variableDeclarations, t.typeConstraints, t.getter, t.setter, t.isSetterFirst, receiver);
+ t.variableDeclarations, t.typeConstraints, t.accessors, receiver);
}
}
}
diff --git a/src/test/java/org/openrewrite/kotlin/KotlinTypeMappingTest.java b/src/test/java/org/openrewrite/kotlin/KotlinTypeMappingTest.java
index 409a08a9e..3642a22a6 100644
--- a/src/test/java/org/openrewrite/kotlin/KotlinTypeMappingTest.java
+++ b/src/test/java/org/openrewrite/kotlin/KotlinTypeMappingTest.java
@@ -110,18 +110,20 @@ void fieldType() {
assertThat(id.getType()).isInstanceOf(JavaType.Class.class);
assertThat(id.getType().toString()).isEqualTo("kotlin.Int");
- JavaType.FullyQualified declaringType = property.getGetter().getMethodType().getDeclaringType();
+ J.MethodDeclaration getter = property.getAccessors().getElements().stream().filter(x -> x.getName().getSimpleName().equals("get")).findFirst().orElse(null);
+ JavaType.FullyQualified declaringType = getter.getMethodType().getDeclaringType();
assertThat(declaringType.getFullyQualifiedName()).isEqualTo("org.openrewrite.kotlin.KotlinTypeGoat");
- assertThat(property.getGetter().getMethodType().getName()).isEqualTo("get");
- assertThat(property.getGetter().getMethodType().getReturnType()).isEqualTo(id.getType());
- assertThat(property.getGetter().getName().getType()).isEqualTo(property.getGetter().getMethodType());
- assertThat(property.getGetter().getMethodType().toString().substring(declaringType.toString().length())).isEqualTo("{name=get,return=kotlin.Int,parameters=[]}");
+ assertThat(getter.getMethodType().getName()).isEqualTo("get");
+ assertThat(getter.getMethodType().getReturnType()).isEqualTo(id.getType());
+ assertThat(getter.getName().getType()).isEqualTo(getter.getMethodType());
+ assertThat(getter.getMethodType().toString().substring(declaringType.toString().length())).isEqualTo("{name=get,return=kotlin.Int,parameters=[]}");
- declaringType = property.getSetter().getMethodType().getDeclaringType();
+ J.MethodDeclaration setter = property.getAccessors().getElements().stream().filter(x -> x.getName().getSimpleName().equals("set")).findFirst().orElse(null);
+ declaringType = setter.getMethodType().getDeclaringType();
assertThat(declaringType.getFullyQualifiedName()).isEqualTo("org.openrewrite.kotlin.KotlinTypeGoat");
- assertThat(property.getSetter().getMethodType().getName()).isEqualTo("set");
- assertThat(property.getSetter().getMethodType()).isEqualTo(property.getSetter().getName().getType());
- assertThat(property.getSetter().getMethodType().toString().substring(declaringType.toString().length())).isEqualTo("{name=set,return=kotlin.Unit,parameters=[kotlin.Int]}");
+ assertThat(setter.getMethodType().getName()).isEqualTo("set");
+ assertThat(setter.getMethodType()).isEqualTo(setter.getName().getType());
+ assertThat(setter.getMethodType().toString().substring(declaringType.toString().length())).isEqualTo("{name=set,return=kotlin.Unit,parameters=[kotlin.Int]}");
}
@Test
diff --git a/src/test/java/org/openrewrite/kotlin/tree/VariableDeclarationTest.java b/src/test/java/org/openrewrite/kotlin/tree/VariableDeclarationTest.java
index 2fd1a642d..499e0e354 100644
--- a/src/test/java/org/openrewrite/kotlin/tree/VariableDeclarationTest.java
+++ b/src/test/java/org/openrewrite/kotlin/tree/VariableDeclarationTest.java
@@ -485,6 +485,23 @@ class Test {
);
}
+ @Test
+ void getterSetterWithTrailingSemiColon() {
+ rewriteRun(
+ kotlin(
+ """
+ class Test {
+ var stringRepresentation : String = ""
+ get ( ) = field ;
+ set ( value ) {
+ field = value
+ } ;
+ }
+ """
+ )
+ );
+ }
+
@Issue("https://github.com/openrewrite/rewrite-kotlin/issues/93")
@Test
void setterBeforeGetter() {