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