Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3f4e109
new recipe that changes .equals() to .contentEquals() when comparing …
AlekSimpson Jun 16, 2023
b4877a3
polished somethings up and added license headers
AlekSimpson Jun 16, 2023
ae41eb5
Update src/test/java/org/openrewrite/staticanalysis/EqualsToContentEq…
AlekSimpson Jun 16, 2023
90338a6
Update src/main/java/org/openrewrite/staticanalysis/EqualsToContentEq…
AlekSimpson Jun 16, 2023
b17a46b
Update src/main/java/org/openrewrite/staticanalysis/EqualsToContentEq…
AlekSimpson Jun 16, 2023
05753ca
Update src/main/java/org/openrewrite/staticanalysis/EqualsToContentEq…
AlekSimpson Jun 16, 2023
74ed6f4
Update src/main/java/org/openrewrite/staticanalysis/EqualsToContentEq…
AlekSimpson Jun 16, 2023
24c02a3
Update src/main/java/org/openrewrite/staticanalysis/EqualsToContentEq…
AlekSimpson Jun 16, 2023
ac3ccee
Update src/test/java/org/openrewrite/staticanalysis/EqualsToContentEq…
AlekSimpson Jun 16, 2023
15089c1
added missing import
AlekSimpson Jun 16, 2023
86e3d79
updated license header year
AlekSimpson Jun 16, 2023
9423d0e
added test to check that the recipe runs correctly on selects that ar…
AlekSimpson Jun 17, 2023
a69675b
added first test, need to test recipe
AlekSimpson Jun 18, 2023
dbc8624
the recipe for the toString() replacement is mostly finished, except …
AlekSimpson Jun 19, 2023
83890a9
Merge branch 'main' into alek/RemoveToStringCallsFromArrayInstances
AlekSimpson Jun 20, 2023
a574b69
fixed edge case, all tests pass now
AlekSimpson Jun 20, 2023
3c4ed65
added preconidition check
AlekSimpson Jun 20, 2023
bd586b7
added support for more methods that implicitly call toString() and al…
AlekSimpson Jun 22, 2023
18e5c8c
added RSPEC tags and updated import statements
AlekSimpson Jun 22, 2023
40167dd
The cursor message must be added before the `super` call
knutwannheden Jun 23, 2023
5ca3b34
fixed cursor messaging, updated tests for more edge case methods, rec…
AlekSimpson Jun 23, 2023
ffadf48
more changes from PR feedback
AlekSimpson Jun 26, 2023
f488a15
added support for static methods
AlekSimpson Jun 26, 2023
522afbe
Update src/main/java/org/openrewrite/staticanalysis/RemoveToStringCal…
AlekSimpson Jun 27, 2023
81f193a
Update src/test/java/org/openrewrite/staticanalysis/RemoveToStringCal…
timtebeek Jun 27, 2023
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
@@ -0,0 +1,87 @@
package org.openrewrite.staticanalysis;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;

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

