Skip to content

Commit fd8e2bf

Browse files
Walk JavaType refs embedded in annotation element values (#7426)
JavaTypeVisitor.visitAnnotation only visited annotation.getType(), leaving any JavaType refs in element values untouched: the element meta-variable, SingleElementValue.referenceValue, SingleElementValue.constantValue (when it's a JavaType), and ArrayElementValue's referenceValues / JavaType-valued constantValues. Downstream visitors that rely on the full-graph walk (dedup, type remappers, serializers) silently see non-canonical instances inside annotation values while the rest of the type graph is consistent. Adds visitAnnotationElementValue, which visits every ref kind and reconstructs the ElementValue only when a returned instance differs. UnsafeJavaTypeVisitor inherits this via the default visitAnnotation.
1 parent a6a8b25 commit fd8e2bf

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

rewrite-benchmarks/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dependencies {
1515
jmh(project(":rewrite-core"))
1616
jmh(project(":rewrite-java"))
1717
jmh(project(":rewrite-java-21"))
18+
jmh(project(":rewrite-javascript"))
1819
jmh(project(":rewrite-maven"))
1920
jmh("org.antlr:antlr4-runtime:4.13.2")
2021
jmh("org.rocksdb:rocksdbjni:10.2.1")

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,57 @@ public JavaType visitMultiCatch(JavaType.MultiCatch multiCatch, P p) {
114114
public JavaType visitAnnotation(JavaType.Annotation annotation, P p) {
115115
return annotation.unsafeSet(
116116
(JavaType.FullyQualified) visit(annotation.getType(), p),
117-
arrayOrNullIfEmpty(annotation.getValues(), JavaType.EMPTY_ANNOTATION_VALUE_ARRAY)
117+
arrayOrNullIfEmpty(
118+
ListUtils.map(annotation.getValues(), ev -> visitAnnotationElementValue(ev, p)),
119+
JavaType.EMPTY_ANNOTATION_VALUE_ARRAY)
118120
);
119121
}
120122

123+
/**
124+
* Visit the JavaType refs embedded in an annotation element value — the
125+
* {@code element} meta-variable and any {@code referenceValue}(s). Constant
126+
* values never hold {@link JavaType} instances in practice: Single- and
127+
* ArrayElementValue#from route JavaType-valued arguments into the reference
128+
* branch, so the constant side is only ever primitives, strings, and enums.
129+
* The default implementation returns the same ElementValue when no
130+
* referenced JavaType changed identity, matching the semantics of the other
131+
* {@code visit*} methods on this visitor.
132+
*/
133+
public JavaType.Annotation.ElementValue visitAnnotationElementValue(JavaType.Annotation.ElementValue ev, P p) {
134+
JavaType element = visit(ev.getElement(), p);
135+
if (ev instanceof JavaType.Annotation.SingleElementValue) {
136+
JavaType.Annotation.SingleElementValue sev = (JavaType.Annotation.SingleElementValue) ev;
137+
JavaType referenceValue = sev.getReferenceValue();
138+
if (referenceValue != null) {
139+
JavaType visited = visit(referenceValue, p);
140+
if (visited == referenceValue && element == sev.getElement()) return sev;
141+
return new JavaType.Annotation.SingleElementValue(element, null, visited);
142+
}
143+
if (element == sev.getElement()) return sev;
144+
return new JavaType.Annotation.SingleElementValue(element, sev.getConstantValue(), null);
145+
}
146+
if (ev instanceof JavaType.Annotation.ArrayElementValue) {
147+
JavaType.Annotation.ArrayElementValue aev = (JavaType.Annotation.ArrayElementValue) ev;
148+
JavaType[] referenceValues = aev.getReferenceValues();
149+
if (referenceValues != null) {
150+
JavaType[] visited = null;
151+
for (int i = 0; i < referenceValues.length; i++) {
152+
JavaType v = visit(referenceValues[i], p);
153+
if (v != referenceValues[i]) {
154+
if (visited == null) visited = referenceValues.clone();
155+
visited[i] = v;
156+
}
157+
}
158+
if (visited == null && element == aev.getElement()) return aev;
159+
return new JavaType.Annotation.ArrayElementValue(element, null,
160+
visited != null ? visited : referenceValues);
161+
}
162+
if (element == aev.getElement()) return aev;
163+
return new JavaType.Annotation.ArrayElementValue(element, aev.getConstantValues(), null);
164+
}
165+
return ev;
166+
}
167+
121168
public JavaType visitArray(JavaType.Array array, P p) {
122169
return array.unsafeSet(
123170
visit(array.getElemType(), p),

0 commit comments

Comments
 (0)