Skip to content

Commit 8d08314

Browse files
committed
8337795: Type annotation attached to incorrect type during class reading
Reviewed-by: vromero
1 parent f84240b commit 8d08314

File tree

2 files changed

+65
-84
lines changed

2 files changed

+65
-84
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java

Lines changed: 61 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@
3636
import java.util.HashSet;
3737
import java.util.Map;
3838
import java.util.Set;
39-
import java.util.function.BiFunction;
4039
import java.util.function.IntFunction;
4140
import java.util.function.Predicate;
41+
import java.util.stream.IntStream;
4242

4343
import javax.lang.model.element.Modifier;
4444
import javax.lang.model.element.NestingKind;
@@ -2461,13 +2461,8 @@ private Type addTypeAnnotations(Type type, Predicate<TypeAnnotationPosition> fil
24612461
.add(attribute);
24622462
}
24632463

2464-
// Search the structure of the type to find the contained types at each type path
2465-
Map<Type, List<Attribute.TypeCompound>> attributesByType = new HashMap<>();
2466-
new TypeAnnotationLocator(attributesByPath, attributesByType).visit(type, List.nil());
2467-
24682464
// Rewrite the type and add the annotations
2469-
type = new TypeAnnotationTypeMapping(attributesByType).visit(type, null);
2470-
Assert.check(attributesByType.isEmpty(), "Failed to apply annotations to types");
2465+
type = new TypeAnnotationStructuralTypeMapping(attributesByPath).visit(type, List.nil());
24712466

24722467
return type;
24732468
}
@@ -2495,120 +2490,102 @@ private static Predicate<TypeAnnotationPosition> classExtends(int index) {
24952490
}
24962491

