• 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.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