• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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