public class RemoveToStringCallsFromArrayInstances extends Recipe {
private static final MethodMatcher TO_STRING_MATCHER = new MethodMatcher("java.lang.Object toString(..)");
private static final MethodMatcher PRINTLN_MATCHER = new MethodMatcher("java.io.PrintStream println(..)");
private static final MethodMatcher STR_FORMAT_MATCHER = new MethodMatcher("java.lang.String format(..)");

@Override
public String getDisplayName() {
return "hashCode and toString should not be called on array instances";
}

@Override
public String getDescription() {
return "hashCode and toString should not be called on array instances.";
}

public TreeVisitor<?, ExecutionContext> getVisitor() {
//return Preconditions.check(new UsesType<>("java.lang.Object[]", false), new RemoveToStringFromArraysVisitor());
return new RemoveToStringFromArraysVisitor();
}

private static class RemoveToStringFromArraysVisitor extends JavaIsoVisitor<ExecutionContext> {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation mi, ExecutionContext ctx) {
J.MethodInvocation m = super.visitMethodInvocation(mi, ctx);

if (TO_STRING_MATCHER.matches(m)) {
String builder_string = "Arrays.toString(#{anyArray(java.lang.String)})";
Expression select = m.getSelect();
assert select != null;

return buildReplacement(builder_string, m, select);

}else if (PRINTLN_MATCHER.matches(m)) {
Expression select = m.getArguments().get(0);
String builder_string = "System.out.println(Arrays.toString(#{anyArray(java.lang.String)}))";

return buildReplacement(builder_string, m, select);
}else if (STR_FORMAT_MATCHER.matches(m)) {
List<Expression> arguments = m.getArguments();

for (Expression arg : arguments) {
if (arg.getType() instanceof JavaType.Array) {
arg = JavaTemplate.builder("Arrays.toString(#{anyArray(java.lang.String)})")
.imports("java.util.Arrays")
.build()
.apply(getCursor(), arg.getCoordinates().replace(), arg);
}
}
maybeAddImport("java.util.Arrays");

return m.withArguments(arguments);
}

return m;
}

public J.MethodInvocation buildReplacement(String builder_string, J.MethodInvocation m, Expression select) {
if (!(select.getType() instanceof JavaType.Array)) {
return m;
}

J.MethodInvocation retVal = JavaTemplate.builder(builder_string)
.imports("java.util.Arrays")
.build()
.apply(getCursor(), m.getCoordinates().replace(), select);
maybeAddImport("java.util.Arrays");
return retVal;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import static org.openrewrite.java.Assertions.java;

class EqualsToContentEqualsTest implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package org.openrewrite.staticanalysis;

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

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

@SuppressWarnings({"ImplicitArrayToString", "UnnecessaryLocalVariable", "RedundantStringFormatCall", "MalformedFormatString", "PrimitiveArrayArgumentToVarargsMethod"})
public class RemoveToStringCallsFromArrayInstancesTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec
.parser(JavaParser.fromJavaVersion())
.recipe(new RemoveToStringCallsFromArrayInstances());
}

@Test
@DocumentExample
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/44")
public void fixNonCompliantToString() {
//language=java
rewriteRun(
java(
"""
class SomeClass {
public static void main(String[] args) {
String argStr = args.toString();
}
}
""",
"""
import java.util.Arrays;

class SomeClass {
public static void main(String[] args) {
String argStr = Arrays.toString(args);
}
}
"""
)
);
}

@Test
public void doesNotRunOnNonArrayInstances() {
//language=java
rewriteRun(
java(
"""
class SomeClass {
public static void main(String[] args) {
int number = 5;
System.out.println(number.toString());
}
}
"""
)
);
}

@Test
public void runsOnNonStringArrays() {
//language=java
rewriteRun(
java(
"""
class SomeClass {
public static void main(String[] args) {
String arrStr = getNumArr().toString();
}

public int[] getNumArr() {
int[] nums = {1, 2, 3, 4};
return nums;
}
}
""",
"""
import java.util.Arrays;

class SomeClass {
public static void main(String[] args) {
String arrStr = Arrays.toString(getNumArr());
}

public int[] getNumArr() {
int[] nums = {1, 2, 3, 4};
return nums;
}
}
"""
)
);
}

@Test
public void selectIsAMethod() {
//language=java
rewriteRun(
java(
"""
class SomeClass {
public static void main(String[] args) {
String arrStr = getArr().toString();
}

public String[] getArr() {
String[] arr = {"test", "array"};
return arr;
}
}
""",
"""
import java.util.Arrays;

class SomeClass {
public static void main(String[] args) {
String arrStr = Arrays.toString(getArr());
}

public String[] getArr() {
String[] arr = {"test", "array"};
return arr;
}
}
"""
)
);
}

@Test
public void printlnEdgeCase() {
//language=java
rewriteRun(
java(
"""
class SomeClass {
public static void main(String[] args) {
int[] s = new int[]{1,2,3};
System.out.println(s);
}
}
""",
"""
import java.util.Arrays;

class SomeClass {
public static void main(String[] args) {
int[] s = new int[]{1,2,3};
System.out.println(Arrays.toString(s));
}
}
"""
)
);
}

@Test
public void stringFormatEdgeCase() {
//language=java
rewriteRun(
java(
"""
class SomeClass {
public static void main(String[] args) {
int[] s = new int[]{1, 2, 3};
System.out.println(String.format("s=%s", s));
}
}
""",
"""
import java.util.Arrays;

class SomeClass {
public static void main(String[] args) {
int[] s = new int[]{1, 2, 3};
System.out.println(String.format("s=%s", Arrays.toString(s)));
}
}
"""
)
);
}

@Test
public void stringFormatMultipleArraysPassedIn() {
//language=java
rewriteRun(
java(
"""
class SomeClass {
public static void main(String[] args) {
int[] s1 = new int[]{1, 2, 3};
int[] s2 = new int[]{4, 5, 6};

System.out.println(String.format("s1=%s, s2=%s", s1, s2));
}
}
""",
"""
import java.util.Arrays;

class SomeClass {
public static void main(String[] args) {
int[] s1 = new int[]{1, 2, 3};
int[] s2 = new int[]{4, 5, 6};

System.out.println(String.format("s1=%s, s2=%s", Arrays.toString(s1), Arrays.toString(s2)));
}
}
"""
)
);
}
}