Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -75,6 +75,9 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
boolean argumentsEmpty = ((J.MethodInvocation) initializer).getArguments().stream().allMatch(p -> p instanceof J.Empty);
if (hasNoTypeParams && argumentsEmpty) return vd;

// mark imports for removal if unused
if (vd.getType() instanceof JavaType.FullyQualified) maybeRemoveImport((JavaType.FullyQualified) vd.getType());

return transformToVar(vd, new ArrayList<>(), new ArrayList<>());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ public String getDescription() {
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
new UsesJavaVersion<>(10),
new UseVarForGenericsConstructors.UseVarForGenericsVisitor());
new UseVarForGenericsConstructorsVisitor());
}

static final class UseVarForGenericsVisitor extends JavaIsoVisitor<ExecutionContext> {
static final class UseVarForGenericsConstructorsVisitor extends JavaIsoVisitor<ExecutionContext> {
private final JavaTemplate template = JavaTemplate.builder("var #{} = #{any()}")
.javaParser(JavaParser.fromJavaVersion()).build();

Expand All @@ -72,11 +72,22 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
List<JavaType> rightTypes = extractParameters(variable.getInitializer());
if (rightTypes == null || (leftTypes.isEmpty() && rightTypes.isEmpty())) return vd;

// skip generics with type bounds, it's not yet implemented
boolean genericHasBounds = leftTypes.stream()
.filter(t -> t instanceof JavaType.GenericTypeVariable)
.map(t -> (JavaType.GenericTypeVariable) t)
.map(t -> !t.getBounds().isEmpty())
.reduce(false, Boolean::logicalOr);
if (genericHasBounds) return vd;

// mark imports for removal if unused
if (vd.getType() instanceof JavaType.FullyQualified) maybeRemoveImport((JavaType.FullyQualified) vd.getType());

return transformToVar(vd, leftTypes, rightTypes);
}

/**
* Tries to extract the genric parameters from the expression,
* Tries to extract the generic parameters from the expression,
* if the Initializer is no new class or not of a parameterized type, returns null to signale "no info".
* if the initializer uses empty diamonds use an empty list to signale no type information
* @param initializer to extract parameters from
Expand All @@ -101,9 +112,14 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
return null;
}

private List<JavaType> extractParameters(@Nullable JavaType.Variable variableType) {
if (variableType != null && variableType.getType() instanceof JavaType.Parameterized) {
return ((JavaType.Parameterized) variableType.getType()).getTypeParameters();
/**
* Try to extract the parameters from the variables type.
* @param variable to extract from
* @return may be empty list of type parameters
*/
private List<JavaType> extractParameters(@Nullable JavaType.Variable variable) {
if (variable != null && variable.getType() instanceof JavaType.Parameterized) {
return ((JavaType.Parameterized) variable.getType()).getTypeParameters();
} else {
return new ArrayList<>();
}
Expand All @@ -113,14 +129,17 @@ private J.VariableDeclarations transformToVar(J.VariableDeclarations vd, List<Ja
Expression initializer = vd.getVariables().get(0).getInitializer();
String simpleName = vd.getVariables().get(0).getSimpleName();


// if left is defined but not right, copy types to initializer
if(rightTypes.isEmpty() && !leftTypes.isEmpty()) {
// we need to switch type infos from left to right here
List<Expression> typeArgument = leftTypes.stream()
.map(t ->
new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, ((JavaType.Class)t).getClassName(), t, null))
.map(UseVarForGenericsConstructorsVisitor::typeToExpression)
.collect(Collectors.toList());
J.ParameterizedType typedInitializerClazz = ((J.ParameterizedType) ((J.NewClass) initializer).getClazz()).withTypeParameters(typeArgument);

J.ParameterizedType typedInitializerClazz = ((J.ParameterizedType) ((J.NewClass) initializer)
.getClazz())
.withTypeParameters(typeArgument);
initializer = ((J.NewClass) initializer).withClazz(typedInitializerClazz);
}

Expand All @@ -143,5 +162,47 @@ private J.VariableDeclarations transformToVar(J.VariableDeclarations vd, List<Ja

return result;
}

/**
* recursively map a JavaType to an Expression with same semantics
* @param type to map
* @return semantically equal Expression
*/
private static Expression typeToExpression(JavaType type) {
if (type instanceof JavaType.Class) { // easy just parse to identifier
String className = ((JavaType.Class) type).getClassName();
return new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, className, type, null);
}
if (type instanceof JavaType.GenericTypeVariable) {
String variableName = ((JavaType.GenericTypeVariable) type).getName();
J.Identifier identifier = new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, variableName, type, null);

List<JavaType> bounds1 = ((JavaType.GenericTypeVariable) type).getBounds();
if (bounds1.isEmpty()) {
return identifier;
} else {
/*
List<JRightPadded<TypeTree>> bounds = bounds1.stream()
.map(b -> new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, , null, null))
.map(JRightPadded::build)
.collect(Collectors.toList());

return new J.TypeParameter(Tree.randomId(), Space.EMPTY, Markers.EMPTY, new ArrayList<>(), identifier, JContainer.build(bounds));
*/
throw new IllegalStateException("Generic type variables with bound are not supported, yet.");
}
}
if (type instanceof JavaType.Parameterized) { // recursively parse
List<JRightPadded<Expression>> typeParams = ((JavaType.Parameterized) type).getTypeParameters().stream()
.map(UseVarForGenericsConstructorsVisitor::typeToExpression)
.map(JRightPadded::build)
.collect(Collectors.toList());

NameTree clazz = new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, ((JavaType.Parameterized) type).getClassName(),null, null);
return new J.ParameterizedType(Tree.randomId(), Space.EMPTY, Markers.EMPTY, clazz, JContainer.build(typeParams), type);
}

