Skip to content

Commit

Permalink
Pull up recipes from rewrite-migrate-java (#4918)
Browse files Browse the repository at this point in the history
* Pull up recipes from rewrite-migrate-java

* Also pull up `UpdateMavenProjectPropertyJavaVersion`

* Apply formatter
timtebeek authored Jan 17, 2025
1 parent 9ddbb83 commit 1d96858
Showing 8 changed files with 1,515 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://docs.moderne.io/licensing/moderne-source-available-license
* <p>
* 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.java;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.Markers;

import static java.util.Collections.emptyList;

@Value
@EqualsAndHashCode(callSuper = false)
public class ChangeMethodInvocationReturnType extends Recipe {

@Option(displayName = "Method pattern",
description = "A method pattern that is used to find matching method declarations/invocations.",
example = "org.mockito.Matchers anyVararg()")
String methodPattern;

@Option(displayName = "New method invocation return type",
description = "The fully qualified new return type of method invocation.",
example = "long")
String newReturnType;

@Override
public String getDisplayName() {
return "Change method invocation return type";
}

@Override
public String getDescription() {
return "Changes the return type of a method invocation.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {
private final MethodMatcher methodMatcher = new MethodMatcher(methodPattern, false);

private boolean methodUpdated;

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
JavaType.Method type = m.getMethodType();
if (methodMatcher.matches(method) && type != null && !newReturnType.equals(type.getReturnType().toString())) {
type = type.withReturnType(JavaType.buildType(newReturnType));
m = m.withMethodType(type);
if (m.getName().getType() != null) {
m = m.withName(m.getName().withType(type));
}
methodUpdated = true;
}
return m;
}

@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) {
methodUpdated = false;
JavaType.FullyQualified originalType = multiVariable.getTypeAsFullyQualified();
J.VariableDeclarations mv = super.visitVariableDeclarations(multiVariable, ctx);

if (methodUpdated) {
JavaType newType = JavaType.buildType(newReturnType);
JavaType.FullyQualified newFieldType = TypeUtils.asFullyQualified(newType);

maybeAddImport(newFieldType);
maybeRemoveImport(originalType);

mv = mv.withTypeExpression(mv.getTypeExpression() == null ?
null :
new J.Identifier(mv.getTypeExpression().getId(),
mv.getTypeExpression().getPrefix(),
Markers.EMPTY,
emptyList(),
newReturnType.substring(newReturnType.lastIndexOf('.') + 1),
newType,
null
)
);

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

return mv;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://docs.moderne.io/licensing/moderne-source-available-license
* <p>
* 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.java;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;

@Value
@EqualsAndHashCode(callSuper = false)
public class ReplaceStringLiteralValue extends Recipe {

@Option(displayName = "Old literal `String` value",
description = "The `String` value to replace.",
example = "apple")
String oldLiteralValue;

@Option(displayName = "New literal `String` value",
description = "The `String` value to replace with.",
example = "orange")
String newLiteralValue;

@JsonCreator
public ReplaceStringLiteralValue(@JsonProperty("oldStringValue") String oldStringValue, @JsonProperty("newStringValue") String newStringValue) {
this.oldLiteralValue = oldStringValue;
this.newLiteralValue = newStringValue;
}

@Override
public String getDisplayName() {
return "Replace `String` literal";
}

@Override
public String getDescription() {
return "Replace the value of a complete `String` literal.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.Literal visitLiteral(J.Literal literal, ExecutionContext ctx) {
J.Literal lit = super.visitLiteral(literal, ctx);
if (lit.getType() == JavaType.Primitive.String &&
oldLiteralValue.equals(lit.getValue())) {
return lit
.withValue(newLiteralValue)
.withValueSource('"' + newLiteralValue + '"');
}
return lit;
}
};
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://docs.moderne.io/licensing/moderne-source-available-license
* <p>
* 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.java;

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

import static org.openrewrite.java.Assertions.java;

class ChangeMethodInvocationReturnTypeTest implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new ChangeMethodInvocationReturnType("java.lang.Integer parseInt(String)", "long"));
}

@Test
@DocumentExample
void replaceVariableAssignment() {
rewriteRun(
//language=java
java(
"""
class Foo {
void bar() {
int one = Integer.parseInt("1");
}
}
""",
"""
class Foo {
void bar() {
long one = Integer.parseInt("1");
}
}
"""
)
);
}

@Test
void shouldOnlyChangeTargetMethodAssignments() {
rewriteRun(
//language=java
java(
"""
class Foo {
void bar() {
int zero = Integer.valueOf("0");
int one = Integer.parseInt("1");
int two = Integer.valueOf("2");
}
}
""",
"""
class Foo {
void bar() {
int zero = Integer.valueOf("0");
long one = Integer.parseInt("1");
int two = Integer.valueOf("2");
}
}
"""
)
);
}

@Test
void replaceVariableAssignmentFullyQualified() {
rewriteRun(
spec -> spec.recipe(new ChangeMethodInvocationReturnType("bar.Bar bar()", "java.math.BigInteger"))
.parser(JavaParser.fromJavaVersion()
//language=java
.dependsOn(
"""
package bar;
public class Bar {
public static Integer bar() {
return null;
}
}
"""
)
),
//language=java
java(
"""
import bar.Bar;
class Foo {
void foo() {
Integer one = Bar.bar();
}
}
""",
"""
import bar.Bar;
import java.math.BigInteger;
class Foo {
void foo() {
BigInteger one = Bar.bar();
}
}
"""
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2025 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.java;

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

import static org.openrewrite.java.Assertions.java;

class ReplaceStringLiteralValueTest implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new ReplaceStringLiteralValue("apple", "orange"));
}

@DocumentExample
@Test
void replaceAppleWithOrange() {
rewriteRun(
java(
"""
class Test {
String s = "apple";
}
""",
"""
class Test {
String s = "orange";
}
"""
)
);
}
@Test
void doNotReplacePineapply() {
rewriteRun(
java(
"""
class Test {
// We only match the full String literal value
String s = "pineapple";
}
"""
)
);
}

}
Loading

0 comments on commit 1d96858

Please sign in to comment.