Skip to content

Commit

Permalink
Multiple type constraints support for classes, methods, and properties (
Browse files Browse the repository at this point in the history
#317)

* Multiple type constraints support for classes

Implements support for multiple type constraints at the class level.

Issue: #160

* Remove use of `withClasses()` from `AddImport`

Now in the presence of `K.ClassDeclaration` this is bound to cause even more confusion.

* Also use `TypeReferencePrefix` for type constraint formatting

* Support `where` clause on functions

* Support `where` clause on properties
  • Loading branch information
knutwannheden authored Sep 20, 2023
1 parent 40580c1 commit 1854a26
Show file tree
Hide file tree
Showing 12 changed files with 1,806 additions and 1,387 deletions.
10 changes: 5 additions & 5 deletions src/main/java/org/openrewrite/kotlin/AddImport.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String
if (cu.getPackageDeclaration() == null) {
// leave javadocs on the class and move other comments up to the import
// (which could include license headers and the like)
Space firstClassPrefix = cu.getClasses().get(0).getPrefix();
importToAdd = importToAdd.withPrefix(firstClassPrefix
.withComments(ListUtils.map(firstClassPrefix.getComments(), comment -> comment instanceof Javadoc ? null : comment))
Space firstStatementPrefix = cu.getStatements().get(0).getPrefix();
importToAdd = importToAdd.withPrefix(firstStatementPrefix
.withComments(ListUtils.map(firstStatementPrefix.getComments(), comment -> comment instanceof Javadoc ? null : comment))
.withWhitespace(""));

cu = cu.withClasses(ListUtils.mapFirst(cu.getClasses(), clazz ->
clazz.withComments(ListUtils.map(clazz.getComments(), comment -> comment instanceof Javadoc ? comment : null))
cu = cu.withStatements(ListUtils.mapFirst(cu.getStatements(), stmt ->
stmt.withComments(ListUtils.map(stmt.getComments(), comment -> comment instanceof Javadoc ? comment : null))
));
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/openrewrite/kotlin/KotlinIsoVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public K.Binary visitBinary(K.Binary binary, P p) {
return (K.Binary) super.visitBinary(binary, p);
}

@Override
public K.ClassDeclaration visitClassDeclaration(K.ClassDeclaration classDeclaration, P p) {
return (K.ClassDeclaration) super.visitClassDeclaration(classDeclaration, p);
}

@Override
public K.Constructor visitConstructor(K.Constructor constructor, P p) {
return (K.Constructor) super.visitConstructor(constructor, p);
Expand Down Expand Up @@ -82,6 +87,11 @@ public K.KThis visitKThis(K.KThis kThis, P p) {
return (K.KThis) super.visitKThis(kThis, p);
}

@Override
public K.MethodDeclaration visitMethodDeclaration(K.MethodDeclaration methodDeclaration, P p) {
return (K.MethodDeclaration) super.visitMethodDeclaration(methodDeclaration, p);
}

@Override
public K.ListLiteral visitListLiteral(K.ListLiteral listLiteral, P p) {
return (K.ListLiteral) super.visitListLiteral(listLiteral, p);
Expand All @@ -92,6 +102,11 @@ public K.Property visitProperty(K.Property property, P p) {
return (K.Property) super.visitProperty(property, p);
}

@Override
public K.TypeConstraints visitTypeConstraints(K.TypeConstraints typeConstraints, P p) {
return (K.TypeConstraints) super.visitTypeConstraints(typeConstraints, p);
}

@Override
public K.When visitWhen(K.When when, P p) {
return (K.When) super.visitWhen(when, p);
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/org/openrewrite/kotlin/KotlinVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ public J visitBinary(K.Binary binary, P p) {
return b;
}

public J visitClassDeclaration(K.ClassDeclaration classDeclaration, P p) {
K.ClassDeclaration c = classDeclaration;
c = c.withMarkers(visitMarkers(c.getMarkers(), p));
c = c.withClassDeclaration(visitAndCast(c.getClassDeclaration(), p));
c = c.withTypeConstraints(visitAndCast(c.getTypeConstraints(), p));
return c;
}

public J visitConstructor(K.Constructor constructor, P p) {
K.Constructor c = constructor;
c = c.withMarkers(visitMarkers(c.getMarkers(), p));
Expand Down Expand Up @@ -271,6 +279,14 @@ public J visitListLiteral(K.ListLiteral listLiteral, P p) {
return l;
}

public J visitMethodDeclaration(K.MethodDeclaration methodDeclaration, P p) {
K.MethodDeclaration m = methodDeclaration;
m = m.withMarkers(visitMarkers(m.getMarkers(), p));
m = m.withMethodDeclaration(visitAndCast(m.getMethodDeclaration(), p));
m = m.withTypeConstraints(visitAndCast(m.getTypeConstraints(), p));
return m;
}

public J visitNamedVariableInitializer(K.NamedVariableInitializer namedVariableInitializer, P p) {
K.NamedVariableInitializer n = namedVariableInitializer;
n = n.withPrefix(visitSpace(n.getPrefix(), KSpace.Location.NAMED_VARIABLE_INITIALIZER_PREFIX, p));
Expand All @@ -295,6 +311,13 @@ public J visitProperty(K.Property property, P p) {
return pr;
}

public J visitTypeConstraints(K.TypeConstraints typeConstraints, P p) {
K.TypeConstraints t = typeConstraints;
t = t.withMarkers(visitMarkers(t.getMarkers(), p));
t = t.getPadding().withConstraints(visitContainer(t.getPadding().getConstraints(), p));
return t;
}

public J visitWhen(K.When when, P p) {
K.When w = when;
w = w.withPrefix(visitSpace(w.getPrefix(), KSpace.Location.WHEN_PREFIX, p));
Expand Down
16 changes: 15 additions & 1 deletion src/main/java/org/openrewrite/kotlin/format/SpacesVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,21 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, P
return m;
}

@Override
public J.TypeParameter visitTypeParameter(J.TypeParameter typeParam, P p) {
J.TypeParameter pa = super.visitTypeParameter(typeParam, p);

// handle space before colon after declaration name
pa = pa.withMarkers(spaceBeforeColonAfterDeclarationName(pa.getMarkers()));
if (pa.getMarkers().findFirst(TypeReferencePrefix.class).isPresent()) {
pa = pa.withBounds(
ListUtils.map(pa.getBounds(), b ->
spaceBefore(b, style.getOther().getAfterColonBeforeDeclarationType()))
);
}
return pa;
}

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, P p) {
J.MethodInvocation m = super.visitMethodInvocation(method, p);
Expand Down Expand Up @@ -703,7 +718,6 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations m
if (multiVariable.getMarkers().findFirst(TypeReferencePrefix.class).orElse(null) != null &&
mv.getTypeExpression() != null) {
mv = mv.withTypeExpression(spaceBefore(mv.getTypeExpression(), style.getOther().getAfterColonBeforeDeclarationType()));

}
return mv;
}
Expand Down
49 changes: 42 additions & 7 deletions src/main/java/org/openrewrite/kotlin/internal/KotlinPrinter.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ public J visitBinary(K.Binary binary, PrintOutputCapture<P> p) {
return binary;
}

@Override
public J visitClassDeclaration(K.ClassDeclaration classDeclaration, PrintOutputCapture<P> p) {
return delegate.visitClassDeclaration0(classDeclaration.getClassDeclaration(), classDeclaration.getTypeConstraints(), p);
}

@Override
public J visitConstructor(K.Constructor constructor, PrintOutputCapture<P> p) {
J.MethodDeclaration method = constructor.getMethodDeclaration();
Expand Down Expand Up @@ -193,7 +198,7 @@ public J visitDestructuringDeclaration(K.DestructuringDeclaration destructuringD
}

if (!destructuringDeclaration.getInitializer().getVariables().isEmpty() &&
destructuringDeclaration.getInitializer().getVariables().get(0).getPadding().getInitializer() != null) {
destructuringDeclaration.getInitializer().getVariables().get(0).getPadding().getInitializer() != null) {
visitSpace(Objects.requireNonNull(destructuringDeclaration.getInitializer().getVariables().get(0).getPadding()
.getInitializer()).getBefore(), Space.Location.LANGUAGE_EXTENSION, p);
p.append("=");
Expand Down Expand Up @@ -316,6 +321,11 @@ public J visitListLiteral(K.ListLiteral listLiteral, PrintOutputCapture<P> p) {
return listLiteral;
}

@Override
public J visitMethodDeclaration(K.MethodDeclaration methodDeclaration, PrintOutputCapture<P> p) {
return delegate.visitMethodDeclaration0(methodDeclaration.getMethodDeclaration(), methodDeclaration.getTypeConstraints(), p);
}

@Override
public J visitProperty(K.Property property, PrintOutputCapture<P> p) {
beforeSyntax(property, KSpace.Location.PROPERTY_PREFIX, p);
Expand All @@ -334,14 +344,14 @@ public J visitProperty(K.Property property, PrintOutputCapture<P> p) {
Extension extension = vd.getMarkers().findFirst(Extension.class).orElse(null);
if (extension != null) {
if (property.getSetter() != null &&
!property.getSetter().getParameters().isEmpty() &&
property.getSetter().getParameters().get(0) instanceof J.VariableDeclarations) {
!property.getSetter().getParameters().isEmpty() &&
property.getSetter().getParameters().get(0) instanceof J.VariableDeclarations) {
visit(((J.VariableDeclarations) property.getSetter().getParameters().get(0)).getTypeExpression(), p);
delegate.visitSpace(property.getSetter().getPadding().getParameters().getPadding().getElements().get(0).getAfter(), Space.Location.LANGUAGE_EXTENSION, p);
p.append(".");
} else if (property.getGetter() != null &&
!property.getGetter().getParameters().isEmpty() &&
property.getGetter().getParameters().get(0) instanceof J.VariableDeclarations) {
!property.getGetter().getParameters().isEmpty() &&
property.getGetter().getParameters().get(0) instanceof J.VariableDeclarations) {
visit(((J.VariableDeclarations) property.getGetter().getParameters().get(0)).getTypeExpression(), p);
delegate.visitSpace(property.getGetter().getPadding().getParameters().getPadding().getElements().get(0).getAfter(), Space.Location.LANGUAGE_EXTENSION, p);
p.append(".");
Expand All @@ -367,6 +377,10 @@ public J visitProperty(K.Property property, PrintOutputCapture<P> p) {
visit(nv.getInitializer(), p);
}

if (property.getTypeConstraints() != null) {
delegate.visitContainer("where", property.getTypeConstraints().getPadding().getConstraints(), JContainer.Location.TYPE_PARAMETERS, ",", "", p);
}

if (property.isSetterFirst()) {
visit(property.getSetter(), p);
visit(property.getGetter(), p);
Expand Down Expand Up @@ -560,6 +574,11 @@ public <J2 extends J> JContainer<J2> visitContainer(@Nullable JContainer<J2> con

@Override
public J visitClassDeclaration(J.ClassDeclaration classDecl, PrintOutputCapture<P> p) {
return visitClassDeclaration0(classDecl, null, p);
}

@NotNull
private J.ClassDeclaration visitClassDeclaration0(J.ClassDeclaration classDecl, @Nullable K.TypeConstraints typeConstraints, PrintOutputCapture<P> p) {
beforeSyntax(classDecl, Space.Location.CLASS_DECLARATION_PREFIX, p);
visit(classDecl.getLeadingAnnotations(), p);
for (J.Modifier m : classDecl.getModifiers()) {
Expand Down Expand Up @@ -594,8 +613,8 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, PrintOutputCapture<
if (classDecl.getMarkers().findFirst(PrimaryConstructor.class).isPresent()) {
for (Statement statement : classDecl.getBody().getStatements()) {
if (statement instanceof J.MethodDeclaration &&
statement.getMarkers().findFirst(PrimaryConstructor.class).isPresent() &&
!statement.getMarkers().findFirst(Implicit.class).isPresent()) {
statement.getMarkers().findFirst(PrimaryConstructor.class).isPresent() &&
!statement.getMarkers().findFirst(Implicit.class).isPresent()) {
J.MethodDeclaration method = (J.MethodDeclaration) statement;
beforeSyntax(method, Space.Location.METHOD_DECLARATION_PREFIX, p);
visit(method.getLeadingAnnotations(), p);
Expand Down Expand Up @@ -635,6 +654,10 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, PrintOutputCapture<
afterSyntax(container.getMarkers(), p);
}

if (typeConstraints != null) {
visitContainer("where", typeConstraints.getPadding().getConstraints(), JContainer.Location.TYPE_PARAMETERS, ",", "", p);
}

if (!classDecl.getBody().getMarkers().findFirst(OmitBraces.class).isPresent()) {
visit(classDecl.getBody(), p);
}
Expand Down Expand Up @@ -790,6 +813,11 @@ private void visitLambdaParameters(J.Lambda.Parameters parameters, PrintOutputCa

@Override
public J visitMethodDeclaration(J.MethodDeclaration method, PrintOutputCapture<P> p) {
return visitMethodDeclaration0(method, null, p);
}

@NotNull
private J.MethodDeclaration visitMethodDeclaration0(J.MethodDeclaration method, @Nullable K.TypeConstraints typeConstraints, PrintOutputCapture<P> p) {
// Do not print generated methods.
for (Marker marker : method.getMarkers().getMarkers()) {
if (marker instanceof Implicit || marker instanceof PrimaryConstructor) {
Expand Down Expand Up @@ -847,6 +875,10 @@ public J visitMethodDeclaration(J.MethodDeclaration method, PrintOutputCapture<P
visit(method.getReturnTypeExpression(), p);
}

if (typeConstraints != null) {
visitContainer("where", typeConstraints.getPadding().getConstraints(), JContainer.Location.TYPE_PARAMETERS, ",", "", p);
}

visit(method.getBody(), p);
afterSyntax(method, p);
return method;
Expand Down Expand Up @@ -1019,6 +1051,9 @@ public J visitTypeParameter(J.TypeParameter typeParam, PrintOutputCapture<P> p)
delimiter = "in";
}
} else if (typeParam.getBounds() != null && !typeParam.getBounds().isEmpty()) {
typeParam.getMarkers().findFirst(TypeReferencePrefix.class).ifPresent(prefix ->
kotlinPrinter.visitSpace(prefix.getPrefix(), KSpace.Location.TYPE_REFERENCE_PREFIX, p)
);
delimiter = ":";
}
visitContainer(delimiter, typeParam.getPadding().getBounds(), JContainer.Location.TYPE_BOUNDS, "&", "", p);
Expand Down
Loading

0 comments on commit 1854a26

Please sign in to comment.