Skip to content

Commit 071fb76

Browse files
Rename variables if the name matches class name
1 parent 19ca58c commit 071fb76

File tree

3 files changed

+70
-14
lines changed

3 files changed

+70
-14
lines changed

rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,4 +732,14 @@ public static boolean containsWhitespace(String s) {
732732

733733
return false;
734734
}
735+
736+
/**
737+
* @return string with first character changed to lowercase (or empty string)
738+
*/
739+
public static String decapitalize(@Nullable String string) {
740+
if (string != null && !string.isEmpty()) {
741+
return Character.toLowerCase(string.charAt(0)) + string.substring(1);
742+
}
743+
return "";
744+
}
735745
}

rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,8 +1592,8 @@ public A1 method(A1 a1) {
15921592
import a.A2;
15931593
15941594
public class Example {
1595-
public A2 method(A2 a1) {
1596-
return a1;
1595+
public A2 method(A2 a2) {
1596+
return a2;
15971597
}
15981598
}
15991599
"""

rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,44 @@
1818
import lombok.EqualsAndHashCode;
1919
import lombok.Value;
2020
import org.jspecify.annotations.Nullable;
21-
import org.openrewrite.*;
21+
import org.openrewrite.Cursor;
22+
import org.openrewrite.ExecutionContext;
23+
import org.openrewrite.Option;
24+
import org.openrewrite.Preconditions;
25+
import org.openrewrite.Recipe;
26+
import org.openrewrite.SourceFile;
27+
import org.openrewrite.SourceFileWithReferences;
28+
import org.openrewrite.Tree;
29+
import org.openrewrite.TreeVisitor;
2230
import org.openrewrite.internal.ListUtils;
31+
import org.openrewrite.internal.StringUtils;
2332
import org.openrewrite.java.search.UsesType;
24-
import org.openrewrite.java.tree.*;
33+
import org.openrewrite.java.tree.Expression;
34+
import org.openrewrite.java.tree.Flag;
35+
import org.openrewrite.java.tree.J;
36+
import org.openrewrite.java.tree.JavaSourceFile;
37+
import org.openrewrite.java.tree.JavaType;
38+
import org.openrewrite.java.tree.Space;
39+
import org.openrewrite.java.tree.TypeTree;
40+
import org.openrewrite.java.tree.TypeUtils;
41+
import org.openrewrite.java.tree.TypedTree;
2542
import org.openrewrite.marker.Markers;
2643
import org.openrewrite.marker.SearchResult;
2744
import org.openrewrite.trait.Reference;
2845

2946
import java.nio.file.Path;
3047
import java.nio.file.Paths;
31-
import java.util.*;
48+
import java.util.HashMap;
49+
import java.util.HashSet;
50+
import java.util.IdentityHashMap;
51+
import java.util.Map;
52+
import java.util.Optional;
53+
import java.util.Set;
54+
import java.util.Stack;
3255
import java.util.concurrent.atomic.AtomicBoolean;
3356

3457
import static java.util.Objects.requireNonNull;
58+
import static org.openrewrite.internal.StringUtils.decapitalize;
3559

3660
@Value
3761
@EqualsAndHashCode(callSuper = false)
@@ -49,7 +73,7 @@ public class ChangeType extends Recipe {
4973

5074
@Option(displayName = "Ignore type definition",
5175
description = "When set to `true` the definition of the old type will be left untouched. " +
52-
"This is useful when you're replacing usage of a class but don't want to rename it.",
76+
"This is useful when you're replacing usage of a class but don't want to rename it.",
5377
required = false)
5478
@Nullable
5579
Boolean ignoreDefinition;
@@ -337,7 +361,7 @@ public J visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContext ctx) {
337361
public J visitIdentifier(J.Identifier ident, ExecutionContext ctx) {
338362
// Do not modify the identifier if it's on a inner class definition.
339363
if (Boolean.TRUE.equals(ignoreDefinition) && getCursor().getParent() != null &&
340-
getCursor().getParent().getValue() instanceof J.ClassDeclaration) {
364+
getCursor().getParent().getValue() instanceof J.ClassDeclaration) {
341365
return super.visitIdentifier(ident, ctx);
342366
}
343367
// if the ident's type is equal to the type we're looking for, and the classname of the type we're looking for is equal to the ident's string representation
@@ -368,13 +392,26 @@ public J visitIdentifier(J.Identifier ident, ExecutionContext ctx) {
368392
}
369393
}
370394

395+
// Rename variable if it matches class name (starting with a lowercase character)
396+
if (ident.getSimpleName().equals(decapitalize(className))) {
397+
if (targetType instanceof JavaType.FullyQualified) {
398+
String newName = decapitalize(((JavaType.FullyQualified) targetType).getClassName());
399+
400+
ident = ident.withSimpleName(newName);
401+
402+
if (ident.getFieldType() != null) {
403+
ident = ident.withFieldType(ident.getFieldType().withName(newName));
404+
}
405+
}
406+
}
407+
371408
// Recreate any static imports as needed
372409
if (sf != null) {
373410
for (J.Import anImport : sf.getImports()) {
374411
if (anImport.isStatic() && anImport.getQualid().getTarget().getType() != null) {
375412
JavaType.FullyQualified fqn = TypeUtils.asFullyQualified(anImport.getQualid().getTarget().getType());
376413
if (fqn != null && TypeUtils.isOfClassType(fqn, originalType.getFullyQualifiedName()) &&
377-
ident.getSimpleName().equals(anImport.getQualid().getSimpleName())) {
414+
ident.getSimpleName().equals(anImport.getQualid().getSimpleName())) {
378415
JavaType.FullyQualified targetFqn = (JavaType.FullyQualified) targetType;
379416
maybeAddImport((targetFqn).getFullyQualifiedName(), ident.getSimpleName());
380417
break;
@@ -387,6 +424,15 @@ public J visitIdentifier(J.Identifier ident, ExecutionContext ctx) {
387424
return visitAndCast(ident, ctx, super::visitIdentifier);
388425
}
389426

427+
@Override
428+
public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext executionContext) {
429+
J.VariableDeclarations.NamedVariable v = (J.VariableDeclarations.NamedVariable) super.visitVariable(variable, executionContext);
430+
if (v.getVariableType() != null && !v.getSimpleName().equals(v.getVariableType().getName())) {
431+
return v.withVariableType(v.getVariableType().withName(v.getSimpleName()));
432+
}
433+
return v;
434+
}
435+
390436
@Override
391437
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
392438
if (method.getMethodType() != null && method.getMethodType().hasFlags(Flag.Static)) {
@@ -397,7 +443,7 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx)
397443
if (anImport.isStatic() && anImport.getQualid().getTarget().getType() != null) {
398444
JavaType.FullyQualified fqn = TypeUtils.asFullyQualified(anImport.getQualid().getTarget().getType());
399445
if (fqn != null && TypeUtils.isOfClassType(fqn, originalType.getFullyQualifiedName()) &&
400-
method.getSimpleName().equals(anImport.getQualid().getSimpleName())) {
446+
method.getSimpleName().equals(anImport.getQualid().getSimpleName())) {
401447
JavaType.FullyQualified targetFqn = (JavaType.FullyQualified) targetType;
402448

403449
addImport(targetFqn);
@@ -567,9 +613,9 @@ private boolean hasNoConflictingImport(@Nullable JavaSourceFile sf) {
567613
for (J.Import anImport : sf.getImports()) {
568614
JavaType.FullyQualified currType = TypeUtils.asFullyQualified(anImport.getQualid().getType());
569615
if (currType != null &&
570-
!TypeUtils.isOfType(currType, oldType) &&
571-
!TypeUtils.isOfType(currType, newType) &&
572-
currType.getClassName().equals(newType.getClassName())) {
616+
!TypeUtils.isOfType(currType, oldType) &&
617+
!TypeUtils.isOfType(currType, newType) &&
618+
currType.getClassName().equals(newType.getClassName())) {
573619
return false;
574620
}
575621
}
@@ -640,8 +686,8 @@ private String fqnToPath(String fullyQualifiedName) {
640686
private boolean updatePath(JavaSourceFile sf, String oldPath, String newPath) {
641687
return !oldPath.equals(newPath) && sf.getClasses().stream()
642688
.anyMatch(o -> !o.hasModifier(J.Modifier.Type.Private) &&
643-
o.getType() != null && !o.getType().getFullyQualifiedName().contains("$") &&
644-
TypeUtils.isOfClassType(o.getType(), getTopLevelClassName(originalType).getFullyQualifiedName()));
689+
o.getType() != null && !o.getType().getFullyQualifiedName().contains("$") &&
690+
TypeUtils.isOfClassType(o.getType(), getTopLevelClassName(originalType).getFullyQualifiedName()));
645691
}
646692

647693
@Override

0 commit comments

Comments
 (0)