Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HotFix] NoGuavaJava21 causing invalid code since v2.28.0 #601

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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;
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
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;
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
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
Loading