Skip to content

Commit

Permalink
Update K.Property model, add accessors as a replacement of `sette…
Browse files Browse the repository at this point in the history
…r`/`getter`/`isSetterFirst` (#523)

* Update K.Property model, add accessors as a replacement of setter/getter/isSetterFirst
  • Loading branch information
kunli2 authored Dec 15, 2023
1 parent eb4decc commit 52af835
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 50 deletions.
3 changes: 1 addition & 2 deletions src/main/java/org/openrewrite/kotlin/KotlinVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,14 +395,7 @@ public J visitProperty(K.Property property, PrintOutputCapture<P> 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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2811,13 +2811,10 @@ public J visitProperty(KtProperty property, ExecutionContext data) {
List<J.Modifier> modifiers = mapModifiers(property.getModifierList(), leadingAnnotations, lastAnnotations, data);
TypeTree typeExpression = null;
List<JRightPadded<J.VariableDeclarations.NamedVariable>> variables = new ArrayList<>();
J.MethodDeclaration getter = null;
J.MethodDeclaration setter = null;
JRightPadded<Expression> receiver = null;
JContainer<J.TypeParameter> typeParameters = property.getTypeParameterList() != null ?
JContainer.build(prefix(property.getTypeParameterList()), mapTypeParameters(property.getTypeParameterList(), data), Markers.EMPTY) : null;
K.TypeConstraints typeConstraints = null;
boolean isSetterFirst = false;
Set<PsiElement> prefixConsumedSet = preConsumedInfix(property);

modifiers.add(new J.Modifier(
Expand Down Expand Up @@ -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
Expand All @@ -2898,17 +2883,24 @@ public J visitProperty(KtProperty property, ExecutionContext data) {
.withPrefix(prefix(whereKeyword));
}

if (getter != null || setter != null || receiver != null || typeConstraints != null) {
List<KtPropertyAccessor> ktPropertyAccessors = property.getAccessors();
if (!ktPropertyAccessors.isEmpty() || receiver != null || typeConstraints != null) {
List<JRightPadded<J.MethodDeclaration>> 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),
markers,
typeParameters,
variableDeclarations.withPrefix(Space.EMPTY),
typeConstraints,
getter,
setter,
isSetterFirst,
JContainer.build(accessors),
receiver
);
} else {
Expand Down Expand Up @@ -3671,14 +3663,12 @@ private J.Block convertToBlock(KtExpression ktExpression, ExecutionContext data)

private <J2 extends J> JRightPadded<J2> 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())));
}

Expand Down
58 changes: 50 additions & 8 deletions src/main/java/org/openrewrite/kotlin/tree/K.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1503,16 +1504,57 @@ public List<TypeParameter> getTypeParameters() {
@Nullable
TypeConstraints typeConstraints;

@Nullable
J.MethodDeclaration getter;
// A replacement of `getter`,`setter` and `isSetterFirst`
JContainer<J.MethodDeclaration> accessors;

@Nullable
J.MethodDeclaration setter;
JRightPadded<Expression> 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<TypeParameter> 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<J.MethodDeclaration> accessors,
@Nullable JRightPadded<Expression> receiver
) {
this.id = id;
this.prefix = prefix;
this.markers = markers;
this.typeParameters = typeParameters;
this.variableDeclarations = variableDeclarations;
this.typeConstraints = typeConstraints;

@Nullable
JRightPadded<Expression> receiver;
if (getter != null || setter != null || isSetterFirst != null) {
List<JRightPadded<J.MethodDeclaration>> 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() {
Expand Down Expand Up @@ -1562,7 +1604,7 @@ public JContainer<TypeParameter> getTypeParameters() {

public Property withTypeParameters(@Nullable JContainer<TypeParameter> 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
Expand All @@ -1573,7 +1615,7 @@ public JRightPadded<Expression> getReceiver() {
@Nullable
public Property withReceiver(@Nullable JRightPadded<Expression> 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);
}
}
}
Expand Down
20 changes: 11 additions & 9 deletions src/test/java/org/openrewrite/kotlin/KotlinTypeMappingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 52af835

Please sign in to comment.