24972492
/**
2498-
* Visit all contained types, assembling a type path to represent the current location, and
2499-
* record the types at each type path that need to be annotated.
2493+
* A type mapping that rewrites the type to include type annotations.
2494+
*
2495+
* <p>This logic is similar to {@link Type.StructuralTypeMapping}, but also tracks the path to
2496+
* the contained types being rewritten, and so cannot easily share the existing logic.
25002497
*/
2501-
private static class TypeAnnotationLocator
2502-
extends Types.DefaultTypeVisitor<Void, List<TypeAnnotationPosition.TypePathEntry>> {
2498+
private static final class TypeAnnotationStructuralTypeMapping
2499+
extends Types.TypeMapping<List<TypeAnnotationPosition.TypePathEntry>> {
2500+
25032501
private final Map<List<TypeAnnotationPosition.TypePathEntry>,
2504-
ListBuffer<Attribute.TypeCompound>> attributesByPath;
2505-
private final Map<Type, List<Attribute.TypeCompound>> attributesByType;
2502+
ListBuffer<Attribute.TypeCompound>> attributesByPath;
25062503

2507-
private TypeAnnotationLocator(
2504+
private TypeAnnotationStructuralTypeMapping(
25082505
Map<List<TypeAnnotationPosition.TypePathEntry>, ListBuffer<Attribute.TypeCompound>>
2509-
attributesByPath,
2510-
Map<Type, List<Attribute.TypeCompound>> attributesByType) {
2506+
attributesByPath) {
25112507
this.attributesByPath = attributesByPath;
2512-
this.attributesByType = attributesByType;
25132508
}
25142509

2510+
25152511
@Override
2516-
public Void visitClassType(ClassType t, List<TypeAnnotationPosition.TypePathEntry> path) {
2512+
public Type visitClassType(ClassType t, List<TypeAnnotationPosition.TypePathEntry> path) {
25172513
// As described in JVMS 4.7.20.2, type annotations on nested types are located with
25182514
// 'left-to-right' steps starting on 'the outermost part of the type for which a type
25192515
// annotation is admissible'. So the current path represents the outermost containing
25202516
// type of the type being visited, and we add type path steps for every contained nested
25212517
// type.
2522-
List<ClassType> enclosing = List.nil();
2523-
for (Type curr = t;
2524-
curr != null && curr != Type.noType;
2518+
Type outer = t.getEnclosingType();
2519+
Type outer1 = outer != Type.noType ? visit(outer, path) : outer;
2520+
for (Type curr = t.getEnclosingType();
2521+
curr != Type.noType;
25252522
curr = curr.getEnclosingType()) {
2526-
enclosing = enclosing.prepend((ClassType) curr);
2527-
}
2528-
for (ClassType te : enclosing) {
2529-
if (te.typarams_field != null) {
2530-
int i = 0;
2531-
for (Type typaram : te.typarams_field) {
2532-
visit(typaram, path.append(new TypeAnnotationPosition.TypePathEntry(
2533-
TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i++)));
2534-
}
2535-
}
2536-
visitType(te, path);
25372523
path = path.append(TypeAnnotationPosition.TypePathEntry.INNER_TYPE);
25382524
}
2539-
return null;
2525+
List<Type> typarams = t.getTypeArguments();
2526+
List<Type> typarams1 = rewriteTypeParams(path, typarams);
2527+
if (outer1 != outer || typarams != typarams1) {
2528+
t = new ClassType(outer1, typarams1, t.tsym, t.getMetadata());
2529+
}
2530+
return reannotate(t, path);
25402531
}
25412532

2542-
@Override
2543-
public Void visitWildcardType(
2544-
WildcardType t, List<TypeAnnotationPosition.TypePathEntry> path) {
2545-
visit(t.type, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD));
2546-
return super.visitWildcardType(t, path);
2533+
private List<Type> rewriteTypeParams(
2534+
List<TypeAnnotationPosition.TypePathEntry> path, List<Type> typarams) {
2535+
var i = IntStream.iterate(0, x -> x + 1).iterator();
2536+
return typarams.map(typaram -> visit(typaram,
2537+
path.append(new TypeAnnotationPosition.TypePathEntry(
2538+
TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i.nextInt()))));
25472539
}
25482540

25492541
@Override
2550-
public Void visitArrayType(ArrayType t, List<TypeAnnotationPosition.TypePathEntry> path) {
2551-
visit(t.elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY));
2552-
return super.visitArrayType(t, path);
2542+
public Type visitWildcardType(
2543+
WildcardType wt, List<TypeAnnotationPosition.TypePathEntry> path) {
2544+
Type t = wt.type;
2545+
if (t != null) {
2546+
t = visit(t, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD));
2547+
}
2548+
if (t != wt.type) {
2549+
wt = new WildcardType(t, wt.kind, wt.tsym, wt.bound, wt.getMetadata());
2550+
}
2551+
return reannotate(wt, path);
25532552
}
25542553

25552554
@Override
2556-
public Void visitType(Type t, List<TypeAnnotationPosition.TypePathEntry> path) {
2557-
ListBuffer<Attribute.TypeCompound> attributes = attributesByPath.remove(path);
2558-
if (attributes != null) {
2559-
attributesByType.put(t, attributes.toList());
2555+
public Type visitArrayType(ArrayType t, List<TypeAnnotationPosition.TypePathEntry> path) {
2556+
Type elemtype = t.elemtype;
2557+
Type elemtype1 =
2558+
visit(elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY));
2559+
if (elemtype1 != elemtype) {
2560+
t = new ArrayType(elemtype1, t.tsym, t.getMetadata());
25602561
}
2561-
return null;
2562+
return reannotate(t, path);
25622563
}
2563-
}
2564-
2565-
/** A type mapping that rewrites the type to include type annotations. */
2566-
private static class TypeAnnotationTypeMapping extends Type.StructuralTypeMapping<Void> {
25672564

2568-
private final Map<Type, List<Attribute.TypeCompound>> attributesByType;
2569-
2570-
private TypeAnnotationTypeMapping(
2571-
Map<Type, List<Attribute.TypeCompound>> attributesByType) {
2572-
this.attributesByType = attributesByType;
2565+
@Override
2566+
public Type visitType(Type t, List<TypeAnnotationPosition.TypePathEntry> path) {
2567+
return reannotate(t, path);
25732568
}
25742569

2575-
private <T extends Type> Type reannotate(T t, BiFunction<T, Void, Type> f) {
2576-
// We're relying on object identify of Type instances to record where the annotations
2577-
// need to be added, so we have to retrieve the annotations for each type before
2578-
// rewriting it, and then add them after its contained types have been rewritten.
2579-
List<Attribute.TypeCompound> attributes = attributesByType.remove(t);
2580-
Type mapped = f.apply(t, null);
2581-
if (attributes == null) {
2582-
return mapped;
2570+
Type reannotate(Type type, List<TypeAnnotationPosition.TypePathEntry> path) {
2571+
List<Attribute.TypeCompound> attributes = attributesForPath(path);
2572+
if (attributes.isEmpty()) {
2573+
return type;
25832574
}
25842575
// Runtime-visible and -invisible annotations are completed separately, so if the same
25852576
// type has annotations from both it will get annotated twice.
2586-
TypeMetadata.Annotations existing = mapped.getMetadata(TypeMetadata.Annotations.class);
2577+
TypeMetadata.Annotations existing = type.getMetadata(TypeMetadata.Annotations.class);
25872578
if (existing != null) {
25882579
existing.annotationBuffer().addAll(attributes);
2589-
return mapped;
2580+
return type;
25902581
}
2591-
return mapped.annotatedType(attributes);
2582+
return type.annotatedType(attributes);
25922583
}
25932584

2594-
@Override
2595-
public Type visitClassType(ClassType t, Void unused) {
2596-
return reannotate(t, super::visitClassType);
2597-
}
2598-
2599-
@Override
2600-
public Type visitWildcardType(WildcardType t, Void unused) {
2601-
return reannotate(t, super::visitWildcardType);
2602-
}
2603-
2604-
@Override
2605-
public Type visitArrayType(ArrayType t, Void unused) {
2606-
return reannotate(t, super::visitArrayType);
2607-
}
2608-
2609-
@Override
2610-
public Type visitType(Type t, Void unused) {
2611-
return reannotate(t, (x, u) -> x);
2585+
List<Attribute.TypeCompound> attributesForPath(
2586+
List<TypeAnnotationPosition.TypePathEntry> path) {
2587+
ListBuffer<Attribute.TypeCompound> attributes = attributesByPath.remove(path);
2588+
return attributes != null ? attributes.toList() : List.nil();
26122589
}
26132590
}
26142591

test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,4 +717,8 @@ private class GenericNested<Y> {
717717
GenericNested(@TA(120) GenericInner120<X> GenericInner120.this) {}
718718
}
719719
}
720+
721+
@Test(posn=1, annoType=TA.class, expect="130")
722+
@Test(posn=23, annoType=TA.class, expect="131")
723+
public Map<@TA(130) String, @TA(131) String> f130;
720724
}

0 commit comments

Comments
 (0)