Skip to content

Commit 7cf2266

Browse files
authored
Merge branch 'main' into lombok/normalize-setter
2 parents 4ec2411 + ccd18d3 commit 7cf2266

File tree

4 files changed

+812
-2
lines changed

4 files changed

+812
-2
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.migrate.lombok;
17+
18+
import lombok.EqualsAndHashCode;
19+
import lombok.Value;
20+
import org.jspecify.annotations.Nullable;
21+
import org.openrewrite.ExecutionContext;
22+
import org.openrewrite.ScanningRecipe;
23+
import org.openrewrite.Tree;
24+
import org.openrewrite.TreeVisitor;
25+
import org.openrewrite.java.ChangeMethodName;
26+
import org.openrewrite.java.JavaIsoVisitor;
27+
import org.openrewrite.java.MethodMatcher;
28+
import org.openrewrite.java.tree.Expression;
29+
import org.openrewrite.java.tree.J;
30+
import org.openrewrite.java.tree.JavaType;
31+
import org.openrewrite.java.tree.TypeUtils;
32+
33+
import java.util.ArrayList;
34+
import java.util.List;
35+
import java.util.Set;
36+
37+
@Value
38+
@EqualsAndHashCode(callSuper = false)
39+
public class AdoptLombokGetterMethodNames extends ScanningRecipe<List<AdoptLombokGetterMethodNames.RenameRecord>> {
40+
41+
private final static String DO_NOT_RENAME = "DO_NOT_RENAME";
42+
43+
@Override
44+
public String getDisplayName() {
45+
return "Rename getter methods to fit Lombok";
46+
}
47+
48+
@Override
49+
public String getDescription() {
50+
return "Rename methods that are effectively getter to the name Lombok would give them.\n\n" +
51+
"Limitations:\n" +
52+
" - If two methods in a class are effectively the same getter then one's name will be corrected and the others name will be left as it is.\n" +
53+
" - If the correct name for a method is already taken by another method then the name will not be corrected.\n" +
54+
" - Method name swaps or circular renaming within a class cannot be performed because the names block each other.\n" +
55+
"E.g. `int getFoo() { return ba; } int getBa() { return foo; }` stays as it is.";
56+
}
57+
58+
@Value
59+
public static class RenameRecord {
60+
String methodPattern;
61+
String newMethodName;
62+
}
63+
64+
@Override
65+
public List<RenameRecord> getInitialValue(ExecutionContext ctx) {
66+
return new ArrayList<>();
67+
}
68+
69+
@Override
70+
public TreeVisitor<?, ExecutionContext> getScanner(List<RenameRecord> renameRecords) {
71+
return new JavaIsoVisitor<ExecutionContext>() {
72+
@Override
73+
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
74+
// Cheaply collect all declared methods; this also means we do not support clashing nested class methods
75+
Set<JavaType.Method> declaredMethods = cu.getTypesInUse().getDeclaredMethods();
76+
List<String> existingMethodNames = new ArrayList<>();
77+
for (JavaType.Method method : declaredMethods) {
78+
existingMethodNames.add(method.getName());
79+
}
80+
getCursor().putMessage(DO_NOT_RENAME, existingMethodNames);
81+
return super.visitCompilationUnit(cu, ctx);
82+
}
83+
84+
@Override
85+
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
86+
if (method.getMethodType() == null || method.getBody() == null ||
87+
!LombokUtils.isEffectivelyGetter(method) ||
88+
TypeUtils.isOverride(method.getMethodType())) {
89+
return method;
90+
}
91+
92+
String simpleName;
93+
Expression returnExpression = ((J.Return) method.getBody().getStatements().get(0)).getExpression();
94+
if (returnExpression instanceof J.Identifier) {
95+
simpleName = ((J.Identifier) returnExpression).getSimpleName();
96+
} else if (returnExpression instanceof J.FieldAccess) {
97+
simpleName = ((J.FieldAccess) returnExpression).getSimpleName();
98+
} else {
99+
return method;
100+
}
101+
102+
// If method already has the name it should have, then nothing to be done
103+
String expectedMethodName = LombokUtils.deriveGetterMethodName(returnExpression.getType(), simpleName);
104+
if (expectedMethodName.equals(method.getSimpleName())) {
105+
return method;
106+
}
107+
108+
// If the desired method name is already taken by an existing method, the current method cannot be renamed
109+
List<String> doNotRename = getCursor().getNearestMessage(DO_NOT_RENAME);
110+
assert doNotRename != null;
111+
if (doNotRename.contains(expectedMethodName)) {
112+
return method;
113+
}
114+
115+
renameRecords.add(new RenameRecord(MethodMatcher.methodPattern(method), expectedMethodName));
116+
doNotRename.remove(method.getSimpleName()); //actual method name becomes available again
117+
doNotRename.add(expectedMethodName); //expected method name now blocked
118+
return method;
119+
}
120+
};
121+
}
122+
123+
@Override
124+
public TreeVisitor<?, ExecutionContext> getVisitor(List<RenameRecord> renameRecords) {
125+
return new TreeVisitor<Tree, ExecutionContext>() {
126+
@Override
127+
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
128+
for (RenameRecord rr : renameRecords) {
129+
tree = new ChangeMethodName(rr.methodPattern, rr.newMethodName, true, null)
130+
.getVisitor().visit(tree, ctx);
131+
}
132+
return tree;
133+
}
134+
};
135+
}
136+
}

