Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AddOrUpdateAnnotationAttribute unable to handle FieldAccess #4898

Merged
merged 7 commits into from
Jan 16, 2025
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,47 @@ public class A {
);
}

@Test
void updateFieldAccessAttribute() {
rewriteRun(
MBoegers marked this conversation as resolved.
Show resolved Hide resolved
spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", "value", "hello", false, null)),
java(
"""
package org.example;

public class Const {
public static final String HI = "hi";
}
"""),
java(
"""
package org.example;
public @interface Foo {
String value() default "";
}
"""
),
java(
"""
import org.example.Foo;
import org.example.Const;

@Foo(value = Const.HI)
public class A {
}
""",
"""
import org.example.Foo;
import org.example.Const;

@Foo(value = "hello")
public class A {
}
"""
)
);
}

@Test
void addAttributeToNestedAnnotationArray() {
rewriteRun(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public String getDisplayName() {
@Override
public String getDescription() {
return "Some annotations accept arguments. This recipe sets an existing argument to the specified value, " +
"or adds the argument if it is not already set.";
"or adds the argument if it is not already set.";
SiBorea marked this conversation as resolved.
Show resolved Hide resolved
}

@Option(displayName = "Annotation type",
Expand Down Expand Up @@ -74,9 +74,9 @@ public String getDescription() {

@Option(displayName = "Append array",
description = "If the attribute is an array, setting this option to `true` will append the value(s). " +
"In conjunction with `addOnly`, it is possible to control duplicates: " +
"`addOnly=true`, always append. " +
"`addOnly=false`, only append if the value is not already present.")
"In conjunction with `addOnly`, it is possible to control duplicates: " +
"`addOnly=true`, always append. " +
"`addOnly=false`, only append if the value is not already present.")
@Nullable
Boolean appendArray;

Expand Down Expand Up @@ -105,7 +105,7 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) {
} else {
String newAttributeValueResult = newAttributeValue;
if (((JavaType.FullyQualified) Objects.requireNonNull(a.getAnnotationType().getType())).getMethods().stream().anyMatch(method -> method.getReturnType().toString().equals("java.lang.String[]"))) {
String attributeValueCleanedUp = attributeValue.replaceAll("\\s+","").replaceAll("[\\s+{}\"]","");
String attributeValueCleanedUp = attributeValue.replaceAll("\\s+", "").replaceAll("[\\s+{}\"]", "");
List<String> attributeList = Arrays.asList(attributeValueCleanedUp.contains(",") ? attributeValueCleanedUp.split(",") : new String[]{attributeValueCleanedUp});
newAttributeValueResult = attributeList.stream()
.map(String::valueOf)
Expand Down Expand Up @@ -135,7 +135,7 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) {

if (as.getAssignment() instanceof J.NewArray) {
List<Expression> jLiteralList = ((J.NewArray) as.getAssignment()).getInitializer();
String attributeValueCleanedUp = attributeValue.replaceAll("\\s+","").replaceAll("[\\s+{}\"]","");
String attributeValueCleanedUp = attributeValue.replaceAll("\\s+", "").replaceAll("[\\s+{}\"]", "");
List<String> attributeList = Arrays.asList(attributeValueCleanedUp.contains(",") ? attributeValueCleanedUp.split(",") : new String[]{attributeValueCleanedUp});

if (as.getMarkers().findFirst(AlreadyAppended.class).filter(ap -> ap.getValues().equals(newAttributeValue)).isPresent()) {
Expand All @@ -156,16 +156,16 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) {
.withMarkers(as.getMarkers().add(new AlreadyAppended(randomId(), newAttributeValue))) : as;
}
int m = 0;
for (int i = 0; i< Objects.requireNonNull(jLiteralList).size(); i++){
if (i >= attributeList.size()){
for (int i = 0; i < Objects.requireNonNull(jLiteralList).size(); i++) {
if (i >= attributeList.size()) {
jLiteralList.remove(i);
i--;
continue;
}

String newAttributeListValue = maybeQuoteStringArgument(attributeName, attributeList.get(i), finalA);
if (jLiteralList.size() == i+1){
m = i+1;
if (jLiteralList.size() == i + 1) {
m = i + 1;
}

if (newAttributeListValue != null && newAttributeListValue.equals(((J.Literal) jLiteralList.get(i)).getValueSource()) || Boolean.TRUE.equals(addOnly)) {
Expand All @@ -174,23 +174,34 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) {

jLiteralList.set(i, ((J.Literal) jLiteralList.get(i)).withValue(newAttributeListValue).withValueSource(newAttributeListValue).withPrefix(jLiteralList.get(i).getPrefix()));
}
if (jLiteralList.size() < attributeList.size() || Boolean.TRUE.equals(addOnly)){
if (Boolean.TRUE.equals(addOnly)){
if (jLiteralList.size() < attributeList.size() || Boolean.TRUE.equals(addOnly)) {
if (Boolean.TRUE.equals(addOnly)) {
m = 0;
}
for (int j = m; j < attributeList.size(); j++){
for (int j = m; j < attributeList.size(); j++) {
String newAttributeListValue = maybeQuoteStringArgument(attributeName, attributeList.get(j), finalA);
jLiteralList.add(j, new J.Literal(randomId(), jLiteralList.get(j - 1).getPrefix(), Markers.EMPTY, newAttributeListValue, newAttributeListValue, null, JavaType.Primitive.String));
}
}

return as.withAssignment(((J.NewArray) as.getAssignment()).withInitializer(jLiteralList));
} else {
J.Literal value = (J.Literal) as.getAssignment();
if (newAttributeValue.equals(value.getValueSource()) || Boolean.TRUE.equals(addOnly)) {
return it;
Expression exp = as.getAssignment();
if (exp instanceof J.Literal) {
J.Literal value = (J.Literal) exp;
if (newAttributeValue.equals(value.getValueSource()) || Boolean.TRUE.equals(addOnly)) {
return it;
}
return as.withAssignment(value.withValue(newAttributeValue).withValueSource(newAttributeValue));
} else if (exp instanceof J.FieldAccess) {
if (Boolean.TRUE.equals(addOnly)) {
return it;
}
as = JavaTemplate.builder("#{} = #{}")
SiBorea marked this conversation as resolved.
Show resolved Hide resolved
.build()
.apply(new Cursor(getCursor(), as), as.getCoordinates().replace(), var.getSimpleName(), newAttributeValue);
return as;
}
return as.withAssignment(value.withValue(newAttributeValue).withValueSource(newAttributeValue));
}
} else if (it instanceof J.Literal) {
// The only way anything except an assignment can appear is if there's an implicit assignment to "value"
Expand Down
Loading