Skip to content

Commit de4f1d9

Browse files
Fix print idempotency for annotated array type casts (#6861)
When javac represents `(@nullable Object[])` as `JCArrayTypeTree(JCAnnotatedType(@nullable, JCIdent(Object)))`, the `arrayTypeTree` method stripped the JCAnnotatedType wrapper without collecting its annotations, causing the cursor to advance over the annotation text and produce garbled output like `(Objectble Object[])`. The fix collects annotations from inner JCAnnotatedType wrappers during the tree walk (guarded by `count > 0` to avoid double-collecting when called from `visitAnnotatedType`), consumes them as leading annotations before the element type, and wraps the result in `J.AnnotatedType` when leading annotations are present.
1 parent 8c6b95e commit de4f1d9

6 files changed

Lines changed: 89 additions & 6 deletions

File tree

rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,9 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
13341334
JCArrayTypeTree arrayTypeTree = null;
13351335
while (typeIdent instanceof JCAnnotatedType || typeIdent instanceof JCArrayTypeTree) {
13361336
if (typeIdent instanceof JCAnnotatedType) {
1337+
if (count > 0) {
1338+
mapAnnotations(((JCAnnotatedType) typeIdent).getAnnotations(), annotationPosTable);
1339+
}
13371340
typeIdent = ((JCAnnotatedType) typeIdent).getUnderlyingType();
13381341
}
13391342
if (typeIdent instanceof JCArrayTypeTree) {
@@ -1345,16 +1348,21 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
13451348
}
13461349
}
13471350

1351+
List<J.Annotation> leadingAnnotations = leadingAnnotations(annotationPosTable);
13481352
Space prefix = whitespace();
13491353
TypeTree elemType = convert(typeIdent);
13501354
List<J.Annotation> annotations = leadingAnnotations(annotationPosTable);
13511355
JLeftPadded<Space> dimension = padLeft(sourceBefore("["), sourceBefore("]"));
13521356
assert arrayTypeTree != null;
1353-
return new J.ArrayType(randomId(), prefix, Markers.EMPTY,
1357+
TypeTree result = new J.ArrayType(randomId(), prefix, Markers.EMPTY,
13541358
count == 1 ? elemType : mapDimensions(elemType, arrayTypeTree.getType(), annotationPosTable),
13551359
annotations,
13561360
dimension,
13571361
typeMapping.type(tree));
1362+
if (!leadingAnnotations.isEmpty()) {
1363+
result = new J.AnnotatedType(randomId(), EMPTY, Markers.EMPTY, leadingAnnotations, result);
1364+
}
1365+
return result;
13581366
}
13591367

13601368
private TypeTree mapDimensions(TypeTree baseType, Tree tree, Map<Integer, JCAnnotation> annotationPosTable) {

rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,9 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
14771477
JCArrayTypeTree arrayTypeTree = null;
14781478
while (typeIdent instanceof JCAnnotatedType || typeIdent instanceof JCArrayTypeTree) {
14791479
if (typeIdent instanceof JCAnnotatedType) {
1480+
if (count > 0) {
1481+
mapAnnotations(((JCAnnotatedType) typeIdent).getAnnotations(), annotationPosTable);
1482+
}
14801483
typeIdent = ((JCAnnotatedType) typeIdent).getUnderlyingType();
14811484
}
14821485
if (typeIdent instanceof JCArrayTypeTree) {
@@ -1488,16 +1491,21 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
14881491
}
14891492
}
14901493

1494+
List<J.Annotation> leadingAnnotations = leadingAnnotations(annotationPosTable);
14911495
Space prefix = whitespace();
14921496
TypeTree elemType = convert(typeIdent);
14931497
List<J.Annotation> annotations = leadingAnnotations(annotationPosTable);
14941498
JLeftPadded<Space> dimension = padLeft(sourceBefore("["), sourceBefore("]"));
14951499
assert arrayTypeTree != null;
1496-
return new J.ArrayType(randomId(), prefix, Markers.EMPTY,
1500+
TypeTree result = new J.ArrayType(randomId(), prefix, Markers.EMPTY,
14971501
count == 1 ? elemType : mapDimensions(elemType, arrayTypeTree.getType(), annotationPosTable),
14981502
annotations,
14991503
dimension,
15001504
typeMapping.type(tree));
1505+
if (!leadingAnnotations.isEmpty()) {
1506+
result = new J.AnnotatedType(randomId(), EMPTY, Markers.EMPTY, leadingAnnotations, result);
1507+
}
1508+
return result;
15011509
}
15021510

15031511
private TypeTree mapDimensions(TypeTree baseType, Tree tree, Map<Integer, JCAnnotation> annotationPosTable) {

rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,9 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
15081508
JCArrayTypeTree arrayTypeTree = null;
15091509
while (typeIdent instanceof JCAnnotatedType || typeIdent instanceof JCArrayTypeTree) {
15101510
if (typeIdent instanceof JCAnnotatedType) {
1511+
if (count > 0) {
1512+
mapAnnotations(((JCAnnotatedType) typeIdent).getAnnotations(), annotationPosTable);
1513+
}
15111514
typeIdent = ((JCAnnotatedType) typeIdent).getUnderlyingType();
15121515
}
15131516
if (typeIdent instanceof JCArrayTypeTree) {
@@ -1519,16 +1522,21 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
15191522
}
15201523
}
15211524

1525+
List<J.Annotation> leadingAnnotations = leadingAnnotations(annotationPosTable);
15221526
Space prefix = whitespace();
15231527
TypeTree elemType = convert(typeIdent);
15241528
List<J.Annotation> annotations = leadingAnnotations(annotationPosTable);
15251529
JLeftPadded<Space> dimension = padLeft(sourceBefore("["), sourceBefore("]"));
15261530
assert arrayTypeTree != null;
1527-
return new J.ArrayType(randomId(), prefix, Markers.EMPTY,
1531+
TypeTree result = new J.ArrayType(randomId(), prefix, Markers.EMPTY,
15281532
count == 1 ? elemType : mapDimensions(elemType, arrayTypeTree.getType(), annotationPosTable),
15291533
annotations,
15301534
dimension,
15311535
typeMapping.type(tree));
1536+
if (!leadingAnnotations.isEmpty()) {
1537+
result = new J.AnnotatedType(randomId(), EMPTY, Markers.EMPTY, leadingAnnotations, result);
1538+
}
1539+
return result;
15321540
}
15331541

15341542
private TypeTree mapDimensions(TypeTree baseType, Tree tree, Map<Integer, JCAnnotation> annotationPosTable) {

rewrite-java-25/src/main/java/org/openrewrite/java/isolated/ReloadableJava25ParserVisitor.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,9 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
15401540
JCArrayTypeTree arrayTypeTree = null;
15411541
while (typeIdent instanceof JCAnnotatedType || typeIdent instanceof JCArrayTypeTree) {
15421542
if (typeIdent instanceof JCAnnotatedType) {
1543+
if (count > 0) {
1544+
mapAnnotations(((JCAnnotatedType) typeIdent).getAnnotations(), annotationPosTable);
1545+
}
15431546
typeIdent = ((JCAnnotatedType) typeIdent).getUnderlyingType();
15441547
}
15451548
if (typeIdent instanceof JCArrayTypeTree) {
@@ -1551,16 +1554,21 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
15511554
}
15521555
}
15531556

1557+
List<J.Annotation> leadingAnnotations = leadingAnnotations(annotationPosTable);
15541558
Space prefix = whitespace();
15551559
TypeTree elemType = convert(typeIdent);
15561560
List<J.Annotation> annotations = leadingAnnotations(annotationPosTable);
15571561
JLeftPadded<Space> dimension = padLeft(sourceBefore("["), sourceBefore("]"));
15581562
assert arrayTypeTree != null;
1559-
return new J.ArrayType(randomId(), prefix, Markers.EMPTY,
1563+
TypeTree result = new J.ArrayType(randomId(), prefix, Markers.EMPTY,
15601564
count == 1 ? elemType : mapDimensions(elemType, arrayTypeTree.getType(), annotationPosTable),
15611565
annotations,
15621566
dimension,
15631567
typeMapping.type(tree));
1568+
if (!leadingAnnotations.isEmpty()) {
1569+
result = new J.AnnotatedType(randomId(), EMPTY, Markers.EMPTY, leadingAnnotations, result);
1570+
}
1571+
return result;
15641572
}
15651573

15661574
private TypeTree mapDimensions(TypeTree baseType, Tree tree, Map<Integer, JCAnnotation> annotationPosTable) {

rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,9 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
13271327
JCArrayTypeTree arrayTypeTree = null;
13281328
while (typeIdent instanceof JCAnnotatedType || typeIdent instanceof JCArrayTypeTree) {
13291329
if (typeIdent instanceof JCAnnotatedType) {
1330-
mapAnnotations(((JCAnnotatedType) typeIdent).getAnnotations(), annotationPosTable);
1330+
if (count > 0) {
1331+
mapAnnotations(((JCAnnotatedType) typeIdent).getAnnotations(), annotationPosTable);
1332+
}
13311333
typeIdent = ((JCAnnotatedType) typeIdent).getUnderlyingType();
13321334
}
13331335
if (typeIdent instanceof JCArrayTypeTree) {
@@ -1339,16 +1341,21 @@ private TypeTree arrayTypeTree(Tree tree, Map<Integer, JCAnnotation> annotationP
13391341
}
13401342
}
13411343

1344+
List<J.Annotation> leadingAnnotations = leadingAnnotations(annotationPosTable);
13421345
Space prefix = whitespace();
13431346
TypeTree elemType = convert(typeIdent);
13441347
List<J.Annotation> annotations = leadingAnnotations(annotationPosTable);
13451348
JLeftPadded<Space> dimension = padLeft(sourceBefore("["), sourceBefore("]"));
13461349
assert arrayTypeTree != null;
1347-
return new J.ArrayType(randomId(), prefix, Markers.EMPTY,
1350+
TypeTree result = new J.ArrayType(randomId(), prefix, Markers.EMPTY,
13481351
count == 1 ? elemType : mapDimensions(elemType, arrayTypeTree.getType(), annotationPosTable),
13491352
annotations,
13501353
dimension,
13511354
typeMapping.type(tree));
1355+
if (!leadingAnnotations.isEmpty()) {
1356+
result = new J.AnnotatedType(randomId(), EMPTY, Markers.EMPTY, leadingAnnotations, result);
1357+
}
1358+
return result;
13521359
}
13531360

13541361
private TypeTree mapDimensions(TypeTree baseType, Tree tree, Map<Integer, JCAnnotation> annotationPosTable) {

rewrite-java-tck/src/main/java/org/openrewrite/java/tree/TypeCastTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,50 @@ class Test {
3838
);
3939
}
4040

41+
@Test
42+
void annotatedArrayTypeCast() {
43+
rewriteRun(
44+
java(
45+
"""
46+
import java.lang.annotation.ElementType;
47+
import java.lang.annotation.Target;
48+
49+
class Test {
50+
@Target(ElementType.TYPE_USE)
51+
@interface Nullable {}
52+
53+
Object[] m(Object o) {
54+
return (@Nullable Object[]) o;
55+
}
56+
}
57+
"""
58+
)
59+
);
60+
}
61+
62+
@Test
63+
void annotatedArrayTypeCastInExpression() {
64+
rewriteRun(
65+
java(
66+
"""
67+
import java.lang.annotation.ElementType;
68+
import java.lang.annotation.Target;
69+
import java.lang.reflect.Array;
70+
71+
class Test {
72+
@Target(ElementType.TYPE_USE)
73+
@interface Nullable {}
74+
75+
Object[] m(Object o) {
76+
Object[] varargs = (@Nullable Object[]) Array.newInstance(Object.class, 1);
77+
return varargs;
78+
}
79+
}
80+
"""
81+
)
82+
);
83+
}
84+
4185
@Test
4286
void intersectionCast() {
4387
rewriteRun(

0 commit comments

Comments
 (0)