src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,25 @@ private static boolean hasMatchingTypeAndGetterName(J.MethodDeclaration method,
8787
return false;
8888
}
8989

90-
private static String deriveGetterMethodName(@Nullable JavaType type, String fieldName) {
90+
public static boolean isEffectivelyGetter(J.MethodDeclaration method) {
91+
if (!method.getParameters().isEmpty() && !(method.getParameters().get(0) instanceof J.Empty)) {
92+
return false;
93+
}
94+
if (method.getBody() == null ||
95+
method.getBody().getStatements().size() != 1 ||
96+
!(method.getBody().getStatements().get(0) instanceof J.Return)) {
97+
return false;
98+
}
99+
Expression returnExpression = ((J.Return) method.getBody().getStatements().get(0)).getExpression();
100+
if (!(returnExpression instanceof J.Identifier) && !(returnExpression instanceof J.FieldAccess)) {
101+
return false;
102+
}
103+
// compiler already guarantees that the returned variable is a subtype of the method type, but we want an exact match
104+
return method.getType() == returnExpression.getType();
105+
}
106+
107+
public static String deriveGetterMethodName(@Nullable JavaType type, String fieldName) {
108+
91109
if (type == JavaType.Primitive.Boolean) {
92110
boolean alreadyStartsWithIs = fieldName.length() >= 3 &&
93111
fieldName.substring(0, 3).matches("is[A-Z]");

src/main/resources/sdkman-java.csv

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@
1313
11.0.26-zulu
1414
11.0.26.fx-librca
1515
11.0.26.fx-zulu
16+
11.0.27-amzn
17+
11.0.27-librca
18+
11.0.27-sapmchn
1619
11.0.27-sem
20+
11.0.27-tem
21+
11.0.27-zulu
22+
11.0.27.fx-librca
23+
11.0.27.fx-zulu
1724
17.0.12-graal
1825
17.0.12-oracle
1926
17.0.13-albba
@@ -33,7 +40,14 @@
3340
17.0.14.crac-zulu
3441
17.0.14.fx-librca
3542
17.0.14.fx-zulu
43+
17.0.15-amzn
44+
17.0.15-librca
45+
17.0.15-sapmchn
3646
17.0.15-sem
47+
17.0.15-tem
48+
17.0.15-zulu
49+
17.0.15.fx-librca
50+
17.0.15.fx-zulu
3751
17.0.9-graalce
3852
21.0.2-graalce
3953
21.0.2-open
@@ -54,7 +68,16 @@
5468
21.0.6.crac-zulu
5569
21.0.6.fx-librca
5670
21.0.6.fx-zulu
71+
21.0.7-amzn
72+
21.0.7-graal
73+
21.0.7-librca
74+
21.0.7-oracle
75+
21.0.7-sapmchn
5776
21.0.7-sem
77+
21.0.7-tem
78+
21.0.7-zulu
79+
21.0.7.fx-librca
80+
21.0.7.fx-zulu
5881
22.0.2-oracle
5982
22.1.0.1.r11-gln
6083
22.1.0.1.r17-gln
@@ -88,6 +111,16 @@
88111
24-sapmchn
89112
24-tem
90113
24-zulu
114+
24.0.1-amzn
115+
24.0.1-graal
116+
24.0.1-graalce
117+
24.0.1-librca
118+
24.0.1-oracle
119+
24.0.1-sapmchn
120+
24.0.1-tem
121+
24.0.1-zulu
122+
24.0.1.fx-librca
123+
24.0.1.fx-zulu
91124
24.0.2.r22-mandrel
92125
24.1.2.r23-mandrel
93126
24.1.2.r23-nik
@@ -105,6 +138,7 @@
105138
25.ea.15-open
106139
25.ea.16-graal
107140
25.ea.16-open
141+
25.ea.17-graal
108142
25.ea.8-graal
109143
6.0.119-zulu
110144
7.0.352-zulu
@@ -120,4 +154,10 @@
120154
8.0.442-zulu
121155
8.0.442.fx-librca
122156
8.0.442.fx-zulu
123-
8.0.452-sem
157+
8.0.452-amzn
158+
8.0.452-librca
159+
8.0.452-sem
160+
8.0.452-tem
161+
8.0.452-zulu
162+
8.0.452.fx-librca
163+
8.0.452.fx-zulu

0 commit comments

Comments
 (0)