Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,48 @@
*/
package org.openrewrite.java.migrate.guava;

import static java.util.Collections.emptyList;

import java.util.ArrayList;
import org.jspecify.annotations.Nullable;
import org.openrewrite.*;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.Tree;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.search.UsesJavaVersion;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.*;
import org.openrewrite.marker.Markers;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

import static java.util.Collections.emptyList;
import org.openrewrite.marker.Markers;

abstract class AbstractNoGuavaImmutableOf extends Recipe {

private final String guavaType;
private final String javaType;

@Option(displayName = "Whether to convert return type (the default value is false).",
description = "converting the return type from Guava Type to Java Type " +
"The default value is false.",
example = "true",
required = false)
boolean isAbleToConvertReturnType;
AbstractNoGuavaImmutableOf(String guavaType, String javaType) {
this.guavaType = guavaType;
this.javaType = javaType;
}
AbstractNoGuavaImmutableOf(String guavaType, String javaType, boolean isAbleToConvertReturnType) {
this.guavaType = guavaType;
this.javaType = javaType;
this.isAbleToConvertReturnType = isAbleToConvertReturnType;
}

private String getShortType(String fullyQualifiedType) {
return fullyQualifiedType.substring(javaType.lastIndexOf(".") + 1);
Expand Down Expand Up @@ -100,55 +116,6 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx)
return super.visitMethodInvocation(m, ctx);
}

@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) {
J.VariableDeclarations mv = (J.VariableDeclarations) super.visitVariableDeclarations(multiVariable, ctx);

if (multiVariable != mv && TypeUtils.isOfClassType(mv.getType(), guavaType)) {
JavaType newType = JavaType.buildType(javaType);
mv = mv.withTypeExpression(mv.getTypeExpression() == null ?
null : createNewTypeExpression(mv.getTypeExpression(), newType));

mv = mv.withVariables(ListUtils.map(mv.getVariables(), variable -> {
JavaType.FullyQualified varType = TypeUtils.asFullyQualified(variable.getType());
if (varType != null && !varType.equals(newType)) {
return variable.withType(newType).withName(variable.getName().withType(newType));
}
return variable;
}));
}

return mv;
}

private TypeTree createNewTypeExpression(TypeTree typeTree, JavaType newType) {
if (typeTree instanceof J.ParameterizedType) {
J.ParameterizedType parameterizedType = (J.ParameterizedType) typeTree;
List<JRightPadded<Expression>> jRightPaddedList = new ArrayList<>();
parameterizedType.getTypeParameters().forEach(
expression -> {
if (expression instanceof J.ParameterizedType && TypeUtils.isOfClassType(expression.getType(), guavaType)) {
jRightPaddedList.add(JRightPadded.build(((J.ParameterizedType) createNewTypeExpression((TypeTree) expression, newType))));
} else {
jRightPaddedList.add(JRightPadded.build(expression));
}
});
NameTree clazz = new J.Identifier(
Tree.randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), getShortType(javaType), null, null);
return parameterizedType.withClazz(clazz).withType(newType).getPadding().withTypeParameters(JContainer.build(jRightPaddedList));
}
return new J.Identifier(
typeTree.getId(),
typeTree.getPrefix(),
Markers.EMPTY,
emptyList(),
getShortType(javaType),
newType,
null
);
}


