diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/ChangeStringValueOfNamedParameterInMethodInvocation.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/ChangeStringValueOfNamedParameterInMethodInvocation.java new file mode 100644 index 00000000000..c2563c7ca6d --- /dev/null +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/ChangeStringValueOfNamedParameterInMethodInvocation.java @@ -0,0 +1,108 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.groovy; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.groovy.tree.G; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; + +public class ChangeStringValueOfNamedParameterInMethodInvocation extends Recipe { + + @Option + public String methodName; + + @Option + public String key; + + @Option + public String value; + + public ChangeStringValueOfNamedParameterInMethodInvocation(final String methodName, final String key, final String value) { + this.methodName = methodName; + this.key = key; + this.value = value; + } + + @Override + public @NlsRewrite.DisplayName String getDisplayName() { + return "Change the value of a groovy named string parameter of a method invocation"; + } + + @Override + public @NlsRewrite.Description String getDescription() { + return "Changes the value of a given parameter in a given groovy method invocation, supporting Strings and GStrings."; + } + + @Override + public TreeVisitor getVisitor() { + return new GroovyIsoVisitor() { + @Override + public J visitMapEntry(G.MapEntry mapEntry, ExecutionContext ctx) { + mapEntry = (G.MapEntry) super.visitMapEntry(mapEntry, ctx); + + if (!isInTargetMethod()) { + return mapEntry; + } + + if (!hasStringValue(mapEntry)) { + return mapEntry; + } + + if (!mapEntry.getKey().toString().equals(key)) { + return mapEntry; + } + + if (mapEntry.getValue().toString().equals(value)) { + return mapEntry; + } + + return replaceValue(mapEntry); + } + + private boolean isInTargetMethod() { + return getCursor().firstEnclosingOrThrow(J.MethodInvocation.class).getSimpleName().equals(methodName); + } + + private G. MapEntry replaceValue(final G.MapEntry mapEntry) { + J.Literal entryValue = (J.Literal) mapEntry.getValue(); + + J.Literal newEntryValue = entryValue + .withValue(value) + .withValueSource(buildNewValueSource(entryValue)); + + return mapEntry.withValue(newEntryValue); + } + + private @Nullable String buildNewValueSource(J.Literal entryValue) { + String oldValue = entryValue.getValue() == null ? "" : entryValue.getValue().toString(); + + if (entryValue.getValueSource() == null) { + return null; + } + + return entryValue.getValueSource().replace(oldValue, value); + } + }; + } + + private static boolean hasStringValue(G.MapEntry mapEntry) { + return ((J.Literal) mapEntry.getValue()).getType().equals(JavaType.Primitive.String); + } + + +} diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/ChangeNamedStringParameterValueOfMethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/ChangeNamedStringParameterValueOfMethodInvocationTest.java new file mode 100644 index 00000000000..68cd4d7fa7b --- /dev/null +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/ChangeNamedStringParameterValueOfMethodInvocationTest.java @@ -0,0 +1,143 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.groovy; + +import org.junit.jupiter.api.Test; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.groovy.Assertions.groovy; + +class ChangeNamedStringParameterValueOfMethodInvocationTest implements RewriteTest { + + @Test + void whenParamSet_thenChangeToNewValue() { + rewriteRun(spec -> spec.recipe(new ChangeStringValueOfNamedParameterInMethodInvocation("method", "param", "newValue")), + //language=groovy + groovy( + """ + method( + param: 'oldValue' + ) + """, """ + method( + param: 'newValue' + ) + """ + ) + ); + } + + @Test + void noChangeWhenNewValueEqualsOldValue() { + rewriteRun(spec -> spec.recipe(new ChangeStringValueOfNamedParameterInMethodInvocation("method", "param", "value")), + //language=groovy + groovy( + """ + method( + param: 'value' + ) + """ + ) + ); + } + + @Test + void whenSingleParamSetWithGString_thenChangeToNewValue() { + rewriteRun(spec -> spec.recipe(new ChangeStringValueOfNamedParameterInMethodInvocation("method", "param", "newValue")), + //language=groovy + groovy( + """ + method( + param: "oldValue" + ) + """, """ + method( + param: "newValue" + ) + """ + ) + ); + } + + @Test + void whenMethodWithMultipleParameters_thenChangeOnlySelectedToNewValue() { + rewriteRun(spec -> spec.recipe(new ChangeStringValueOfNamedParameterInMethodInvocation("method", "param2", "newValue")), + //language=groovy + groovy( + """ + method( + param1: "oldValue", + param2: "oldValue", + param3: "oldValue" + ) + """, """ + method( + param1: "oldValue", + param2: "newValue", + param3: "oldValue" + ) + """ + ) + ); + } + + @Test + void whenTwoMethods_thenOnlyChangeOne() { + rewriteRun(spec -> spec.recipe(new ChangeStringValueOfNamedParameterInMethodInvocation("method2", "param", "newValue")), + groovy( + """ + method1( + param: "oldValue" + ) + method2( + param: "oldValue" + ) + """, """ + method1( + param: "oldValue" + ) + method2( + param: "newValue" + ) + """ + ) + ); + } + + @Test + void noChangeWhenParameterWithOtherDatatype() { + rewriteRun(spec -> spec.recipe(new ChangeStringValueOfNamedParameterInMethodInvocation("method", "param", "newValue")), + groovy( + """ + method( + param: 1 + ) + """ + ) + ); + } + + @Test + void noChangeWhenMethodWithoutParameters() { + rewriteRun(spec -> spec.recipe(new ChangeStringValueOfNamedParameterInMethodInvocation("method2", "param", "newValue")), + groovy( + """ + method() + """ + ) + ); + } +}