Skip to content

Commit

Permalink
Apply formatter to Joda time classes
Browse files Browse the repository at this point in the history
  • Loading branch information
timtebeek committed Oct 5, 2024
1 parent e013ee9 commit 984efb8
Show file tree
Hide file tree
Showing 8 changed files with 759 additions and 764 deletions.
261 changes: 128 additions & 133 deletions src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,160 +22,155 @@
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.migrate.joda.templates.*;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.MethodCall;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.java.tree.*;

import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.*;


public class JodaTimeVisitor extends JavaVisitor<ExecutionContext> {

private final MethodMatcher anyNewDateTime = new MethodMatcher(JODA_DATE_TIME + "<constructor>(..)");
private final MethodMatcher anyDateTime = new MethodMatcher(JODA_DATE_TIME + " *(..)");
private final MethodMatcher anyBaseDateTime = new MethodMatcher(JODA_BASE_DATE_TIME + " *(..)");
private final MethodMatcher zoneFor = new MethodMatcher(JODA_DATE_TIME_ZONE + " for*(..)");
private final MethodMatcher anyTimeFormatter = new MethodMatcher(JODA_TIME_FORMAT + " *(..)");
private final MethodMatcher anyNewDuration = new MethodMatcher(JODA_DURATION + "<constructor>(..)");
private final MethodMatcher anyDuration = new MethodMatcher(JODA_DURATION + " *(..)");

@Override
public @NonNull J visitCompilationUnit(@NonNull J.CompilationUnit cu, @NonNull ExecutionContext ctx) {
maybeRemoveImport(JODA_DATE_TIME);
maybeRemoveImport(JODA_DATE_TIME_ZONE);
maybeRemoveImport(JODA_TIME_FORMAT);
maybeRemoveImport(JODA_DURATION);
maybeRemoveImport("java.util.Locale");

maybeAddImport(JAVA_DATE_TIME);
maybeAddImport(JAVA_ZONE_OFFSET);
maybeAddImport(JAVA_ZONE_ID);
maybeAddImport(JAVA_INSTANT);
maybeAddImport(JAVA_TIME_FORMATTER);
maybeAddImport(JAVA_TIME_FORMAT_STYLE);
maybeAddImport(JAVA_DURATION);
maybeAddImport(JAVA_LOCAL_DATE);
maybeAddImport(JAVA_LOCAL_TIME);
maybeAddImport(JAVA_TEMPORAL_ISO_FIELDS);
maybeAddImport(JAVA_CHRONO_FIELD);
return super.visitCompilationUnit(cu, ctx);
}

@Override
public @NonNull J visitVariable(@NonNull J.VariableDeclarations.NamedVariable variable, @NonNull ExecutionContext ctx) {
// TODO implement logic for safe variable migration
if (variable.getType().isAssignableFrom(JODA_CLASS_PATTERN)) {
return variable;
}
return super.visitVariable(variable, ctx);
}

@Override
public @NonNull J visitNewClass(@NonNull J.NewClass newClass, @NonNull ExecutionContext ctx) {
MethodCall updated = (MethodCall) super.visitNewClass(newClass, ctx);
if (hasJodaType(updated.getArguments())) {
return newClass;
}
if (anyNewDateTime.matches(newClass)) {
return applyTemplate(newClass, updated, DateTimeTemplates.getTemplates()).orElse(newClass);
}
if (anyNewDuration.matches(newClass)) {
return applyTemplate(newClass, updated, DurationTemplates.getTemplates()).orElse(newClass);
private final MethodMatcher anyNewDateTime = new MethodMatcher(JODA_DATE_TIME + "<constructor>(..)");
private final MethodMatcher anyDateTime = new MethodMatcher(JODA_DATE_TIME + " *(..)");
private final MethodMatcher anyBaseDateTime = new MethodMatcher(JODA_BASE_DATE_TIME + " *(..)");
private final MethodMatcher zoneFor = new MethodMatcher(JODA_DATE_TIME_ZONE + " for*(..)");
private final MethodMatcher anyTimeFormatter = new MethodMatcher(JODA_TIME_FORMAT + " *(..)");
private final MethodMatcher anyNewDuration = new MethodMatcher(JODA_DURATION + "<constructor>(..)");
private final MethodMatcher anyDuration = new MethodMatcher(JODA_DURATION + " *(..)");

@Override
public @NonNull J visitCompilationUnit(@NonNull J.CompilationUnit cu, @NonNull ExecutionContext ctx) {
maybeRemoveImport(JODA_DATE_TIME);
maybeRemoveImport(JODA_DATE_TIME_ZONE);
maybeRemoveImport(JODA_TIME_FORMAT);
maybeRemoveImport(JODA_DURATION);
maybeRemoveImport("java.util.Locale");

maybeAddImport(JAVA_DATE_TIME);
maybeAddImport(JAVA_ZONE_OFFSET);
maybeAddImport(JAVA_ZONE_ID);
maybeAddImport(JAVA_INSTANT);
maybeAddImport(JAVA_TIME_FORMATTER);
maybeAddImport(JAVA_TIME_FORMAT_STYLE);
maybeAddImport(JAVA_DURATION);
maybeAddImport(JAVA_LOCAL_DATE);
maybeAddImport(JAVA_LOCAL_TIME);
maybeAddImport(JAVA_TEMPORAL_ISO_FIELDS);
maybeAddImport(JAVA_CHRONO_FIELD);
return super.visitCompilationUnit(cu, ctx);
}

@Override
public @NonNull J visitVariable(@NonNull J.VariableDeclarations.NamedVariable variable, @NonNull ExecutionContext ctx) {
// TODO implement logic for safe variable migration
if (variable.getType().isAssignableFrom(JODA_CLASS_PATTERN)) {
return variable;
}
return super.visitVariable(variable, ctx);
}
if (areArgumentsAssignable(updated)) {
return updated;

@Override
public @NonNull J visitNewClass(@NonNull J.NewClass newClass, @NonNull ExecutionContext ctx) {
MethodCall updated = (MethodCall) super.visitNewClass(newClass, ctx);
if (hasJodaType(updated.getArguments())) {
return newClass;
}
if (anyNewDateTime.matches(newClass)) {
return applyTemplate(newClass, updated, DateTimeTemplates.getTemplates()).orElse(newClass);
}
if (anyNewDuration.matches(newClass)) {
return applyTemplate(newClass, updated, DurationTemplates.getTemplates()).orElse(newClass);
}
if (areArgumentsAssignable(updated)) {
return updated;
}
return newClass;
}
return newClass;
}


@Override
public @NonNull J visitMethodInvocation(@NonNull J.MethodInvocation method, @NonNull ExecutionContext ctx) {
J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx);
if (hasJodaType(m.getArguments()) || isJodaVarRef(m.getSelect())) {
return method;
}
if (zoneFor.matches(method)) {
return applyTemplate(method, m, TimeZoneTemplates.getTemplates()).orElse(method);
}
if (anyDateTime.matches(method) || anyBaseDateTime.matches(method)) {
return applyTemplate(method, m, DateTimeTemplates.getTemplates()).orElse(method);
}
if (anyTimeFormatter.matches(method)) {
return applyTemplate(method, m, DateTimeFormatTemplates.getTemplates()).orElse(method);
}
if (anyDuration.matches(method)) {
return applyTemplate(method, m, DurationTemplates.getTemplates()).orElse(method);
}
if (areArgumentsAssignable(m)) {
return m;
}
return method;
}

@Override
public @NonNull J visitFieldAccess(@NonNull J.FieldAccess fieldAccess, @NonNull ExecutionContext ctx) {
J.FieldAccess f = (J.FieldAccess) super.visitFieldAccess(fieldAccess, ctx);
if (TypeUtils.isOfClassType(f.getType(), JODA_DATE_TIME_ZONE) && f.getSimpleName().equals("UTC")) {
return JavaTemplate.builder("ZoneOffset.UTC")
.imports(JAVA_ZONE_OFFSET)
.build()
.apply(updateCursor(f), f.getCoordinates().replace());
@Override
public @NonNull J visitMethodInvocation(@NonNull J.MethodInvocation method, @NonNull ExecutionContext ctx) {
J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx);
if (hasJodaType(m.getArguments()) || isJodaVarRef(m.getSelect())) {
return method;
}
if (zoneFor.matches(method)) {
return applyTemplate(method, m, TimeZoneTemplates.getTemplates()).orElse(method);
}
if (anyDateTime.matches(method) || anyBaseDateTime.matches(method)) {
return applyTemplate(method, m, DateTimeTemplates.getTemplates()).orElse(method);
}
if (anyTimeFormatter.matches(method)) {
return applyTemplate(method, m, DateTimeFormatTemplates.getTemplates()).orElse(method);
}
if (anyDuration.matches(method)) {
return applyTemplate(method, m, DurationTemplates.getTemplates()).orElse(method);
}
if (areArgumentsAssignable(m)) {
return m;
}
return method;
}
return f;
}

private boolean hasJodaType(List<Expression> exprs) {
for (Expression expr : exprs) {
JavaType exprType = expr.getType();
if (exprType != null && exprType.isAssignableFrom(Pattern.compile("org.joda.time.*"))) {
return true;
}
}
return false;
}

private Optional<MethodCall> applyTemplate(MethodCall original, MethodCall updated, List<MethodTemplate> templates) {
for (MethodTemplate template : templates) {
if (template.getMatcher().matches(original)) {
Expression[] args = template.getTemplateArgsFunc().apply(updated);
if (args.length == 0) {
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace()));
}
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace(), (Object[]) args));
}
@Override
public @NonNull J visitFieldAccess(@NonNull J.FieldAccess fieldAccess, @NonNull ExecutionContext ctx) {
J.FieldAccess f = (J.FieldAccess) super.visitFieldAccess(fieldAccess, ctx);
if (TypeUtils.isOfClassType(f.getType(), JODA_DATE_TIME_ZONE) && f.getSimpleName().equals("UTC")) {
return JavaTemplate.builder("ZoneOffset.UTC")
.imports(JAVA_ZONE_OFFSET)
.build()
.apply(updateCursor(f), f.getCoordinates().replace());
}
return f;
}
return Optional.empty(); // unhandled case
}

