Skip to content

Commit

Permalink
ReplaceDuplicateStringLiterals: More tweaks
Browse files Browse the repository at this point in the history
Should slightly improve performance and readability.
  • Loading branch information
knutwannheden committed Jul 12, 2024
1 parent b82b177 commit 7686b53
Showing 1 changed file with 26 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,12 @@
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.*;
import org.openrewrite.marker.Markers;

import java.time.Duration;
import java.util.*;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.openrewrite.Tree.randomId;

@Value
Expand Down Expand Up @@ -84,6 +82,7 @@ public J visit(@Nullable Tree tree, ExecutionContext ctx) {
return super.visit(tree, ctx);
}

@SuppressWarnings("UnusedAssignment")
@Override
public J visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
if (classDecl.getType() == null) {
Expand Down Expand Up @@ -118,75 +117,24 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ct
continue;
}
J.Literal replaceLiteral = duplicateLiterals.get(0).withId(randomId());
String insertStatement = "private static final String " + variableName + " = #{any(String)};";
JavaTemplate template = JavaTemplate.builder("private static final String " + variableName + " = #{any(String)};").build();
if (classDecl.getKind() == J.ClassDeclaration.Kind.Type.Enum) {
J.EnumValueSet enumValueSet = classDecl.getBody().getStatements().stream()
.filter(J.EnumValueSet.class::isInstance)
.map(J.EnumValueSet.class::cast)
.findFirst()
.orElse(null);

if (enumValueSet != null) {
// "Temporary" work around due to an issue in the JavaTemplate related to BlockStatementTemplateGenerator#enumClassDeclaration.
Space singleSpace = Space.build(" ", emptyList());
Expression literal = duplicateLiterals.get(0).withId(randomId());
J.Modifier privateModifier = new J.Modifier(randomId(), Space.build("\n", emptyList()), Markers.EMPTY, null, J.Modifier.Type.Private, emptyList());
J.Modifier staticModifier = new J.Modifier(randomId(), singleSpace, Markers.EMPTY, null, J.Modifier.Type.Static, emptyList());
J.Modifier finalModifier = new J.Modifier(randomId(), singleSpace, Markers.EMPTY, null, J.Modifier.Type.Final, emptyList());
J.VariableDeclarations variableDeclarations = autoFormat(new J.VariableDeclarations(
randomId(),
Space.EMPTY,
Markers.EMPTY,
emptyList(),
Arrays.asList(privateModifier, staticModifier, finalModifier),
new J.Identifier(
randomId(),
singleSpace,
Markers.EMPTY,
emptyList(),
"String",
JavaType.ShallowClass.build("java.lang.String"),
null),
null,
emptyList(),
singletonList(JRightPadded.build(new J.VariableDeclarations.NamedVariable(
randomId(),
Space.EMPTY,
Markers.EMPTY,
new J.Identifier(
randomId(),
Space.EMPTY,
Markers.EMPTY,
emptyList(),
variableName,
JavaType.ShallowClass.build("java.lang.String"),
null),
emptyList(),
JLeftPadded.build(literal).withBefore(singleSpace),
null)))
), ctx, new Cursor(getCursor(), classDecl.getBody()));

// Insert the new statement after the EnumValueSet.
List<Statement> statements = new ArrayList<>(classDecl.getBody().getStatements().size() + 1);
boolean addedNewStatement = false;
for (Statement statement : classDecl.getBody().getStatements()) {
if (!(statement instanceof J.EnumValueSet) && !addedNewStatement) {
statements.add(variableDeclarations);
addedNewStatement = true;
}
statements.add(statement);
}
classDecl = classDecl.withBody(classDecl.getBody().withStatements(statements));
}
J.Block applied = template
.apply(new Cursor(getCursor(), classDecl.getBody()), classDecl.getBody().getCoordinates().lastStatement(), replaceLiteral);
List<Statement> statements = applied.getStatements();
statements.add(1, statements.remove(statements.size() - 1));
classDecl = classDecl.withBody(applied.withStatements(statements));
} else {
classDecl = classDecl.withBody(
JavaTemplate.builder(insertStatement).build()
template
.apply(new Cursor(getCursor(), classDecl.getBody()), classDecl.getBody().getCoordinates().firstStatement(), replaceLiteral));
}
}
variableNames.add(variableName);
entry.getValue().forEach(v -> replacements.put(v, variableName));
}
duplicateLiteralInfo = null;
duplicateLiteralsMap = null;
return replacements.isEmpty() ? classDecl :
new ReplaceStringLiterals(classDecl, replacements).visitNonNull(classDecl, ctx, getCursor().getParent());
}
Expand Down Expand Up @@ -218,19 +166,18 @@ private String transformToVariableName(String valueOfLiteral) {
StringBuilder newName = new StringBuilder();
for (int i = 0; i < valueOfLiteral.length(); i++) {
char c = valueOfLiteral.charAt(i);
if (i > 0 && newName.lastIndexOf("_") != newName.length() - 1 &&
(Character.isUpperCase(c) && prevIsLower || !prevIsCharacter)) {
newName.append("_");
if (i > 0 && (Character.isUpperCase(c) && prevIsLower || !prevIsCharacter) &&
newName.length() > 0 && newName.charAt(newName.length() - 1) != '_') {
newName.append('_');
}
prevIsCharacter = Character.isLetterOrDigit(c);
if (!prevIsCharacter) {
continue;
}
if (newName.length() == 0 && Character.isDigit(c)) {
newName.append("A_");
if (prevIsCharacter) {
if (newName.length() == 0 && Character.isDigit(c)) {
newName.append("A_");
}
newName.append(Character.toUpperCase(c));
prevIsLower = Character.isLowerCase(c);
}
newName.append(Character.toUpperCase(c));
prevIsLower = Character.isLowerCase(c);
}
return VariableNameUtils.normalizeName(newName.toString());
}
Expand Down Expand Up @@ -265,17 +212,17 @@ public J.Annotation visitAnnotation(J.Annotation annotation, Integer integer) {
public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, Integer integer) {
J.VariableDeclarations.NamedVariable v = super.visitVariable(variable, integer);
Cursor parentScope = getCursor().dropParentUntil(is -> is instanceof J.ClassDeclaration || is instanceof J.MethodDeclaration);
J.VariableDeclarations declaration = getCursor().firstEnclosing(J.VariableDeclarations.class);
J.VariableDeclarations declaration = getCursor().firstEnclosingOrThrow(J.VariableDeclarations.class);
boolean privateStaticFinalVariable = isPrivateStaticFinalVariable(declaration);
// `private static final String`(s) are handled separately by `FindExistingPrivateStaticFinalFields`.
if (parentScope.getValue() instanceof J.MethodDeclaration ||
(parentScope.getValue() instanceof J.ClassDeclaration && declaration != null &&
// `private static final String`(s) are handled separately by `FindExistingPrivateStaticFinalFields`.
!(isPrivateStaticFinalVariable(declaration) && v.getInitializer() instanceof J.Literal &&
((J.Literal) v.getInitializer()).getValue() instanceof String))) {
parentScope.getValue() instanceof J.ClassDeclaration &&
!(privateStaticFinalVariable && v.getInitializer() instanceof J.Literal &&
((J.Literal) v.getInitializer()).getValue() instanceof String)) {
result.variableNames.add(v.getSimpleName());
}
if (parentScope.getValue() instanceof J.ClassDeclaration &&
declaration != null && isPrivateStaticFinalVariable(declaration) &&
v.getInitializer() instanceof J.Literal &&
privateStaticFinalVariable && v.getInitializer() instanceof J.Literal &&
((J.Literal) v.getInitializer()).getValue() instanceof String) {
String value = (String) (((J.Literal) v.getInitializer()).getValue());
result.fieldValueToFieldName.putIfAbsent(value, v.getSimpleName());
Expand Down

0 comments on commit 7686b53

Please sign in to comment.