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