private boolean areArgumentsAssignable(MethodCall m) {
if (m.getMethodType() == null || m.getArguments().size() != m.getMethodType().getParameterTypes().size()) {
return false;
}
for (int i = 0; i < m.getArguments().size(); i++) {
if (!TypeUtils.isAssignableTo(m.getMethodType().getParameterTypes().get(i), m.getArguments().get(i).getType())) {
private boolean hasJodaType(List<Expression> exprs) {
for (Expression expr : exprs) {
JavaType exprType = expr.getType();
if (exprType != null && exprType.isAssignableFrom(Pattern.compile("org.joda.time.*"))) {
return true;
}
}
return false;
}
}
return true;
}

private boolean isJodaVarRef(@Nullable Expression expr) {
if (expr == null || expr.getType() == null || !expr.getType().isAssignableFrom(JODA_CLASS_PATTERN)) {
return false;
private Optional<MethodCall> applyTemplate(MethodCall original, MethodCall updated, List<MethodTemplate> templates) {
for (MethodTemplate template : templates) {
if (template.getMatcher().matches(original)) {
Expression[] args = template.getTemplateArgsFunc().apply(updated);
if (args.length == 0) {
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace()));
}
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace(), (Object[]) args));
}
}
return Optional.empty(); // unhandled case
}
if (expr instanceof J.FieldAccess) {
return ((J.FieldAccess) expr).getName().getFieldType() != null;

private boolean areArgumentsAssignable(MethodCall m) {
if (m.getMethodType() == null || m.getArguments().size() != m.getMethodType().getParameterTypes().size()) {
return false;
}
for (int i = 0; i < m.getArguments().size(); i++) {
if (!TypeUtils.isAssignableTo(m.getMethodType().getParameterTypes().get(i), m.getArguments().get(i).getType())) {
return false;
}
}
return true;
}
if (expr instanceof J.Identifier) {
return ((J.Identifier) expr).getFieldType() != null;

private boolean isJodaVarRef(@Nullable Expression expr) {
if (expr == null || expr.getType() == null || !expr.getType().isAssignableFrom(JODA_CLASS_PATTERN)) {
return false;
}
if (expr instanceof J.FieldAccess) {
return ((J.FieldAccess) expr).getName().getFieldType() != null;
}
if (expr instanceof J.Identifier) {
return ((J.Identifier) expr).getFieldType() != null;
}
return false;
}
return false;
}
}
Loading

0 comments on commit 984efb8

Please sign in to comment.