1 /* 2 * Copyright 2016 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.turbine.lower; 18 19 import static com.google.common.collect.Iterables.getOnlyElement; 20 import static com.google.turbine.binder.DisambiguateTypeAnnotations.groupRepeated; 21 22 import com.google.common.base.Function; 23 import com.google.common.collect.ImmutableList; 24 import com.google.common.collect.ImmutableList.Builder; 25 import com.google.common.collect.ImmutableMap; 26 import com.google.common.collect.ImmutableSet; 27 import com.google.turbine.binder.bound.AnnotationValue; 28 import com.google.turbine.binder.bound.EnumConstantValue; 29 import com.google.turbine.binder.bound.ModuleInfo.ExportInfo; 30 import com.google.turbine.binder.bound.ModuleInfo.OpenInfo; 31 import com.google.turbine.binder.bound.ModuleInfo.ProvideInfo; 32 import com.google.turbine.binder.bound.ModuleInfo.RequireInfo; 33 import com.google.turbine.binder.bound.ModuleInfo.UseInfo; 34 import com.google.turbine.binder.bound.SourceModuleInfo; 35 import com.google.turbine.binder.bound.SourceTypeBoundClass; 36 import com.google.turbine.binder.bound.TurbineClassValue; 37 import com.google.turbine.binder.bound.TypeBoundClass; 38 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo; 39 import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo; 40 import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo; 41 import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo; 42 import com.google.turbine.binder.bytecode.BytecodeBoundClass; 43 import com.google.turbine.binder.env.CompoundEnv; 44 import com.google.turbine.binder.env.Env; 45 import com.google.turbine.binder.env.SimpleEnv; 46 import com.google.turbine.binder.sym.ClassSymbol; 47 import com.google.turbine.binder.sym.Symbol; 48 import com.google.turbine.binder.sym.TyVarSymbol; 49 import com.google.turbine.bytecode.ClassFile; 50 import com.google.turbine.bytecode.ClassFile.AnnotationInfo; 51 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue; 52 import com.google.turbine.bytecode.ClassFile.MethodInfo.ParameterInfo; 53 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo; 54 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.Target; 55 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TargetType; 56 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.ThrowsTarget; 57 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypePath; 58 import com.google.turbine.bytecode.ClassWriter; 59 import com.google.turbine.bytecode.sig.Sig; 60 import com.google.turbine.bytecode.sig.Sig.MethodSig; 61 import com.google.turbine.bytecode.sig.Sig.TySig; 62 import com.google.turbine.bytecode.sig.SigWriter; 63 import com.google.turbine.diag.SourceFile; 64 import com.google.turbine.diag.TurbineError; 65 import com.google.turbine.diag.TurbineError.ErrorKind; 66 import com.google.turbine.model.Const; 67 import com.google.turbine.model.TurbineFlag; 68 import com.google.turbine.model.TurbineTyKind; 69 import com.google.turbine.model.TurbineVisibility; 70 import com.google.turbine.type.AnnoInfo; 71 import com.google.turbine.type.Type; 72 import com.google.turbine.type.Type.ArrayTy; 73 import com.google.turbine.type.Type.ClassTy; 74 import com.google.turbine.type.Type.ClassTy.SimpleClassTy; 75 import com.google.turbine.type.Type.TyKind; 76 import com.google.turbine.type.Type.TyVar; 77 import com.google.turbine.type.Type.WildTy; 78 import com.google.turbine.types.Erasure; 79 import java.lang.annotation.RetentionPolicy; 80 import java.util.ArrayDeque; 81 import java.util.ArrayList; 82 import java.util.Deque; 83 import java.util.LinkedHashSet; 84 import java.util.List; 85 import java.util.Map; 86 import java.util.Set; 87 import javax.annotation.Nullable; 88 89 /** Lowering from bound classes to bytecode. */ 90 public class Lower { 91 92 /** The lowered compilation output. */ 93 public static class Lowered { 94 private final ImmutableMap<String, byte[]> bytes; 95 private final ImmutableSet<ClassSymbol> symbols; 96 Lowered(ImmutableMap<String, byte[]> bytes, ImmutableSet<ClassSymbol> symbols)97 public Lowered(ImmutableMap<String, byte[]> bytes, ImmutableSet<ClassSymbol> symbols) { 98 this.bytes = bytes; 99 this.symbols = symbols; 100 } 101 102 /** Returns the bytecode for classes in the compilation. */ bytes()103 public ImmutableMap<String, byte[]> bytes() { 104 return bytes; 105 } 106 107 /** Returns the set of all referenced symbols in the compilation. */ symbols()108 public ImmutableSet<ClassSymbol> symbols() { 109 return symbols; 110 } 111 } 112 113 /** Lowers all given classes to bytecode. */ lowerAll( ImmutableMap<ClassSymbol, SourceTypeBoundClass> units, ImmutableList<SourceModuleInfo> modules, Env<ClassSymbol, BytecodeBoundClass> classpath)114 public static Lowered lowerAll( 115 ImmutableMap<ClassSymbol, SourceTypeBoundClass> units, 116 ImmutableList<SourceModuleInfo> modules, 117 Env<ClassSymbol, BytecodeBoundClass> classpath) { 118 CompoundEnv<ClassSymbol, TypeBoundClass> env = 119 CompoundEnv.<ClassSymbol, TypeBoundClass>of(classpath).append(new SimpleEnv<>(units)); 120 ImmutableMap.Builder<String, byte[]> result = ImmutableMap.builder(); 121 Set<ClassSymbol> symbols = new LinkedHashSet<>(); 122 for (ClassSymbol sym : units.keySet()) { 123 result.put(sym.binaryName(), lower(units.get(sym), env, sym, symbols)); 124 } 125 if (modules.size() == 1) { 126 // single module mode: the module-info.class file is at the root 127 result.put("module-info", lower(getOnlyElement(modules), env, symbols)); 128 } else { 129 // multi-module mode: the output module-info.class are in a directory corresponding to their 130 // package 131 for (SourceModuleInfo module : modules) { 132 result.put(module.name().replace('.', '/') + "/module-info", lower(module, env, symbols)); 133 } 134 } 135 return new Lowered(result.build(), ImmutableSet.copyOf(symbols)); 136 } 137 138 /** Lowers a class to bytecode. */ lower( SourceTypeBoundClass info, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, Set<ClassSymbol> symbols)139 public static byte[] lower( 140 SourceTypeBoundClass info, 141 Env<ClassSymbol, TypeBoundClass> env, 142 ClassSymbol sym, 143 Set<ClassSymbol> symbols) { 144 return new Lower(env).lower(info, sym, symbols); 145 } 146 lower( SourceModuleInfo module, CompoundEnv<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> symbols)147 private static byte[] lower( 148 SourceModuleInfo module, 149 CompoundEnv<ClassSymbol, TypeBoundClass> env, 150 Set<ClassSymbol> symbols) { 151 return new Lower(env).lower(module, symbols); 152 } 153 154 private final LowerSignature sig = new LowerSignature(); 155 private final Env<ClassSymbol, TypeBoundClass> env; 156 Lower(Env<ClassSymbol, TypeBoundClass> env)157 public Lower(Env<ClassSymbol, TypeBoundClass> env) { 158 this.env = env; 159 } 160 lower(SourceModuleInfo module, Set<ClassSymbol> symbols)161 private byte[] lower(SourceModuleInfo module, Set<ClassSymbol> symbols) { 162 String name = "module-info"; 163 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(module.annos()); 164 ClassFile.ModuleInfo moduleInfo = lowerModule(module); 165 166 ImmutableList.Builder<ClassFile.InnerClass> innerClasses = ImmutableList.builder(); 167 { 168 Set<ClassSymbol> all = new LinkedHashSet<>(); 169 for (ClassSymbol sym : sig.classes) { 170 addEnclosing(module.source(), env, all, sym); 171 } 172 for (ClassSymbol innerSym : all) { 173 innerClasses.add(innerClass(env, innerSym)); 174 } 175 } 176 177 ClassFile classfile = 178 new ClassFile( 179 /* access= */ TurbineFlag.ACC_MODULE, 180 name, 181 /* signature= */ null, 182 /* superClass= */ null, 183 /* interfaces= */ ImmutableList.of(), 184 /* methods= */ ImmutableList.of(), 185 /* fields= */ ImmutableList.of(), 186 annotations, 187 innerClasses.build(), 188 /* typeAnnotations= */ ImmutableList.of(), 189 moduleInfo); 190 symbols.addAll(sig.classes); 191 return ClassWriter.writeClass(classfile); 192 } 193 lowerModule(SourceModuleInfo module)194 private ClassFile.ModuleInfo lowerModule(SourceModuleInfo module) { 195 ImmutableList.Builder<ClassFile.ModuleInfo.RequireInfo> requires = ImmutableList.builder(); 196 for (RequireInfo require : module.requires()) { 197 requires.add( 198 new ClassFile.ModuleInfo.RequireInfo( 199 require.moduleName(), require.flags(), require.version())); 200 } 201 ImmutableList.Builder<ClassFile.ModuleInfo.ExportInfo> exports = ImmutableList.builder(); 202 for (ExportInfo export : module.exports()) { 203 int exportAccess = 0; // not synthetic or mandated 204 exports.add( 205 new ClassFile.ModuleInfo.ExportInfo( 206 export.packageName(), exportAccess, export.modules())); 207 } 208 ImmutableList.Builder<ClassFile.ModuleInfo.OpenInfo> opens = ImmutableList.builder(); 209 for (OpenInfo open : module.opens()) { 210 int openAccess = 0; // not synthetic or mandated 211 opens.add(new ClassFile.ModuleInfo.OpenInfo(open.packageName(), openAccess, open.modules())); 212 } 213 ImmutableList.Builder<ClassFile.ModuleInfo.UseInfo> uses = ImmutableList.builder(); 214 for (UseInfo use : module.uses()) { 215 uses.add(new ClassFile.ModuleInfo.UseInfo(sig.descriptor(use.sym()))); 216 } 217 ImmutableList.Builder<ClassFile.ModuleInfo.ProvideInfo> provides = ImmutableList.builder(); 218 for (ProvideInfo provide : module.provides()) { 219 ImmutableList.Builder<String> impls = ImmutableList.builder(); 220 for (ClassSymbol impl : provide.impls()) { 221 impls.add(sig.descriptor(impl)); 222 } 223 provides.add( 224 new ClassFile.ModuleInfo.ProvideInfo(sig.descriptor(provide.sym()), impls.build())); 225 } 226 return new ClassFile.ModuleInfo( 227 module.name(), 228 module.flags(), 229 module.version(), 230 requires.build(), 231 exports.build(), 232 opens.build(), 233 uses.build(), 234 provides.build()); 235 } 236 lower(SourceTypeBoundClass info, ClassSymbol sym, Set<ClassSymbol> symbols)237 private byte[] lower(SourceTypeBoundClass info, ClassSymbol sym, Set<ClassSymbol> symbols) { 238 int access = classAccess(info); 239 String name = sig.descriptor(sym); 240 String signature = sig.classSignature(info, env); 241 String superName = info.superclass() != null ? sig.descriptor(info.superclass()) : null; 242 List<String> interfaces = new ArrayList<>(); 243 for (ClassSymbol i : info.interfaces()) { 244 interfaces.add(sig.descriptor(i)); 245 } 246 247 List<ClassFile.MethodInfo> methods = new ArrayList<>(); 248 for (MethodInfo m : info.methods()) { 249 if (TurbineVisibility.fromAccess(m.access()) == TurbineVisibility.PRIVATE) { 250 // TODO(cushon): drop private members earlier? 251 continue; 252 } 253 methods.add(lowerMethod(m, sym)); 254 } 255 256 ImmutableList.Builder<ClassFile.FieldInfo> fields = ImmutableList.builder(); 257 for (FieldInfo f : info.fields()) { 258 if ((f.access() & TurbineFlag.ACC_PRIVATE) == TurbineFlag.ACC_PRIVATE) { 259 // TODO(cushon): drop private members earlier? 260 continue; 261 } 262 fields.add(lowerField(f)); 263 } 264 265 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(info.annotations()); 266 267 ImmutableList<ClassFile.InnerClass> inners = collectInnerClasses(info.source(), sym, info); 268 269 ImmutableList<TypeAnnotationInfo> typeAnnotations = classTypeAnnotations(info); 270 271 ClassFile classfile = 272 new ClassFile( 273 access, 274 name, 275 signature, 276 superName, 277 interfaces, 278 methods, 279 fields.build(), 280 annotations, 281 inners, 282 typeAnnotations, 283 /* module= */ null); 284 285 symbols.addAll(sig.classes); 286 287 return ClassWriter.writeClass(classfile); 288 } 289 lowerMethod(final MethodInfo m, final ClassSymbol sym)290 private ClassFile.MethodInfo lowerMethod(final MethodInfo m, final ClassSymbol sym) { 291 int access = m.access(); 292 Function<TyVarSymbol, TyVarInfo> tenv = new TyVarEnv(m.tyParams()); 293 String name = m.name(); 294 String desc = methodDescriptor(m, tenv); 295 String signature = sig.methodSignature(env, m, sym); 296 ImmutableList.Builder<String> exceptions = ImmutableList.builder(); 297 if (!m.exceptions().isEmpty()) { 298 for (Type e : m.exceptions()) { 299 exceptions.add(sig.descriptor(((ClassTy) Erasure.erase(e, tenv)).sym())); 300 } 301 } 302 303 ElementValue defaultValue = m.defaultValue() != null ? annotationValue(m.defaultValue()) : null; 304 305 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(m.annotations()); 306 307 ImmutableList<ImmutableList<AnnotationInfo>> paramAnnotations = parameterAnnotations(m); 308 309 ImmutableList<TypeAnnotationInfo> typeAnnotations = methodTypeAnnotations(m); 310 311 ImmutableList<ClassFile.MethodInfo.ParameterInfo> parameters = methodParameters(m); 312 313 return new ClassFile.MethodInfo( 314 access, 315 name, 316 desc, 317 signature, 318 exceptions.build(), 319 defaultValue, 320 annotations, 321 paramAnnotations, 322 typeAnnotations, 323 parameters); 324 } 325 methodParameters(MethodInfo m)326 private ImmutableList<ParameterInfo> methodParameters(MethodInfo m) { 327 ImmutableList.Builder<ParameterInfo> result = ImmutableList.builder(); 328 for (ParamInfo p : m.parameters()) { 329 result.add(new ParameterInfo(p.name(), p.access() & PARAMETER_ACCESS_MASK)); 330 } 331 return result.build(); 332 } 333 334 private static final int PARAMETER_ACCESS_MASK = 335 TurbineFlag.ACC_MANDATED | TurbineFlag.ACC_FINAL | TurbineFlag.ACC_SYNTHETIC; 336 parameterAnnotations(MethodInfo m)337 private ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations(MethodInfo m) { 338 ImmutableList.Builder<ImmutableList<AnnotationInfo>> annotations = ImmutableList.builder(); 339 for (ParamInfo parameter : m.parameters()) { 340 if (parameter.synthetic()) { 341 continue; 342 } 343 if (parameter.annotations().isEmpty()) { 344 annotations.add(ImmutableList.of()); 345 continue; 346 } 347 ImmutableList.Builder<AnnotationInfo> parameterAnnotations = ImmutableList.builder(); 348 for (AnnoInfo annotation : parameter.annotations()) { 349 Boolean visible = isVisible(annotation.sym()); 350 if (visible == null) { 351 continue; 352 } 353 String desc = sig.objectType(annotation.sym()); 354 parameterAnnotations.add( 355 new AnnotationInfo(desc, visible, annotationValues(annotation.values()))); 356 } 357 annotations.add(parameterAnnotations.build()); 358 } 359 return annotations.build(); 360 } 361 methodDescriptor(MethodInfo m, Function<TyVarSymbol, TyVarInfo> tenv)362 private String methodDescriptor(MethodInfo m, Function<TyVarSymbol, TyVarInfo> tenv) { 363 ImmutableList<Sig.TyParamSig> typarams = ImmutableList.of(); 364 ImmutableList.Builder<TySig> fparams = ImmutableList.builder(); 365 for (ParamInfo t : m.parameters()) { 366 fparams.add(sig.signature(Erasure.erase(t.type(), tenv))); 367 } 368 TySig result = sig.signature(Erasure.erase(m.returnType(), tenv)); 369 ImmutableList<TySig> excns = ImmutableList.of(); 370 return SigWriter.method(new MethodSig(typarams, fparams.build(), result, excns)); 371 } 372 lowerField(FieldInfo f)373 private ClassFile.FieldInfo lowerField(FieldInfo f) { 374 final String name = f.name(); 375 Function<TyVarSymbol, TyVarInfo> tenv = new TyVarEnv(ImmutableMap.of()); 376 String desc = SigWriter.type(sig.signature(Erasure.erase(f.type(), tenv))); 377 String signature = sig.fieldSignature(f.type()); 378 379 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(f.annotations()); 380 381 ImmutableList.Builder<TypeAnnotationInfo> typeAnnotations = ImmutableList.builder(); 382 lowerTypeAnnotations( 383 typeAnnotations, f.type(), TargetType.FIELD, TypeAnnotationInfo.EMPTY_TARGET); 384 385 return new ClassFile.FieldInfo( 386 f.access(), name, desc, signature, f.value(), annotations, typeAnnotations.build()); 387 } 388 389 /** Creates inner class attributes for all referenced inner classes. */ collectInnerClasses( SourceFile source, ClassSymbol origin, SourceTypeBoundClass info)390 private ImmutableList<ClassFile.InnerClass> collectInnerClasses( 391 SourceFile source, ClassSymbol origin, SourceTypeBoundClass info) { 392 Set<ClassSymbol> all = new LinkedHashSet<>(); 393 addEnclosing(source, env, all, origin); 394 for (ClassSymbol sym : info.children().values()) { 395 addEnclosing(source, env, all, sym); 396 } 397 for (ClassSymbol sym : sig.classes) { 398 addEnclosing(source, env, all, sym); 399 } 400 ImmutableList.Builder<ClassFile.InnerClass> inners = ImmutableList.builder(); 401 for (ClassSymbol innerSym : all) { 402 inners.add(innerClass(env, innerSym)); 403 } 404 return inners.build(); 405 } 406 407 /** 408 * Record all enclosing declarations of a symbol, to make sure the necessary InnerClass attributes 409 * are added. 410 * 411 * <p>javac expects InnerClass attributes for enclosing classes to appear before their member 412 * classes' entries. 413 */ addEnclosing( SourceFile source, Env<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> all, ClassSymbol sym)414 private void addEnclosing( 415 SourceFile source, 416 Env<ClassSymbol, TypeBoundClass> env, 417 Set<ClassSymbol> all, 418 ClassSymbol sym) { 419 TypeBoundClass info = env.get(sym); 420 if (info == null) { 421 throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, sym); 422 } 423 ClassSymbol owner = env.get(sym).owner(); 424 if (owner != null) { 425 addEnclosing(source, env, all, owner); 426 all.add(sym); 427 } 428 } 429 430 /** 431 * Creates an inner class attribute, given an inner class that was referenced somewhere in the 432 * class. 433 */ innerClass( Env<ClassSymbol, TypeBoundClass> env, ClassSymbol innerSym)434 private ClassFile.InnerClass innerClass( 435 Env<ClassSymbol, TypeBoundClass> env, ClassSymbol innerSym) { 436 TypeBoundClass inner = env.get(innerSym); 437 438 String innerName = innerSym.binaryName().substring(inner.owner().binaryName().length() + 1); 439 440 int access = inner.access(); 441 access &= ~(TurbineFlag.ACC_SUPER | TurbineFlag.ACC_STRICT); 442 443 return new ClassFile.InnerClass( 444 innerSym.binaryName(), inner.owner().binaryName(), innerName, access); 445 } 446 447 /** Updates visibility, and unsets access bits that can only be set in InnerClass. */ classAccess(SourceTypeBoundClass info)448 private int classAccess(SourceTypeBoundClass info) { 449 int access = info.access(); 450 access &= ~(TurbineFlag.ACC_STATIC | TurbineFlag.ACC_PRIVATE | TurbineFlag.ACC_STRICT); 451 if ((access & TurbineFlag.ACC_PROTECTED) != 0) { 452 access &= ~TurbineFlag.ACC_PROTECTED; 453 access |= TurbineFlag.ACC_PUBLIC; 454 } 455 return access; 456 } 457 458 /** 459 * Looks up {@link TyVarInfo}s. 460 * 461 * <p>We could generalize {@link com.google.turbine.binder.lookup.Scope} instead, but this isn't 462 * needed anywhere else. 463 */ 464 class TyVarEnv implements Function<TyVarSymbol, TyVarInfo> { 465 466 private final Map<TyVarSymbol, TyVarInfo> tyParams; 467 468 /** @param tyParams the initial lookup scope, e.g. a method's formal type parameters. */ TyVarEnv(Map<TyVarSymbol, TyVarInfo> tyParams)469 public TyVarEnv(Map<TyVarSymbol, TyVarInfo> tyParams) { 470 this.tyParams = tyParams; 471 } 472 473 @Override apply(TyVarSymbol sym)474 public TyVarInfo apply(TyVarSymbol sym) { 475 TyVarInfo result = tyParams.get(sym); 476 if (result != null) { 477 return result; 478 } 479 // type variables can only be declared by methods and classes, 480 // and we've already handled methods 481 Symbol ownerSym = sym.owner(); 482 if (ownerSym.symKind() != Symbol.Kind.CLASS) { 483 throw new AssertionError(sym); 484 } 485 // anything that lexically encloses the class being lowered 486 // must be in the same compilation unit, so we have source 487 // information for it 488 TypeBoundClass owner = env.get((ClassSymbol) ownerSym); 489 return owner.typeParameterTypes().get(sym); 490 } 491 } 492 lowerAnnotations(ImmutableList<AnnoInfo> annotations)493 private ImmutableList<AnnotationInfo> lowerAnnotations(ImmutableList<AnnoInfo> annotations) { 494 ImmutableList.Builder<AnnotationInfo> lowered = ImmutableList.builder(); 495 for (AnnoInfo annotation : annotations) { 496 AnnotationInfo anno = lowerAnnotation(annotation); 497 if (anno == null) { 498 continue; 499 } 500 lowered.add(anno); 501 } 502 return lowered.build(); 503 } 504 lowerAnnotation(AnnoInfo annotation)505 private AnnotationInfo lowerAnnotation(AnnoInfo annotation) { 506 Boolean visible = isVisible(annotation.sym()); 507 if (visible == null) { 508 return null; 509 } 510 return new AnnotationInfo( 511 sig.objectType(annotation.sym()), visible, annotationValues(annotation.values())); 512 } 513 514 /** 515 * Returns true if the annotation is visible at runtime, false if it is not visible at runtime, 516 * and {@code null} if it should not be retained in bytecode. 517 */ 518 @Nullable isVisible(ClassSymbol sym)519 private Boolean isVisible(ClassSymbol sym) { 520 RetentionPolicy retention = env.get(sym).annotationMetadata().retention(); 521 switch (retention) { 522 case CLASS: 523 return false; 524 case RUNTIME: 525 return true; 526 case SOURCE: 527 return null; 528 default: 529 throw new AssertionError(retention); 530 } 531 } 532 annotationValues(ImmutableMap<String, Const> values)533 private ImmutableMap<String, ElementValue> annotationValues(ImmutableMap<String, Const> values) { 534 ImmutableMap.Builder<String, ElementValue> result = ImmutableMap.builder(); 535 for (Map.Entry<String, Const> entry : values.entrySet()) { 536 result.put(entry.getKey(), annotationValue(entry.getValue())); 537 } 538 return result.build(); 539 } 540 annotationValue(Const value)541 private ElementValue annotationValue(Const value) { 542 switch (value.kind()) { 543 case CLASS_LITERAL: 544 { 545 TurbineClassValue classValue = (TurbineClassValue) value; 546 return new ElementValue.ConstTurbineClassValue( 547 SigWriter.type(sig.signature(classValue.type()))); 548 } 549 case ENUM_CONSTANT: 550 { 551 EnumConstantValue enumValue = (EnumConstantValue) value; 552 return new ElementValue.EnumConstValue( 553 sig.objectType(enumValue.sym().owner()), enumValue.sym().name()); 554 } 555 case ARRAY: 556 { 557 Const.ArrayInitValue arrayValue = (Const.ArrayInitValue) value; 558 List<ElementValue> values = new ArrayList<>(); 559 for (Const element : arrayValue.elements()) { 560 values.add(annotationValue(element)); 561 } 562 return new ElementValue.ArrayValue(values); 563 } 564 case ANNOTATION: 565 { 566 AnnotationValue annotationValue = (AnnotationValue) value; 567 Boolean visible = isVisible(annotationValue.sym()); 568 if (visible == null) { 569 visible = true; 570 } 571 return new ElementValue.AnnotationValue( 572 new AnnotationInfo( 573 sig.objectType(annotationValue.sym()), 574 visible, 575 annotationValues(annotationValue.values()))); 576 } 577 case PRIMITIVE: 578 return new ElementValue.ConstValue((Const.Value) value); 579 default: 580 throw new AssertionError(value.kind()); 581 } 582 } 583 584 /** Lower type annotations in a class declaration's signature. */ classTypeAnnotations(SourceTypeBoundClass info)585 private ImmutableList<TypeAnnotationInfo> classTypeAnnotations(SourceTypeBoundClass info) { 586 ImmutableList.Builder<TypeAnnotationInfo> result = ImmutableList.builder(); 587 { 588 if (info.superClassType() != null) { 589 lowerTypeAnnotations( 590 result, 591 info.superClassType(), 592 TargetType.SUPERTYPE, 593 new TypeAnnotationInfo.SuperTypeTarget(-1)); 594 } 595 int idx = 0; 596 for (Type i : info.interfaceTypes()) { 597 lowerTypeAnnotations( 598 result, i, TargetType.SUPERTYPE, new TypeAnnotationInfo.SuperTypeTarget(idx++)); 599 } 600 } 601 typeParameterAnnotations( 602 result, 603 info.typeParameterTypes().values(), 604 TargetType.CLASS_TYPE_PARAMETER, 605 TargetType.CLASS_TYPE_PARAMETER_BOUND); 606 return result.build(); 607 } 608 609 /** Lower type annotations in a method declaration's signature. */ methodTypeAnnotations(MethodInfo m)610 private ImmutableList<TypeAnnotationInfo> methodTypeAnnotations(MethodInfo m) { 611 ImmutableList.Builder<TypeAnnotationInfo> result = ImmutableList.builder(); 612 613 typeParameterAnnotations( 614 result, 615 m.tyParams().values(), 616 TargetType.METHOD_TYPE_PARAMETER, 617 TargetType.METHOD_TYPE_PARAMETER_BOUND); 618 619 { 620 int idx = 0; 621 for (Type e : m.exceptions()) { 622 lowerTypeAnnotations(result, e, TargetType.METHOD_THROWS, new ThrowsTarget(idx++)); 623 } 624 } 625 626 if (m.receiver() != null) { 627 lowerTypeAnnotations( 628 result, 629 m.receiver().type(), 630 TargetType.METHOD_RECEIVER_PARAMETER, 631 TypeAnnotationInfo.EMPTY_TARGET); 632 } 633 634 lowerTypeAnnotations( 635 result, m.returnType(), TargetType.METHOD_RETURN, TypeAnnotationInfo.EMPTY_TARGET); 636 637 { 638 int idx = 0; 639 for (ParamInfo p : m.parameters()) { 640 if (p.synthetic()) { 641 continue; 642 } 643 lowerTypeAnnotations( 644 result, 645 p.type(), 646 TargetType.METHOD_FORMAL_PARAMETER, 647 new TypeAnnotationInfo.FormalParameterTarget(idx++)); 648 } 649 } 650 651 return result.build(); 652 } 653 654 /** 655 * Lower type annotations on class or method type parameters, either on the parameters themselves 656 * or on bounds. 657 */ typeParameterAnnotations( Builder<TypeAnnotationInfo> result, Iterable<TyVarInfo> typeParameters, TargetType targetType, TargetType boundTargetType)658 private void typeParameterAnnotations( 659 Builder<TypeAnnotationInfo> result, 660 Iterable<TyVarInfo> typeParameters, 661 TargetType targetType, 662 TargetType boundTargetType) { 663 int typeParameterIndex = 0; 664 for (TyVarInfo p : typeParameters) { 665 for (AnnoInfo anno : groupRepeated(env, p.annotations())) { 666 AnnotationInfo info = lowerAnnotation(anno); 667 if (info == null) { 668 continue; 669 } 670 result.add( 671 new TypeAnnotationInfo( 672 targetType, 673 new TypeAnnotationInfo.TypeParameterTarget(typeParameterIndex), 674 TypePath.root(), 675 info)); 676 } 677 int boundIndex = 0; 678 for (Type i : p.bound().bounds()) { 679 if (boundIndex == 0 && isInterface(i, env)) { 680 // super class bound index is always 0; interface bounds start at 1 681 boundIndex++; 682 } 683 lowerTypeAnnotations( 684 result, 685 i, 686 boundTargetType, 687 new TypeAnnotationInfo.TypeParameterBoundTarget(typeParameterIndex, boundIndex++)); 688 } 689 typeParameterIndex++; 690 } 691 } 692 isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env)693 private boolean isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env) { 694 return type.tyKind() == TyKind.CLASS_TY 695 && env.get(((ClassTy) type).sym()).kind() == TurbineTyKind.INTERFACE; 696 } 697 lowerTypeAnnotations( Builder<TypeAnnotationInfo> result, Type type, TargetType targetType, Target target)698 private void lowerTypeAnnotations( 699 Builder<TypeAnnotationInfo> result, Type type, TargetType targetType, Target target) { 700 new LowerTypeAnnotations(result, targetType, target) 701 .lowerTypeAnnotations(type, TypePath.root()); 702 } 703 704 class LowerTypeAnnotations { 705 private final ImmutableList.Builder<TypeAnnotationInfo> result; 706 private final TargetType targetType; 707 private final Target target; 708 LowerTypeAnnotations( Builder<TypeAnnotationInfo> result, TargetType targetType, Target target)709 public LowerTypeAnnotations( 710 Builder<TypeAnnotationInfo> result, TargetType targetType, Target target) { 711 this.result = result; 712 this.targetType = targetType; 713 this.target = target; 714 } 715 716 /** 717 * Lower all type annotations present in a type. 718 * 719 * <p>Recursively descends into nested types, and accumulates a type path structure to locate 720 * the annotation in the signature. 721 */ lowerTypeAnnotations(Type type, TypePath path)722 private void lowerTypeAnnotations(Type type, TypePath path) { 723 switch (type.tyKind()) { 724 case TY_VAR: 725 lowerTypeAnnotations(((TyVar) type).annos(), path); 726 break; 727 case CLASS_TY: 728 lowerClassTypeTypeAnnotations((ClassTy) type, path); 729 break; 730 case ARRAY_TY: 731 lowerArrayTypeAnnotations(type, path); 732 break; 733 case WILD_TY: 734 lowerWildTyTypeAnnotations((WildTy) type, path); 735 break; 736 case PRIM_TY: 737 lowerTypeAnnotations(((Type.PrimTy) type).annos(), path); 738 break; 739 case VOID_TY: 740 break; 741 default: 742 throw new AssertionError(type.tyKind()); 743 } 744 } 745 746 /** Lower a list of type annotations. */ lowerTypeAnnotations(ImmutableList<AnnoInfo> annos, TypePath path)747 private void lowerTypeAnnotations(ImmutableList<AnnoInfo> annos, TypePath path) { 748 for (AnnoInfo anno : groupRepeated(env, annos)) { 749 AnnotationInfo info = lowerAnnotation(anno); 750 if (info == null) { 751 continue; 752 } 753 result.add(new TypeAnnotationInfo(targetType, target, path, info)); 754 } 755 } 756 lowerWildTyTypeAnnotations(WildTy type, TypePath path)757 private void lowerWildTyTypeAnnotations(WildTy type, TypePath path) { 758 switch (type.boundKind()) { 759 case NONE: 760 lowerTypeAnnotations(type.annotations(), path); 761 break; 762 case UPPER: 763 case LOWER: 764 lowerTypeAnnotations(type.annotations(), path); 765 lowerTypeAnnotations(type.bound(), path.wild()); 766 break; 767 default: 768 throw new AssertionError(type.boundKind()); 769 } 770 } 771 lowerArrayTypeAnnotations(Type type, TypePath path)772 private void lowerArrayTypeAnnotations(Type type, TypePath path) { 773 Type base = type; 774 Deque<ArrayTy> flat = new ArrayDeque<>(); 775 while (base instanceof ArrayTy) { 776 ArrayTy arrayTy = (ArrayTy) base; 777 flat.addFirst(arrayTy); 778 base = arrayTy.elementType(); 779 } 780 for (ArrayTy arrayTy : flat) { 781 lowerTypeAnnotations(arrayTy.annos(), path); 782 path = path.array(); 783 } 784 lowerTypeAnnotations(base, path); 785 } 786 lowerClassTypeTypeAnnotations(ClassTy type, TypePath path)787 private void lowerClassTypeTypeAnnotations(ClassTy type, TypePath path) { 788 for (SimpleClassTy simple : type.classes()) { 789 lowerTypeAnnotations(simple.annos(), path); 790 int idx = 0; 791 for (Type a : simple.targs()) { 792 lowerTypeAnnotations(a, path.typeArgument(idx++)); 793 } 794 path = path.nested(); 795 } 796 } 797 } 798 } 799