throw new IllegalArgumentException(String.format("Unable to parse expression from JavaType %s", type));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package org.openrewrite.java.migrate.lang.var;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
Expand All @@ -27,8 +25,12 @@
import org.openrewrite.java.search.UsesJavaVersion;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeTree;

import lombok.EqualsAndHashCode;
import lombok.Value;

@Value
@EqualsAndHashCode(callSuper = false)
public class UseVarForObject extends Recipe {
Expand Down Expand Up @@ -73,6 +75,9 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
boolean usesTernary = DeclarationCheck.initializedByTernary(vd);
if (isPrimitive || usesGenerics || usesTernary) return vd;

// mark imports for removal if unused
if (vd.getType() instanceof JavaType.FullyQualified) maybeRemoveImport((JavaType.FullyQualified) vd.getType());

return transformToVar(vd);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
package org.openrewrite.java.migrate.lang.var;

import lombok.EqualsAndHashCode;
import lombok.Value;
import static java.lang.String.format;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
Expand All @@ -29,7 +29,8 @@
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;

import static java.lang.String.format;
import lombok.EqualsAndHashCode;
import lombok.Value;

@Value
@EqualsAndHashCode(callSuper = false)
Expand Down Expand Up @@ -79,6 +80,8 @@ public J.VariableDeclarations visitVariableDeclarations( J.VariableDeclarations
boolean isShortVariable = DeclarationCheck.declarationHasType(vd, SHORT_TYPE);
if (isNoPrimitive || isByteVariable || isShortVariable) return vd;

// no need to remove imports, because primitives are never imported

return transformToVar(vd);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openrewrite.Example;
import org.openrewrite.config.Environment;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
Expand Down Expand Up @@ -124,8 +125,6 @@ void varUsage() {
java("""
package com.example.app;

import java.util.Date;

class A {
void m() {
var str1 = "Hello World!";
Expand Down Expand Up @@ -390,6 +389,7 @@ void m() {
@Nested
class Applicable {
@Test
@Example
void forString() {
//language=java
rewriteRun(
Expand Down Expand Up @@ -713,6 +713,7 @@ void ifWelldefined() {
java("""
package com.example.app;

import java.util.List;
import java.util.ArrayList;

class A {
Expand Down Expand Up @@ -756,7 +757,6 @@ void m() {
package com.example.app;

import java.util.ArrayList;
import java.util.List;

class A {
void m() {
Expand All @@ -769,6 +769,7 @@ void m() {
);
}
@Test
@Example
void withDiamondOperator() {
//language=java
rewriteRun(
Expand All @@ -785,9 +786,8 @@ void m() {
}
}
""","""
package com.example.app;
package com.example.app;

import java.util.List;
import java.util.ArrayList;

class A {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

Expand All @@ -39,10 +40,6 @@ void forNonGenericMethod() {
java("""
package com.example.app;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

class A {
static String myString(String ... values) {
return String.join("",values);
Expand Down Expand Up @@ -160,6 +157,7 @@ void m() {
@Nested
class Applicable {
@Test
@DocumentExample
void withJDKFactoryMethods() {
//language=java
rewriteRun(
Expand Down
Loading