diff --git a/src/main/java/org/openrewrite/staticanalysis/OperatorWrap.java b/src/main/java/org/openrewrite/staticanalysis/OperatorWrap.java index 2e32979924..991662c194 100755 --- a/src/main/java/org/openrewrite/staticanalysis/OperatorWrap.java +++ b/src/main/java/org/openrewrite/staticanalysis/OperatorWrap.java @@ -15,6 +15,8 @@ */ package org.openrewrite.staticanalysis; +import lombok.EqualsAndHashCode; +import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.internal.ListUtils; @@ -28,7 +30,16 @@ import static java.util.Objects.requireNonNull; +@Value +@EqualsAndHashCode(callSuper = false) public class OperatorWrap extends Recipe { + + @Option(displayName = "Operator wrapping style", + description = "The operator wrapping style to enforce, which may differ from the configured or detected style.", + valid = {"EOL", "NL"}, + example = "NL") + OperatorWrapStyle.@Nullable WrapOption wrapOption; + @Override public String getDisplayName() { return "Operator wrapping"; @@ -41,382 +52,384 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return new OperatorWrapVisitor(); - } + return new JavaIsoVisitor() { + OperatorWrapStyle operatorWrapStyle; - private static class OperatorWrapVisitor extends JavaIsoVisitor { - OperatorWrapStyle operatorWrapStyle; + @Override + public J visit(@Nullable Tree tree, ExecutionContext ctx) { + if (tree instanceof JavaSourceFile) { + SourceFile cu = (SourceFile) requireNonNull(tree); + operatorWrapStyle = cu.getStyle(OperatorWrapStyle.class) == null ? Checkstyle.operatorWrapStyle() : cu.getStyle(OperatorWrapStyle.class); - @Override - public J visit(@Nullable Tree tree, ExecutionContext ctx) { - if (tree instanceof JavaSourceFile) { - SourceFile cu = (SourceFile) requireNonNull(tree); - operatorWrapStyle = cu.getStyle(OperatorWrapStyle.class) == null ? Checkstyle.operatorWrapStyle() : cu.getStyle(OperatorWrapStyle.class); + if (wrapOption != null) { + // Convenience override, to bypass having to configure a style once to change detected style + operatorWrapStyle = operatorWrapStyle.withWrapOption(wrapOption); + } + } + return super.visit(tree, ctx); } - return super.visit(tree, ctx); - } - @Override - public J.Binary visitBinary(J.Binary binary, ExecutionContext ctx) { - J.Binary b = super.visitBinary(binary, ctx); - J.Binary.Type op = b.getOperator(); - if ((Boolean.TRUE.equals(operatorWrapStyle.getDiv()) && op == J.Binary.Type.Division) || - (Boolean.TRUE.equals(operatorWrapStyle.getStar()) && op == J.Binary.Type.Multiplication) || - (Boolean.TRUE.equals(operatorWrapStyle.getPlus()) && op == J.Binary.Type.Addition) || - (Boolean.TRUE.equals(operatorWrapStyle.getMinus()) && op == J.Binary.Type.Subtraction) || - (Boolean.TRUE.equals(operatorWrapStyle.getMod()) && op == J.Binary.Type.Modulo) || - (Boolean.TRUE.equals(operatorWrapStyle.getSr()) && op == J.Binary.Type.RightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getSl()) && op == J.Binary.Type.LeftShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getBsr()) && op == J.Binary.Type.UnsignedRightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getEqual()) && op == J.Binary.Type.Equal) || - (Boolean.TRUE.equals(operatorWrapStyle.getNotEqual()) && op == J.Binary.Type.NotEqual) || - (Boolean.TRUE.equals(operatorWrapStyle.getGt()) && op == J.Binary.Type.GreaterThan) || - (Boolean.TRUE.equals(operatorWrapStyle.getGe()) && op == J.Binary.Type.GreaterThanOrEqual) || - (Boolean.TRUE.equals(operatorWrapStyle.getLt()) && op == J.Binary.Type.LessThan) || - (Boolean.TRUE.equals(operatorWrapStyle.getLe()) && op == J.Binary.Type.LessThanOrEqual) || - (Boolean.TRUE.equals(operatorWrapStyle.getBand()) && op == J.Binary.Type.BitAnd) || - (Boolean.TRUE.equals(operatorWrapStyle.getBxor()) && op == J.Binary.Type.BitXor) || - (Boolean.TRUE.equals(operatorWrapStyle.getBor()) && op == J.Binary.Type.BitOr) || - (Boolean.TRUE.equals(operatorWrapStyle.getLand()) && op == J.Binary.Type.And) || - (Boolean.TRUE.equals(operatorWrapStyle.getLor()) && op == J.Binary.Type.Or)) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (b.getRight().getPrefix().getWhitespace().contains("\n")) { - b = b.getPadding().withOperator( - b.getPadding().getOperator().withBefore( - b.getRight().getPrefix() - ) - ); + @Override + public J.Binary visitBinary(J.Binary binary, ExecutionContext ctx) { + J.Binary b = super.visitBinary(binary, ctx); + J.Binary.Type op = b.getOperator(); + if ((Boolean.TRUE.equals(operatorWrapStyle.getDiv()) && op == J.Binary.Type.Division) || + (Boolean.TRUE.equals(operatorWrapStyle.getStar()) && op == J.Binary.Type.Multiplication) || + (Boolean.TRUE.equals(operatorWrapStyle.getPlus()) && op == J.Binary.Type.Addition) || + (Boolean.TRUE.equals(operatorWrapStyle.getMinus()) && op == J.Binary.Type.Subtraction) || + (Boolean.TRUE.equals(operatorWrapStyle.getMod()) && op == J.Binary.Type.Modulo) || + (Boolean.TRUE.equals(operatorWrapStyle.getSr()) && op == J.Binary.Type.RightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getSl()) && op == J.Binary.Type.LeftShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getBsr()) && op == J.Binary.Type.UnsignedRightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getEqual()) && op == J.Binary.Type.Equal) || + (Boolean.TRUE.equals(operatorWrapStyle.getNotEqual()) && op == J.Binary.Type.NotEqual) || + (Boolean.TRUE.equals(operatorWrapStyle.getGt()) && op == J.Binary.Type.GreaterThan) || + (Boolean.TRUE.equals(operatorWrapStyle.getGe()) && op == J.Binary.Type.GreaterThanOrEqual) || + (Boolean.TRUE.equals(operatorWrapStyle.getLt()) && op == J.Binary.Type.LessThan) || + (Boolean.TRUE.equals(operatorWrapStyle.getLe()) && op == J.Binary.Type.LessThanOrEqual) || + (Boolean.TRUE.equals(operatorWrapStyle.getBand()) && op == J.Binary.Type.BitAnd) || + (Boolean.TRUE.equals(operatorWrapStyle.getBxor()) && op == J.Binary.Type.BitXor) || + (Boolean.TRUE.equals(operatorWrapStyle.getBor()) && op == J.Binary.Type.BitOr) || + (Boolean.TRUE.equals(operatorWrapStyle.getLand()) && op == J.Binary.Type.And) || + (Boolean.TRUE.equals(operatorWrapStyle.getLor()) && op == J.Binary.Type.Or)) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (b.getRight().getPrefix().getWhitespace().contains("\n")) { + b = b.getPadding().withOperator( + b.getPadding().getOperator().withBefore( + b.getRight().getPrefix() + ) + ); + b = b.withRight( + b.getRight().withPrefix( + b.getRight().getPrefix().withWhitespace(" ") + ) + ); + } + } else if (b.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { b = b.withRight( b.getRight().withPrefix( + b.getPadding().getOperator().getBefore() + ) + ); + b = b.getPadding().withOperator( + b.getPadding().getOperator().withBefore( b.getRight().getPrefix().withWhitespace(" ") ) ); } - } else if (b.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { - b = b.withRight( - b.getRight().withPrefix( - b.getPadding().getOperator().getBefore() - ) - ); - b = b.getPadding().withOperator( - b.getPadding().getOperator().withBefore( - b.getRight().getPrefix().withWhitespace(" ") - ) - ); } + return b; } - return b; - } - @Override - public J.TypeParameter visitTypeParameter(J.TypeParameter typeParam, ExecutionContext ctx) { - J.TypeParameter tp = super.visitTypeParameter(typeParam, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getTypeExtensionAnd()) && tp.getPadding().getBounds() != null) { - int typeBoundsSize = tp.getPadding().getBounds().getPadding().getElements().size(); - tp = tp.getPadding().withBounds( - tp.getPadding().getBounds().getPadding().withElements( - ListUtils.map(tp.getPadding().getBounds().getPadding().getElements(), - (index, elemContainer) -> { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (index != typeBoundsSize - 1 && typeParam.getPadding().getBounds() != null) { - JRightPadded next = typeParam.getPadding().getBounds().getPadding().getElements().get(index + 1); - if (next.getElement().getPrefix().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withAfter( - next.getElement().getPrefix() - ); + @Override + public J.TypeParameter visitTypeParameter(J.TypeParameter typeParam, ExecutionContext ctx) { + J.TypeParameter tp = super.visitTypeParameter(typeParam, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getTypeExtensionAnd()) && tp.getPadding().getBounds() != null) { + int typeBoundsSize = tp.getPadding().getBounds().getPadding().getElements().size(); + tp = tp.getPadding().withBounds( + tp.getPadding().getBounds().getPadding().withElements( + ListUtils.map(tp.getPadding().getBounds().getPadding().getElements(), + (index, elemContainer) -> { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (index != typeBoundsSize - 1 && typeParam.getPadding().getBounds() != null) { + JRightPadded next = typeParam.getPadding().getBounds().getPadding().getElements().get(index + 1); + if (next.getElement().getPrefix().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withAfter( + next.getElement().getPrefix() + ); + } + } else { + if (elemContainer.getElement().getPrefix().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withElement( + elemContainer.getElement().withPrefix( + elemContainer.getElement().getPrefix().withWhitespace(" ") + ) + ); + } } } else { - if (elemContainer.getElement().getPrefix().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withElement( - elemContainer.getElement().withPrefix( - elemContainer.getElement().getPrefix().withWhitespace(" ") - ) - ); - } - } - } else { - if (index != typeBoundsSize - 1) { - if (elemContainer.getAfter().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withAfter( - elemContainer.getAfter().withWhitespace(" ") - ); - } - } else if (typeBoundsSize > 1 && typeParam.getPadding().getBounds() != null) { - JRightPadded previous = typeParam.getPadding().getBounds().getPadding().getElements().get(index - 1); - if (previous.getAfter().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withElement( - elemContainer.getElement().withPrefix( - previous.getAfter() - ) - ); + if (index != typeBoundsSize - 1) { + if (elemContainer.getAfter().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withAfter( + elemContainer.getAfter().withWhitespace(" ") + ); + } + } else if (typeBoundsSize > 1 && typeParam.getPadding().getBounds() != null) { + JRightPadded previous = typeParam.getPadding().getBounds().getPadding().getElements().get(index - 1); + if (previous.getAfter().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withElement( + elemContainer.getElement().withPrefix( + previous.getAfter() + ) + ); + } } } + return elemContainer; } - return elemContainer; - } - ) - ) - ); + ) + ) + ); + } + return tp; } - return tp; - } - @Override - public J.InstanceOf visitInstanceOf(J.InstanceOf instanceOf, ExecutionContext ctx) { - J.InstanceOf i = super.visitInstanceOf(instanceOf, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getLiteralInstanceof())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (i.getClazz().getPrefix().getWhitespace().contains("\n")) { - i = i.getPadding().withExpr( - i.getPadding().getExpr().withAfter( - i.getClazz().getPrefix() - ) - ); + @Override + public J.InstanceOf visitInstanceOf(J.InstanceOf instanceOf, ExecutionContext ctx) { + J.InstanceOf i = super.visitInstanceOf(instanceOf, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getLiteralInstanceof())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (i.getClazz().getPrefix().getWhitespace().contains("\n")) { + i = i.getPadding().withExpr( + i.getPadding().getExpr().withAfter( + i.getClazz().getPrefix() + ) + ); + i = i.withClazz( + i.getClazz().withPrefix( + i.getClazz().getPrefix().withWhitespace(" ") + ) + ); + } + } else if (i.getPadding().getExpr().getAfter().getWhitespace().contains("\n")) { i = i.withClazz( i.getClazz().withPrefix( - i.getClazz().getPrefix().withWhitespace(" ") + i.getPadding().getExpr().getAfter() + ) + ); + i = i.getPadding().withExpr( + i.getPadding().getExpr().withAfter( + i.getPadding().getExpr().getAfter().withWhitespace(" ") ) ); } - } else if (i.getPadding().getExpr().getAfter().getWhitespace().contains("\n")) { - i = i.withClazz( - i.getClazz().withPrefix( - i.getPadding().getExpr().getAfter() - ) - ); - i = i.getPadding().withExpr( - i.getPadding().getExpr().withAfter( - i.getPadding().getExpr().getAfter().withWhitespace(" ") - ) - ); } + return i; } - return i; - } - @Override - public J.Ternary visitTernary(J.Ternary ternary, ExecutionContext ctx) { - J.Ternary t = super.visitTernary(ternary, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getQuestion())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (t.getTruePart().getPrefix().getWhitespace().contains("\n")) { - t = t.getPadding().withTruePart( - t.getPadding().getTruePart().withBefore( - t.getPadding().getTruePart().getElement().getPrefix() - ) - ); + @Override + public J.Ternary visitTernary(J.Ternary ternary, ExecutionContext ctx) { + J.Ternary t = super.visitTernary(ternary, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getQuestion())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (t.getTruePart().getPrefix().getWhitespace().contains("\n")) { + t = t.getPadding().withTruePart( + t.getPadding().getTruePart().withBefore( + t.getPadding().getTruePart().getElement().getPrefix() + ) + ); + t = t.getPadding().withTruePart( + t.getPadding().getTruePart().withElement( + t.getPadding().getTruePart().getElement().withPrefix( + t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } + } else if (t.getPadding().getTruePart().getBefore().getWhitespace().contains("\n")) { t = t.getPadding().withTruePart( t.getPadding().getTruePart().withElement( t.getPadding().getTruePart().getElement().withPrefix( - t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") + t.getPadding().getTruePart().getBefore() ) ) ); - } - } else if (t.getPadding().getTruePart().getBefore().getWhitespace().contains("\n")) { - t = t.getPadding().withTruePart( - t.getPadding().getTruePart().withElement( - t.getPadding().getTruePart().getElement().withPrefix( - t.getPadding().getTruePart().getBefore() - ) - ) - ); - t = t.getPadding().withTruePart( - t.getPadding().getTruePart().withBefore( - t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") - ) - ); - } - } - if (Boolean.TRUE.equals(operatorWrapStyle.getColon())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (t.getPadding().getFalsePart().getElement().getPrefix().getWhitespace().contains("\n")) { - t = t.getPadding().withFalsePart( - t.getPadding().getFalsePart().withBefore( - t.getPadding().getFalsePart().getElement().getPrefix() + t = t.getPadding().withTruePart( + t.getPadding().getTruePart().withBefore( + t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") ) ); + } + } + if (Boolean.TRUE.equals(operatorWrapStyle.getColon())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (t.getPadding().getFalsePart().getElement().getPrefix().getWhitespace().contains("\n")) { + t = t.getPadding().withFalsePart( + t.getPadding().getFalsePart().withBefore( + t.getPadding().getFalsePart().getElement().getPrefix() + ) + ); + t = t.getPadding().withFalsePart( + t.getPadding().getFalsePart().withElement( + t.getPadding().getFalsePart().getElement().withPrefix( + t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } + } else if (t.getPadding().getFalsePart().getBefore().getWhitespace().contains("\n")) { t = t.getPadding().withFalsePart( t.getPadding().getFalsePart().withElement( t.getPadding().getFalsePart().getElement().withPrefix( - t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") + t.getPadding().getFalsePart().getBefore() ) ) ); + t = t.getPadding().withFalsePart( + t.getPadding().getFalsePart().withBefore( + t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") + ) + ); } - } else if (t.getPadding().getFalsePart().getBefore().getWhitespace().contains("\n")) { - t = t.getPadding().withFalsePart( - t.getPadding().getFalsePart().withElement( - t.getPadding().getFalsePart().getElement().withPrefix( - t.getPadding().getFalsePart().getBefore() - ) - ) - ); - t = t.getPadding().withFalsePart( - t.getPadding().getFalsePart().withBefore( - t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") - ) - ); } + return t; } - return t; - } - @Override - public J.MemberReference visitMemberReference(J.MemberReference memberRef, ExecutionContext ctx) { - J.MemberReference m = super.visitMemberReference(memberRef, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getMethodRef())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (m.getPadding().getReference().getBefore().getWhitespace().contains("\n")) { - m = m.getPadding().withContaining( - m.getPadding().getContaining().withAfter( - m.getPadding().getReference().getBefore() - ) - ); + @Override + public J.MemberReference visitMemberReference(J.MemberReference memberRef, ExecutionContext ctx) { + J.MemberReference m = super.visitMemberReference(memberRef, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getMethodRef())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (m.getPadding().getReference().getBefore().getWhitespace().contains("\n")) { + m = m.getPadding().withContaining( + m.getPadding().getContaining().withAfter( + m.getPadding().getReference().getBefore() + ) + ); + m = m.getPadding().withReference( + m.getPadding().getReference().withBefore( + m.getPadding().getReference().getBefore().withWhitespace("") + ) + ); + } + } else if (m.getPadding().getContaining().getAfter().getWhitespace().contains("\n")) { m = m.getPadding().withReference( m.getPadding().getReference().withBefore( + m.getPadding().getContaining().getAfter() + ) + ); + m = m.getPadding().withContaining( + m.getPadding().getContaining().withAfter( m.getPadding().getReference().getBefore().withWhitespace("") ) ); } - } else if (m.getPadding().getContaining().getAfter().getWhitespace().contains("\n")) { - m = m.getPadding().withReference( - m.getPadding().getReference().withBefore( - m.getPadding().getContaining().getAfter() - ) - ); - m = m.getPadding().withContaining( - m.getPadding().getContaining().withAfter( - m.getPadding().getReference().getBefore().withWhitespace("") - ) - ); } + return m; } - return m; - } - @Override - public J.Assignment visitAssignment(J.Assignment assignment, ExecutionContext ctx) { - J.Assignment a = super.visitAssignment(assignment, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getAssign())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (a.getPadding().getAssignment().getElement().getPrefix().getWhitespace().contains("\n")) { - a = a.getPadding().withAssignment( - a.getPadding().getAssignment().withBefore( - a.getPadding().getAssignment().getElement().getPrefix() - ) - ); + @Override + public J.Assignment visitAssignment(J.Assignment assignment, ExecutionContext ctx) { + J.Assignment a = super.visitAssignment(assignment, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getAssign())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (a.getPadding().getAssignment().getElement().getPrefix().getWhitespace().contains("\n")) { + a = a.getPadding().withAssignment( + a.getPadding().getAssignment().withBefore( + a.getPadding().getAssignment().getElement().getPrefix() + ) + ); + a = a.getPadding().withAssignment( + a.getPadding().getAssignment().withElement( + a.getPadding().getAssignment().getElement().withPrefix( + a.getPadding().getAssignment().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } + } else if (a.getPadding().getAssignment().getBefore().getWhitespace().contains("\n")) { a = a.getPadding().withAssignment( a.getPadding().getAssignment().withElement( a.getPadding().getAssignment().getElement().withPrefix( - a.getPadding().getAssignment().getElement().getPrefix().withWhitespace(" ") + a.getPadding().getAssignment().getBefore() ) ) ); + a = a.getPadding().withAssignment( + a.getPadding().getAssignment().withBefore( + a.getPadding().getAssignment().getBefore().withWhitespace(" ") + ) + ); } - } else if (a.getPadding().getAssignment().getBefore().getWhitespace().contains("\n")) { - a = a.getPadding().withAssignment( - a.getPadding().getAssignment().withElement( - a.getPadding().getAssignment().getElement().withPrefix( - a.getPadding().getAssignment().getBefore() - ) - ) - ); - a = a.getPadding().withAssignment( - a.getPadding().getAssignment().withBefore( - a.getPadding().getAssignment().getBefore().withWhitespace(" ") - ) - ); } + return a; } - return a; - } - @Override - public J.AssignmentOperation visitAssignmentOperation(J.AssignmentOperation assignOp, ExecutionContext ctx) { - J.AssignmentOperation a = super.visitAssignmentOperation(assignOp, ctx); - J.AssignmentOperation.Type op = a.getOperator(); - if ((Boolean.TRUE.equals(operatorWrapStyle.getPlusAssign()) && op == J.AssignmentOperation.Type.Addition) || - (Boolean.TRUE.equals(operatorWrapStyle.getMinusAssign()) && op == J.AssignmentOperation.Type.Subtraction) || - (Boolean.TRUE.equals(operatorWrapStyle.getStarAssign()) && op == J.AssignmentOperation.Type.Multiplication) || - (Boolean.TRUE.equals(operatorWrapStyle.getDivAssign()) && op == J.AssignmentOperation.Type.Division) || - (Boolean.TRUE.equals(operatorWrapStyle.getModAssign()) && op == J.AssignmentOperation.Type.Modulo) || - (Boolean.TRUE.equals(operatorWrapStyle.getSrAssign()) && op == J.AssignmentOperation.Type.RightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getSlAssign()) && op == J.AssignmentOperation.Type.LeftShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getBsrAssign()) && op == J.AssignmentOperation.Type.UnsignedRightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getBandAssign()) && op == J.AssignmentOperation.Type.BitAnd) || - (Boolean.TRUE.equals(operatorWrapStyle.getBxorAssign()) && op == J.AssignmentOperation.Type.BitXor) || - (Boolean.TRUE.equals(operatorWrapStyle.getBorAssign()) && op == J.AssignmentOperation.Type.BitOr)) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (a.getAssignment().getPrefix().getWhitespace().contains("\n")) { - a = a.getPadding().withOperator( - a.getPadding().getOperator().withBefore( - a.getAssignment().getPrefix() - ) - ); + @Override + public J.AssignmentOperation visitAssignmentOperation(J.AssignmentOperation assignOp, ExecutionContext ctx) { + J.AssignmentOperation a = super.visitAssignmentOperation(assignOp, ctx); + J.AssignmentOperation.Type op = a.getOperator(); + if ((Boolean.TRUE.equals(operatorWrapStyle.getPlusAssign()) && op == J.AssignmentOperation.Type.Addition) || + (Boolean.TRUE.equals(operatorWrapStyle.getMinusAssign()) && op == J.AssignmentOperation.Type.Subtraction) || + (Boolean.TRUE.equals(operatorWrapStyle.getStarAssign()) && op == J.AssignmentOperation.Type.Multiplication) || + (Boolean.TRUE.equals(operatorWrapStyle.getDivAssign()) && op == J.AssignmentOperation.Type.Division) || + (Boolean.TRUE.equals(operatorWrapStyle.getModAssign()) && op == J.AssignmentOperation.Type.Modulo) || + (Boolean.TRUE.equals(operatorWrapStyle.getSrAssign()) && op == J.AssignmentOperation.Type.RightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getSlAssign()) && op == J.AssignmentOperation.Type.LeftShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getBsrAssign()) && op == J.AssignmentOperation.Type.UnsignedRightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getBandAssign()) && op == J.AssignmentOperation.Type.BitAnd) || + (Boolean.TRUE.equals(operatorWrapStyle.getBxorAssign()) && op == J.AssignmentOperation.Type.BitXor) || + (Boolean.TRUE.equals(operatorWrapStyle.getBorAssign()) && op == J.AssignmentOperation.Type.BitOr)) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (a.getAssignment().getPrefix().getWhitespace().contains("\n")) { + a = a.getPadding().withOperator( + a.getPadding().getOperator().withBefore( + a.getAssignment().getPrefix() + ) + ); + a = a.withAssignment( + a.getAssignment().withPrefix( + a.getAssignment().getPrefix().withWhitespace(" ") + ) + ); + } + } else if (a.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { a = a.withAssignment( a.getAssignment().withPrefix( + a.getPadding().getOperator().getBefore() + ) + ); + a = a.getPadding().withOperator( + a.getPadding().getOperator().withBefore( a.getAssignment().getPrefix().withWhitespace(" ") ) ); } - } else if (a.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { - a = a.withAssignment( - a.getAssignment().withPrefix( - a.getPadding().getOperator().getBefore() - ) - ); - a = a.getPadding().withOperator( - a.getPadding().getOperator().withBefore( - a.getAssignment().getPrefix().withWhitespace(" ") - ) - ); } + return a; } - return a; - } - @Override - public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext ctx) { - J.VariableDeclarations.NamedVariable v = super.visitVariable(variable, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getAssign()) && v.getPadding().getInitializer() != null) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (v.getPadding().getInitializer().getElement().getPrefix().getWhitespace().contains("\n")) { - v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withBefore( - v.getPadding().getInitializer().getElement().getPrefix() - ) - ); - if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getElement() != null) { + @Override + public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext ctx) { + J.VariableDeclarations.NamedVariable v = super.visitVariable(variable, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getAssign()) && v.getPadding().getInitializer() != null) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (v.getPadding().getInitializer().getElement().getPrefix().getWhitespace().contains("\n")) { v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withElement( - v.getPadding().getInitializer().getElement().withPrefix( - v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") - ) + v.getPadding().getInitializer().withBefore( + v.getPadding().getInitializer().getElement().getPrefix() ) ); + if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getElement() != null) { + v = v.getPadding().withInitializer( + v.getPadding().getInitializer().withElement( + v.getPadding().getInitializer().getElement().withPrefix( + v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } } - } - } else if (v.getPadding().getInitializer().getBefore().getWhitespace().contains("\n")) { - v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withElement( - v.getPadding().getInitializer().getElement().withPrefix( - v.getPadding().getInitializer().getBefore() - ) - ) - ); - if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getBefore() != null) { + } else if (v.getPadding().getInitializer().getBefore().getWhitespace().contains("\n")) { v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withBefore( - v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") + v.getPadding().getInitializer().withElement( + v.getPadding().getInitializer().getElement().withPrefix( + v.getPadding().getInitializer().getBefore() + ) ) ); + if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getBefore() != null) { + v = v.getPadding().withInitializer( + v.getPadding().getInitializer().withBefore( + v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") + ) + ); + } } } + return v; } - return v; - } + }; } - } diff --git a/src/test/java/org/openrewrite/staticanalysis/OperatorWrapTest.java b/src/test/java/org/openrewrite/staticanalysis/OperatorWrapTest.java new file mode 100644 index 0000000000..97e6d88aa7 --- /dev/null +++ b/src/test/java/org/openrewrite/staticanalysis/OperatorWrapTest.java @@ -0,0 +1,676 @@ +/* + * Copyright 2021 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.staticanalysis; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.Tree; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.format.AutoFormatVisitor; +import org.openrewrite.java.style.Checkstyle; +import org.openrewrite.java.style.OperatorWrapStyle; +import org.openrewrite.java.tree.J; +import org.openrewrite.style.NamedStyles; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.SourceSpec; + +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.UnaryOperator; + +import static java.util.Collections.emptySet; +import static java.util.Collections.singletonList; +import static org.openrewrite.java.Assertions.java; + +@SuppressWarnings({"StringConcatenationMissingWhitespace", "ConstantConditions", "CStyleArrayDeclaration"}) +class OperatorWrapTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new OperatorWrap(null)); + } + + private static List operatorWrapStyle() { + return operatorWrapStyle(style -> style); + } + + private static List operatorWrapStyle(UnaryOperator with) { + return Collections.singletonList( + new NamedStyles( + Tree.randomId(), "test", "test", "test", emptySet(), + singletonList(with.apply(Checkstyle.operatorWrapStyle())) + ) + ); + } + + @DocumentExample + @Test + void binaryOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle())), + //language=java + java( + """ + class Test { + static void method() { + String s = "aaa" + + "b" + "c"; + } + } + """, + """ + class Test { + static void method() { + String s = "aaa" + + "b" + "c"; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void binaryOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL)))), + //language=java + java( + """ + class Test { + static void method() { + String s = "aaa" + + "b" + "c"; + } + } + """, + """ + class Test { + static void method() { + String s = "aaa" + + "b" + "c"; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void typeParameterOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle())), + //language=java + java( + """ + import java.io.Serializable; + + class Test { + static > T method0() { + return null; + } + + static T method1() { + return null; + } + } + """, + """ + import java.io.Serializable; + + class Test { + static > T method0() { + return null; + } + + static T method1() { + return null; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void typeParameterOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL)))), + //language=java + java( + """ + import java.io.Serializable; + + class Test { + static > T method0() { + return null; + } + + static T method1() { + return null; + } + } + """, + """ + import java.io.Serializable; + + class Test { + static > T method0() { + return null; + } + + static T method1() { + return null; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void instanceOfOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle())), + //language=java + java( + """ + class Test { + static Object method(Object s) { + if (s instanceof + String) { + return null; + } + return s; + } + } + """, + """ + class Test { + static Object method(Object s) { + if (s + instanceof String) { + return null; + } + return s; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void instanceOfOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL)))), + //language=java + java( + """ + class Test { + static Object method(Object s) { + if (s + instanceof String) { + return null; + } + return s; + } + } + """, + """ + class Test { + static Object method(Object s) { + if (s instanceof + String) { + return null; + } + return s; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void ternaryOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle())), + //language=java + java( + """ + class Test { + static String method(String s) { + return s.contains("a") ? + "truePart" : + "falsePart"; + } + } + """, + """ + class Test { + static String method(String s) { + return s.contains("a") + ? "truePart" + : "falsePart"; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void ternaryOnNewlineIgnoringColon() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withColon(false)))), + //language=java + java( + """ + class Test { + static String method(String s) { + return s.contains("a") ? + "truePart" : + "falsePart"; + } + } + """, + """ + class Test { + static String method(String s) { + return s.contains("a") + ? "truePart" : + "falsePart"; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void ternaryOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL)))), + //language=java + java( + """ + class Test { + static String method(String s) { + return s.contains("a") + ? "truePart" + : "falsePart"; + } + } + """, + """ + class Test { + static String method(String s) { + return s.contains("a") ? + "truePart" : + "falsePart"; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void assignmentOperatorOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withAssign(true) + .withDivAssign(true) + .withPlusAssign(true) + .withMinusAssign(true) + .withStarAssign(true) + .withModAssign(true) + .withSrAssign(true) + .withBsrAssign(true) + .withSlAssign(true) + .withBxorAssign(true) + .withBorAssign(true) + .withBandAssign(true) + ))), + //language=java + java( + """ + class Test { + static int method() { + int a = 0; + a /= + 1; + a += + 1; + return a; + } + } + """, + """ + class Test { + static int method() { + int a = 0; + a + /= 1; + a + += 1; + return a; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void assignmentOperatorOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL) + .withAssign(true) + .withDivAssign(true) + .withPlusAssign(true) + .withMinusAssign(true) + .withStarAssign(true) + .withModAssign(true) + .withSrAssign(true) + .withBsrAssign(true) + .withSlAssign(true) + .withBxorAssign(true) + .withBorAssign(true) + .withBandAssign(true) + ))), + //language=java + java( + """ + class Test { + static int method() { + int a = 0; + a + /= 1; + a + += 1; + return a; + } + } + """, + """ + class Test { + static int method() { + int a = 0; + a /= + 1; + a += + 1; + return a; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void memberReferenceOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withMethodRef(true)))), + //language=java + java( + """ + import java.util.stream.Stream; + + class Test { + static void methodStream(Stream stream) { + stream.forEach(System.out:: + println); + } + } + """, + """ + import java.util.stream.Stream; + + class Test { + static void methodStream(Stream stream) { + stream.forEach(System.out + ::println); + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void memberReferenceOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL).withMethodRef(true)))), + //language=java + java( + """ + import java.util.stream.Stream; + + class Test { + static void methodStream(Stream stream) { + stream.forEach(System.out + ::println); + } + } + """, + """ + import java.util.stream.Stream; + + class Test { + static void methodStream(Stream stream) { + stream.forEach(System.out:: + println); + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void assignmentOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withAssign(true)))), + //language=java + java( + """ + class Test { + static int method() { + int n; + n = + 1; + return n; + } + } + """, + """ + class Test { + static int method() { + int n; + n + = 1; + return n; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void assignmentOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL).withAssign(true)))), + //language=java + java( + """ + class Test { + static int method() { + int n; + n + = 1; + return n; + } + } + """, + """ + class Test { + static int method() { + int n; + n = + 1; + return n; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void variableOnNewline() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withAssign(true)))), + //language=java + java( + """ + class Test { + static void method() { + int n = + 1; + int nArr[] = + new int[0]; + } + } + """, + """ + class Test { + static void method() { + int n + = 1; + int nArr[] + = new int[0]; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + @Test + void variableOnEndOfLine() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle(style -> + style.withWrapOption(OperatorWrapStyle.WrapOption.EOL).withAssign(true)))), + //language=java + java( + """ + class Test { + static void method() { + int n + = 1; + int nArr[] + = new int[0]; + } + } + """, + """ + class Test { + static void method() { + int n = + 1; + int nArr[] = + new int[0]; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } + + private static Consumer> autoFormatIsIdempotent() { + return spec -> spec.afterRecipe(cu -> + Assertions.assertThat(new AutoFormatVisitor<>().visit(cu, 0)).isEqualTo(cu)); + } + + @Test + void allowOverrideOfDetectedStyle() { + rewriteRun( + spec -> spec + .recipe(new OperatorWrap(OperatorWrapStyle.WrapOption.EOL)) + .parser(JavaParser.fromJavaVersion().styles(operatorWrapStyle())), + //language=java + java( + """ + class Test { + static void method() { + String s = "aaa" + + "b" + + "c"; + } + } + """, + """ + class Test { + static void method() { + String s = "aaa" + + "b" + + "c"; + } + } + """, + autoFormatIsIdempotent() + ) + ); + } +}