Skip to content

Commit 7b541a2

Browse files
cushonGoeLin
authored andcommitted
8341779: [REDO BACKPORT] type annotations are not visible to javac plugins across compilation boundaries (JDK-8225377)
8340024: In ClassReader, extract a constant for the superclass supertype_index Reviewed-by: vromero Backport-of: de6667cf11aa59d1bab78ae5fb235ea0b901d5c4
1 parent 58dab5e commit 7b541a2

File tree

2 files changed

+313
-1
lines changed

2 files changed

+313
-1
lines changed

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

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
import java.util.HashSet;
3737
import java.util.Map;
3838
import java.util.Set;
39+
import java.util.function.BiFunction;
3940
import java.util.function.IntFunction;
41+
import java.util.function.Predicate;
4042

4143
import javax.lang.model.element.Modifier;
4244
import javax.lang.model.element.NestingKind;
@@ -2185,12 +2187,321 @@ public void run() {
21852187
currentClassFile = classFile;
21862188
List<Attribute.TypeCompound> newList = deproxyTypeCompoundList(proxies);
21872189
sym.setTypeAttributes(newList.prependList(sym.getRawTypeAttributes()));
2190+
addTypeAnnotationsToSymbol(sym, newList);
21882191
} finally {
21892192
currentClassFile = previousClassFile;
21902193
}
21912194
}
21922195
}
21932196

