|
22 | 22 | import org.openrewrite.java.JavaIsoVisitor; |
23 | 23 | import org.openrewrite.java.MethodMatcher; |
24 | 24 | import org.openrewrite.java.search.UsesType; |
25 | | -import org.openrewrite.java.tree.*; |
| 25 | +import org.openrewrite.java.tree.Expression; |
| 26 | +import org.openrewrite.java.tree.J; |
| 27 | +import org.openrewrite.java.tree.TypeUtils; |
26 | 28 |
|
27 | | -import java.util.Arrays; |
28 | 29 | import java.util.Collections; |
29 | | -import java.util.List; |
30 | | -import java.util.stream.Stream; |
| 30 | +import java.util.Set; |
31 | 31 |
|
32 | 32 | public class EqualsToContentEquals extends Recipe { |
33 | | - private static final MethodMatcher equals_matcher = new MethodMatcher("java.lang.String equals(..)"); |
34 | 33 | private static final TreeVisitor<?, ExecutionContext> PRECONDITION = Preconditions.or( |
| 34 | + new UsesType<>("java.lang.CharSequence", false), |
35 | 35 | new UsesType<>("java.lang.StringBuffer", false), |
36 | | - new UsesType<>("java.lang.StringBuilder", false), |
37 | | - new UsesType<>("java.lang.CharSequence", false)); |
38 | | - private static final List<MethodMatcher> TOSTRING_MATCHERS = Arrays.asList( |
39 | | - new MethodMatcher("java.lang.String toString()"), |
40 | | - new MethodMatcher("java.lang.StringBuffer toString()"), |
41 | | - new MethodMatcher("java.lang.StringBuilder toString()"), |
42 | | - new MethodMatcher("java.lang.CharSequence toString()")); |
| 36 | + new UsesType<>("java.lang.StringBuilder", false) |
| 37 | + ); |
43 | 38 |
|
44 | 39 | @Override |
45 | 40 | public String getDisplayName() { |
46 | | - return "Use contentEquals to compare StringBuilder to a String"; |
| 41 | + return "Use `String.contentEquals(CharSequence)` instead of `String.equals(CharSequence.toString())`"; |
47 | 42 | } |
| 43 | + |
48 | 44 | @Override |
49 | 45 | public String getDescription() { |
50 | | - return "Use contentEquals to compare StringBuilder to a String."; |
| 46 | + return "Use `String.contentEquals(CharSequence)` instead of `String.equals(CharSequence.toString())`."; |
51 | 47 | } |
52 | 48 |
|
53 | 49 | public TreeVisitor<?, ExecutionContext> getVisitor() { |
54 | 50 | return Preconditions.check(PRECONDITION, new EqualsToContentEqualsVisitor()); |
55 | 51 | } |
56 | 52 |
|
57 | 53 | private static class EqualsToContentEqualsVisitor extends JavaIsoVisitor<ExecutionContext> { |
| 54 | + private static final MethodMatcher EQUALS_MATCHER = new MethodMatcher("String equals(Object)"); |
| 55 | + private static final MethodMatcher TOSTRING_MATCHER = new MethodMatcher("java.lang.* toString()"); |
| 56 | + |
58 | 57 | @Override |
59 | 58 | public J.MethodInvocation visitMethodInvocation(J.MethodInvocation mi, ExecutionContext ctx) { |
60 | 59 | J.MethodInvocation m = super.visitMethodInvocation(mi, ctx); |
61 | | - // create method matcher on equals(String) |
62 | | - if (equals_matcher.matches(m)) { |
63 | | - Expression argument = m.getArguments().get(0); |
64 | | - |
65 | | - // checks whether the argument is a toString() method call on a StringBuffer or CharSequence |
66 | | - if (TOSTRING_MATCHERS.stream().anyMatch(matcher -> matcher.matches(argument))) { |
67 | | - J.MethodInvocation inv = (J.MethodInvocation) argument; |
68 | | - Expression newArg = inv.getSelect(); |
69 | | - if (inv.getSelect() == null) { return m; } |
70 | | - |
71 | | - Stream<JavaType> TYPES = Stream.of( |
72 | | - JavaType.buildType("java.lang.StringBuilder"), |
73 | | - JavaType.buildType("java.lang.StringBuffer"), |
74 | | - JavaType.buildType("java.lang.CharSequence") |
75 | | - ); |
76 | | - |
77 | | - if (TYPES.anyMatch(type -> TypeUtils.isOfType(newArg.getType(), type))) { |
78 | | - // strip out the toString() on the argument |
79 | | - return m.withArguments(Collections.singletonList(newArg)) |
80 | | - .withName(m.getName().withSimpleName("contentEquals")); |
81 | | - } |
82 | | - } |
| 60 | + if (!EQUALS_MATCHER.matches(m)) { |
| 61 | + return m; |
83 | 62 | } |
84 | | - |
85 | | - return m; |
| 63 | + Expression equalsArgument = m.getArguments().get(0); |
| 64 | + if (!TOSTRING_MATCHER.matches(equalsArgument)) { |
| 65 | + return m; |
| 66 | + } |
| 67 | + J.MethodInvocation inv = (J.MethodInvocation) equalsArgument; |
| 68 | + Expression toStringSelect = inv.getSelect(); |
| 69 | + if (toStringSelect == null || !TypeUtils.isAssignableTo("java.lang.CharSequence", toStringSelect.getType())) { |
| 70 | + return m; |
| 71 | + } |
| 72 | + // Strip out the toString() on the argument and replace with contentEquals |
| 73 | + return m.withArguments(Collections.singletonList(toStringSelect)) |
| 74 | + .withName(m.getName().withSimpleName("contentEquals")); |
86 | 75 | } |
87 | 76 | } |
88 | 77 | } |
0 commit comments