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