Skip to content

Commit a6a2a62

Browse files
committed
Rename _ identifier to __ for Java ≤ 8 source files
In Java 9+, `_` became a reserved keyword causing compile errors. This recipe renames single-underscore identifiers to double-underscore as a prerequisite migration step for projects upgrading from Java 8. Closes moderneinc/customer-requests#2221
1 parent 634e7d9 commit a6a2a62

3 files changed

Lines changed: 479 additions & 0 deletions

File tree

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
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.lang;
17+
18+
import lombok.EqualsAndHashCode;
19+
import lombok.Value;
20+
import org.openrewrite.ExecutionContext;
21+
import org.openrewrite.Preconditions;
22+
import org.openrewrite.Recipe;
23+
import org.openrewrite.TreeVisitor;
24+
import org.openrewrite.java.JavaIsoVisitor;
25+
import org.openrewrite.java.RenameVariable;
26+
import org.openrewrite.java.search.UsesJavaVersion;
27+
import org.openrewrite.java.tree.J;
28+
import org.openrewrite.java.tree.JavaType;
29+
30+
@EqualsAndHashCode(callSuper = false)
31+
@Value
32+
public class RenameUnderscoreIdentifier extends Recipe {
33+
34+
private static final String UNDERSCORE = "_";
35+
private static final String DOUBLE_UNDERSCORE = "__";
36+
37+
String displayName = "Rename `_` identifier to `__`";
38+
39+
String description = "Renames single-underscore identifiers to double-underscore " +
40+
"in Java source files with source compatibility of Java 8 or below. " +
41+
"In Java 9+, `_` is a reserved keyword and causes a compile error.";
42+
43+
@Override
44+
public TreeVisitor<?, ExecutionContext> getVisitor() {
45+
return Preconditions.check(
46+
new UsesJavaVersion<>(1, 8),
47+
new JavaIsoVisitor<ExecutionContext>() {
48+
49+
@Override
50+
public J.VariableDeclarations visitVariableDeclarations(
51+
J.VariableDeclarations multiVariable, ExecutionContext ctx) {
52+
for (J.VariableDeclarations.NamedVariable v : multiVariable.getVariables()) {
53+
if (UNDERSCORE.equals(v.getSimpleName())) {
54+
doAfterVisit(new RenameVariable<>(v, DOUBLE_UNDERSCORE));
55+
}
56+
}
57+
return super.visitVariableDeclarations(multiVariable, ctx);
58+
}
59+
60+
@Override
61+
public J.MethodDeclaration visitMethodDeclaration(
62+
J.MethodDeclaration method, ExecutionContext ctx) {
63+
method = super.visitMethodDeclaration(method, ctx);
64+
if (UNDERSCORE.equals(method.getSimpleName())) {
65+
JavaType.Method type = method.getMethodType();
66+
if (type != null) {
67+
type = type.withName(DOUBLE_UNDERSCORE);
68+
}
69+
method = method.withName(method.getName().withSimpleName(DOUBLE_UNDERSCORE)
70+
.withType(type))
71+
.withMethodType(type);
72+
}
73+
return method;
74+
}
75+
76+
@Override
77+
public J.MethodInvocation visitMethodInvocation(
78+
J.MethodInvocation method, ExecutionContext ctx) {
79+
method = super.visitMethodInvocation(method, ctx);
80+
if (UNDERSCORE.equals(method.getSimpleName())) {
81+
JavaType.Method type = method.getMethodType();
82+
if (type != null) {
83+
type = type.withName(DOUBLE_UNDERSCORE);
84+
}
85+
method = method.withName(method.getName().withSimpleName(DOUBLE_UNDERSCORE)
86+
.withType(type))
87+
.withMethodType(type);
88+
}
89+
return method;
90+
}
91+
92+
@Override
93+
public J.MemberReference visitMemberReference(
94+
J.MemberReference memberRef, ExecutionContext ctx) {
95+
memberRef = super.visitMemberReference(memberRef, ctx);
96+
if (UNDERSCORE.equals(memberRef.getReference().getSimpleName())) {
97+
JavaType.Method type = memberRef.getMethodType();
98+
if (type != null) {
99+
type = type.withName(DOUBLE_UNDERSCORE);
100+
}
101+
memberRef = memberRef.withReference(memberRef.getReference().withSimpleName(DOUBLE_UNDERSCORE))
102+
.withMethodType(type);
103+
}
104+
return memberRef;
105+
}
106+
107+
@Override
108+
public J.ClassDeclaration visitClassDeclaration(
109+
J.ClassDeclaration classDecl, ExecutionContext ctx) {
110+
classDecl = super.visitClassDeclaration(classDecl, ctx);
111+
if (UNDERSCORE.equals(classDecl.getSimpleName())) {
112+
classDecl = classDecl.withName(classDecl.getName().withSimpleName(DOUBLE_UNDERSCORE));
113+
}
114+
return classDecl;
115+
}
116+
}
117+
);
118+
}
119+
}

src/main/resources/META-INF/rewrite/java-version-11.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ preconditions:
3434
- org.openrewrite.Singleton
3535
recipeList:
3636
- org.openrewrite.java.migrate.UpgradeToJava8
37+
- org.openrewrite.java.migrate.lang.RenameUnderscoreIdentifier
3738
- org.openrewrite.java.migrate.UseJavaUtilBase64
3839
- org.openrewrite.java.migrate.CastArraysAsListToList
3940
# Add an explicit JAXB/JAX-WS runtime and upgrade the dependencies to Jakarta EE 8

0 commit comments

Comments
 (0)