private boolean isParentTypeDownCast(MethodCall immutableMethod) {
J parent = getCursor().dropParentUntil(J.class::isInstance).getValue();
boolean isParentTypeDownCast = false;
Expand All @@ -173,10 +140,12 @@ private boolean isParentTypeDownCast(MethodCall immutableMethod) {
} else if (parent instanceof J.MethodInvocation) {
J.MethodInvocation m = (J.MethodInvocation) parent;
int index = m.getArguments().indexOf(immutableMethod);
if (m.getMethodType() != null && index != -1 && !m.getMethodType().getParameterTypes().isEmpty()) {
isParentTypeDownCast = isParentTypeMatched(m.getMethodType().getParameterTypes().get(index));
} else {
isParentTypeDownCast = true;
if (m.getMethodType() != null) {
if (index != -1 && !m.getMethodType().getParameterTypes().isEmpty()) {
isParentTypeDownCast = isParentTypeMatched(m.getMethodType().getParameterTypes().get(index));
} else {
isParentTypeDownCast = !TypeUtils.isOfClassType(m.getMethodType().getReturnType(), guavaType);
}
}
} else if (parent instanceof J.NewClass) {
J.NewClass c = (J.NewClass) parent;
Expand Down Expand Up @@ -204,11 +173,62 @@ private boolean isParentTypeDownCast(MethodCall immutableMethod) {
return isParentTypeDownCast;
}

@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) {
J.VariableDeclarations mv = (J.VariableDeclarations) super.visitVariableDeclarations(multiVariable, ctx);
if(!isAbleToConvertReturnType) {
return mv;
}
if (multiVariable != mv && TypeUtils.isOfClassType(mv.getType(), guavaType)) {
JavaType newType = JavaType.buildType(javaType);
mv = mv.withTypeExpression(mv.getTypeExpression() == null ?
null : createNewTypeExpression(mv.getTypeExpression(), newType));

mv = mv.withVariables(ListUtils.map(mv.getVariables(), variable -> {
JavaType.FullyQualified varType = TypeUtils.asFullyQualified(variable.getType());
if (varType != null && !varType.equals(newType)) {
return variable.withType(newType).withName(variable.getName().withType(newType));
}
return variable;
}));
}

return mv;
}

private TypeTree createNewTypeExpression(TypeTree typeTree, JavaType newType) {
if (typeTree instanceof J.ParameterizedType) {
J.ParameterizedType parameterizedType = (J.ParameterizedType) typeTree;
List<JRightPadded<Expression>> jRightPaddedList = new ArrayList<>();
parameterizedType.getTypeParameters().forEach(
expression -> {
if (expression instanceof J.ParameterizedType && TypeUtils.isOfClassType(expression.getType(), guavaType)) {
jRightPaddedList.add(JRightPadded.build(((J.ParameterizedType) createNewTypeExpression((TypeTree) expression, newType))));
} else {
jRightPaddedList.add(JRightPadded.build(expression));
}
});
NameTree clazz = new J.Identifier(
Tree.randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), getShortType(javaType), null, null);
return parameterizedType.withClazz(clazz).withType(newType).getPadding().withTypeParameters(JContainer.build(jRightPaddedList));
}
return new J.Identifier(
typeTree.getId(),
typeTree.getPrefix(),
Markers.EMPTY,
emptyList(),
getShortType(javaType),
newType,
null
);
}


private boolean isParentTypeMatched(@Nullable JavaType type) {
JavaType.FullyQualified fq = TypeUtils.asFullyQualified(type);
return TypeUtils.isOfClassType(fq, javaType) ||
TypeUtils.isOfClassType(fq, "java.lang.Object") ||
TypeUtils.isOfClassType(fq, guavaType);
(isAbleToConvertReturnType && TypeUtils.isOfClassType(fq, guavaType)) ||
TypeUtils.isOfClassType(fq, "java.lang.Object");
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ public class NoGuavaImmutableListOf extends AbstractNoGuavaImmutableOf {
public NoGuavaImmutableListOf() {
super("com.google.common.collect.ImmutableList", "java.util.List");
}

public NoGuavaImmutableListOf(boolean isAbleToConvertReturnType) {
super("com.google.common.collect.ImmutableList", "java.util.List", isAbleToConvertReturnType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ public class NoGuavaImmutableMapOf extends AbstractNoGuavaImmutableOf {
public NoGuavaImmutableMapOf() {
super("com.google.common.collect.ImmutableMap", "java.util.Map");
}
public NoGuavaImmutableMapOf(boolean isAbleToConvertReturnType) {
super("com.google.common.collect.ImmutableMap", "java.util.Map", isAbleToConvertReturnType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ public class NoGuavaImmutableSetOf extends AbstractNoGuavaImmutableOf {
public NoGuavaImmutableSetOf() {
super("com.google.common.collect.ImmutableSet", "java.util.Set");
}
public NoGuavaImmutableSetOf(boolean isAbleToConvertReturnType) {
super("com.google.common.collect.ImmutableSet", "java.util.Set", isAbleToConvertReturnType);
}
}
Loading