2197+
/**
2198+
* Rewrites types in the given symbol to include type annotations.
2199+
*
2200+
* <p>The list of type annotations includes annotations for all types in the signature of the
2201+
* symbol. Associating the annotations with the correct type requires interpreting the JVMS
2202+
* 4.7.20-A target_type to locate the correct type to rewrite, and then interpreting the JVMS
2203+
* 4.7.20.2 type_path to associate the annotation with the correct contained type.
2204+
*/
2205+
private static void addTypeAnnotationsToSymbol(
2206+
Symbol s, List<Attribute.TypeCompound> attributes) {
2207+
new TypeAnnotationSymbolVisitor(attributes).visit(s, null);
2208+
}
2209+
2210+
private static class TypeAnnotationSymbolVisitor
2211+
extends Types.DefaultSymbolVisitor<Void, Void> {
2212+
2213+
private final List<Attribute.TypeCompound> attributes;
2214+
2215+
private TypeAnnotationSymbolVisitor(List<Attribute.TypeCompound> attributes) {
2216+
this.attributes = attributes;
2217+
}
2218+
2219+
/**
2220+
* A supertype_index value of 65535 specifies that the annotation appears on the superclass
2221+
* in an extends clause of a class declaration, see JVMS 4.7.20.1
2222+
*/
2223+
public static final int SUPERCLASS_INDEX = 65535;
2224+
2225+
@Override
2226+
public Void visitClassSymbol(Symbol.ClassSymbol s, Void unused) {
2227+
ClassType t = (ClassType) s.type;
2228+
int i = 0;
2229+
ListBuffer<Type> interfaces = new ListBuffer<>();
2230+
for (Type itf : t.interfaces_field) {
2231+
interfaces.add(addTypeAnnotations(itf, classExtends(i++)));
2232+
}
2233+
t.interfaces_field = interfaces.toList();
2234+
t.supertype_field = addTypeAnnotations(t.supertype_field, classExtends(SUPERCLASS_INDEX));
2235+
if (t.typarams_field != null) {
2236+
t.typarams_field =
2237+
rewriteTypeParameters(
2238+
t.typarams_field, TargetType.CLASS_TYPE_PARAMETER_BOUND);
2239+
}
2240+
return null;
2241+
}
2242+
2243+
@Override
2244+
public Void visitMethodSymbol(Symbol.MethodSymbol s, Void unused) {
2245+
Type t = s.type;
2246+
if (t.hasTag(TypeTag.FORALL)) {
2247+
Type.ForAll fa = (Type.ForAll) t;
2248+
fa.tvars = rewriteTypeParameters(fa.tvars, TargetType.METHOD_TYPE_PARAMETER_BOUND);
2249+
t = fa.qtype;
2250+
}
2251+
MethodType mt = (MethodType) t;
2252+
ListBuffer<Type> argtypes = new ListBuffer<>();
2253+
int i = 0;
2254+
for (Symbol.VarSymbol param : s.params) {
2255+
param.type = addTypeAnnotations(param.type, methodFormalParameter(i++));
2256+
argtypes.add(param.type);
2257+
}
2258+
mt.argtypes = argtypes.toList();
2259+
ListBuffer<Type> thrown = new ListBuffer<>();
2260+
i = 0;
2261+
for (Type thrownType : mt.thrown) {
2262+
thrown.add(addTypeAnnotations(thrownType, thrownType(i++)));
2263+
}
2264+
mt.thrown = thrown.toList();
2265+
mt.restype = addTypeAnnotations(mt.restype, TargetType.METHOD_RETURN);
2266+
if (mt.recvtype != null) {
2267+
mt.recvtype = addTypeAnnotations(mt.recvtype, TargetType.METHOD_RECEIVER);
2268+
}
2269+
return null;
2270+
}
2271+
2272+
@Override
2273+
public Void visitVarSymbol(Symbol.VarSymbol s, Void unused) {
2274+
s.type = addTypeAnnotations(s.type, TargetType.FIELD);
2275+
return null;
2276+
}
2277+
2278+
@Override
2279+
public Void visitSymbol(Symbol s, Void unused) {
2280+
return null;
2281+
}
2282+
2283+
private List<Type> rewriteTypeParameters(List<Type> tvars, TargetType boundType) {
2284+
ListBuffer<Type> tvarbuf = new ListBuffer<>();
2285+
int typeVariableIndex = 0;
2286+
for (Type tvar : tvars) {
2287+
Type bound = tvar.getUpperBound();
2288+
if (bound.isCompound()) {
2289+
ClassType ct = (ClassType) bound;
2290+
int boundIndex = 0;
2291+
if (ct.supertype_field != null) {
2292+
ct.supertype_field =
2293+
addTypeAnnotations(
2294+
ct.supertype_field,
2295+
typeParameterBound(
2296+
boundType, typeVariableIndex, boundIndex++));
2297+
}
2298+
ListBuffer<Type> itfbuf = new ListBuffer<>();
2299+
for (Type itf : ct.interfaces_field) {
2300+
itfbuf.add(
2301+
addTypeAnnotations(
2302+
itf,
2303+
typeParameterBound(
2304+
boundType, typeVariableIndex, boundIndex++)));
2305+
}
2306+
ct.interfaces_field = itfbuf.toList();
2307+
} else {
2308+
bound =
2309+
addTypeAnnotations(
2310+
bound,
2311+
typeParameterBound(
2312+
boundType,
2313+
typeVariableIndex,
2314+
bound.isInterface() ? 1 : 0));
2315+
}
2316+
((TypeVar) tvar).setUpperBound(bound);
2317+
tvarbuf.add(tvar);
2318+
typeVariableIndex++;
2319+
}
2320+
return tvarbuf.toList();
2321+
}
2322+
2323+
private Type addTypeAnnotations(Type type, TargetType targetType) {
2324+
return addTypeAnnotations(type, pos -> pos.type == targetType);
2325+
}
2326+
2327+
private Type addTypeAnnotations(Type type, Predicate<TypeAnnotationPosition> filter) {
2328+
Assert.checkNonNull(type);
2329+
2330+
// Find type annotations that match the given target type
2331+
ListBuffer<Attribute.TypeCompound> filtered = new ListBuffer<>();
2332+
for (Attribute.TypeCompound attribute : this.attributes) {
2333+
if (filter.test(attribute.position)) {
2334+
filtered.add(attribute);
2335+
}
2336+
}
2337+
if (filtered.isEmpty()) {
2338+
return type;
2339+
}
2340+
2341+
// Group the matching annotations by their type path. Each group of annotations will be
2342+
// added to a type at that location.
2343+
Map<List<TypeAnnotationPosition.TypePathEntry>, ListBuffer<Attribute.TypeCompound>>
2344+
attributesByPath = new HashMap<>();
2345+
for (Attribute.TypeCompound attribute : filtered.toList()) {
2346+
attributesByPath
2347+
.computeIfAbsent(attribute.position.location, k -> new ListBuffer<>())
2348+
.add(attribute);
2349+
}
2350+
2351+
// Search the structure of the type to find the contained types at each type path
2352+
Map<Type, List<Attribute.TypeCompound>> attributesByType = new HashMap<>();
2353+
new TypeAnnotationLocator(attributesByPath, attributesByType).visit(type, List.nil());
2354+
2355+
// Rewrite the type and add the annotations
2356+
type = new TypeAnnotationTypeMapping(attributesByType).visit(type, null);
2357+
Assert.check(attributesByType.isEmpty(), "Failed to apply annotations to types");
2358+
2359+
return type;
2360+
}
2361+
2362+
private static Predicate<TypeAnnotationPosition> typeParameterBound(
2363+
TargetType targetType, int parameterIndex, int boundIndex) {
2364+
return pos ->
2365+
pos.type == targetType
2366+
&& pos.parameter_index == parameterIndex
2367+
&& pos.bound_index == boundIndex;
2368+
}
2369+
2370+
private static Predicate<TypeAnnotationPosition> methodFormalParameter(int index) {
2371+
return pos ->
2372+
pos.type == TargetType.METHOD_FORMAL_PARAMETER && pos.parameter_index == index;
2373+
}
2374+
2375+
private static Predicate<TypeAnnotationPosition> thrownType(int index) {
2376+
return pos -> pos.type == TargetType.THROWS && pos.type_index == index;
2377+
}
2378+
2379+
private static Predicate<TypeAnnotationPosition> classExtends(int index) {
2380+
return pos -> pos.type == TargetType.CLASS_EXTENDS && pos.type_index == index;
2381+
}
2382+
}
2383+
2384+
/**
2385+
* Visit all contained types, assembling a type path to represent the current location, and
2386+
* record the types at each type path that need to be annotated.
2387+
*/
2388+
private static class TypeAnnotationLocator
2389+
extends Types.DefaultTypeVisitor<Void, List<TypeAnnotationPosition.TypePathEntry>> {
2390+
private final Map<List<TypeAnnotationPosition.TypePathEntry>,
2391+
ListBuffer<Attribute.TypeCompound>> attributesByPath;
2392+
private final Map<Type, List<Attribute.TypeCompound>> attributesByType;
2393+
2394+
private TypeAnnotationLocator(
2395+
Map<List<TypeAnnotationPosition.TypePathEntry>, ListBuffer<Attribute.TypeCompound>>
2396+
attributesByPath,
2397+
Map<Type, List<Attribute.TypeCompound>> attributesByType) {
2398+
this.attributesByPath = attributesByPath;
2399+
this.attributesByType = attributesByType;
2400+
}
2401+
2402+
@Override
2403+
public Void visitClassType(ClassType t, List<TypeAnnotationPosition.TypePathEntry> path) {
2404+
// As described in JVMS 4.7.20.2, type annotations on nested types are located with
2405+
// 'left-to-right' steps starting on 'the outermost part of the type for which a type
2406+
// annotation is admissible'. So the current path represents the outermost containing
2407+
// type of the type being visited, and we add type path steps for every contained nested
2408+
// type.
2409+
List<ClassType> enclosing = List.nil();
2410+
for (Type curr = t;
2411+
curr != null && curr != Type.noType;
2412+
curr = curr.getEnclosingType()) {
2413+
enclosing = enclosing.prepend((ClassType) curr);
2414+
}
2415+
for (ClassType te : enclosing) {
2416+
if (te.typarams_field != null) {
2417+
int i = 0;
2418+
for (Type typaram : te.typarams_field) {
2419+
visit(typaram, path.append(new TypeAnnotationPosition.TypePathEntry(
2420+
TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i++)));
2421+
}
2422+
}
2423+
visitType(te, path);
2424+
path = path.append(TypeAnnotationPosition.TypePathEntry.INNER_TYPE);
2425+
}
2426+
return null;
2427+
}
2428+
2429+
@Override
2430+
public Void visitWildcardType(
2431+
WildcardType t, List<TypeAnnotationPosition.TypePathEntry> path) {
2432+
visit(t.type, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD));
2433+
return super.visitWildcardType(t, path);
2434+
}
2435+
2436+
@Override
2437+
public Void visitArrayType(ArrayType t, List<TypeAnnotationPosition.TypePathEntry> path) {
2438+
visit(t.elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY));
2439+
return super.visitArrayType(t, path);
2440+
}
2441+
2442+
@Override
2443+
public Void visitType(Type t, List<TypeAnnotationPosition.TypePathEntry> path) {
2444+
ListBuffer<Attribute.TypeCompound> attributes = attributesByPath.remove(path);
2445+
if (attributes != null) {
2446+
attributesByType.put(t, attributes.toList());
2447+
}
2448+
return null;
2449+
}
2450+
}
2451+
2452+
/** A type mapping that rewrites the type to include type annotations. */
2453+
private static class TypeAnnotationTypeMapping extends Type.StructuralTypeMapping<Void> {
2454+
2455+
private final Map<Type, List<Attribute.TypeCompound>> attributesByType;
2456+
2457+
private TypeAnnotationTypeMapping(
2458+
Map<Type, List<Attribute.TypeCompound>> attributesByType) {
2459+
this.attributesByType = attributesByType;
2460+
}
2461+
2462+
private <T extends Type> Type reannotate(T t, BiFunction<T, Void, Type> f) {
2463+
// We're relying on object identify of Type instances to record where the annotations
2464+
// need to be added, so we have to retrieve the annotations for each type before
2465+
// rewriting it, and then add them after its contained types have been rewritten.
2466+
List<Attribute.TypeCompound> attributes = attributesByType.remove(t);
2467+
Type mapped = f.apply(t, null);
2468+
if (attributes == null) {
2469+
return mapped;
2470+
}
2471+
// Runtime-visible and -invisible annotations are completed separately, so if the same
2472+
// type has annotations from both it will get annotated twice.
2473+
TypeMetadata metadata = mapped.getMetadata();
2474+
TypeMetadata.Annotations existing =
2475+
(TypeMetadata.Annotations) metadata.get(TypeMetadata.Entry.Kind.ANNOTATIONS);
2476+
if (existing != null) {
2477+
TypeMetadata.Annotations combined = new TypeMetadata.Annotations(
2478+
existing.getAnnotations().appendList(attributes));
2479+
return mapped.cloneWithMetadata(
2480+
metadata.without(TypeMetadata.Entry.Kind.ANNOTATIONS).combine(combined));
2481+
}
2482+
return mapped.annotatedType(attributes);
2483+
}
2484+
2485+
@Override
2486+
public Type visitClassType(ClassType t, Void unused) {
2487+
return reannotate(t, super::visitClassType);
2488+
}
2489+
2490+
@Override
2491+
public Type visitWildcardType(WildcardType t, Void unused) {
2492+
return reannotate(t, super::visitWildcardType);
2493+
}
2494+
2495+
@Override
2496+
public Type visitArrayType(ArrayType t, Void unused) {
2497+
return reannotate(t, super::visitArrayType);
2498+
}
2499+
2500+
@Override
2501+
public Type visitType(Type t, Void unused) {
2502+
return reannotate(t, (x, u) -> x);
2503+
}
2504+
}
21942505

21952506
/************************************************************************
21962507
* Reading Symbols

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 8013852 8031744
26+
* @bug 8013852 8031744 8225377
2727
* @summary Annotations on types
2828
* @library /tools/javac/lib
2929
* @modules jdk.compiler/com.sun.tools.javac.api
@@ -33,6 +33,7 @@
3333
* jdk.compiler/com.sun.tools.javac.util
3434
* @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests
3535
* @compile/process -XDaccessInternalAPI -processor BasicAnnoTests -proc:only BasicAnnoTests.java
36+
* @compile/process -XDaccessInternalAPI -processor BasicAnnoTests -proc:only BasicAnnoTests
3637
*/
3738

3839
import java.io.PrintWriter;

0 commit comments

Comments
 (0)