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