• 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.binder;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import com.google.auto.value.AutoValue;
22 import com.google.common.base.Splitter;
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.CompUnitPreprocessor.PreprocessedCompUnit;
27 import com.google.turbine.binder.Processing.ProcessorInfo;
28 import com.google.turbine.binder.Resolve.CanonicalResolver;
29 import com.google.turbine.binder.bound.BoundClass;
30 import com.google.turbine.binder.bound.HeaderBoundClass;
31 import com.google.turbine.binder.bound.ModuleInfo;
32 import com.google.turbine.binder.bound.PackageSourceBoundClass;
33 import com.google.turbine.binder.bound.PackageSourceBoundModule;
34 import com.google.turbine.binder.bound.SourceBoundClass;
35 import com.google.turbine.binder.bound.SourceHeaderBoundClass;
36 import com.google.turbine.binder.bound.SourceModuleInfo;
37 import com.google.turbine.binder.bound.SourceTypeBoundClass;
38 import com.google.turbine.binder.bound.TypeBoundClass;
39 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
40 import com.google.turbine.binder.bytecode.BytecodeBoundClass;
41 import com.google.turbine.binder.env.CompoundEnv;
42 import com.google.turbine.binder.env.Env;
43 import com.google.turbine.binder.env.LazyEnv;
44 import com.google.turbine.binder.env.SimpleEnv;
45 import com.google.turbine.binder.lookup.CanonicalSymbolResolver;
46 import com.google.turbine.binder.lookup.CompoundScope;
47 import com.google.turbine.binder.lookup.CompoundTopLevelIndex;
48 import com.google.turbine.binder.lookup.ImportIndex;
49 import com.google.turbine.binder.lookup.ImportScope;
50 import com.google.turbine.binder.lookup.MemberImportIndex;
51 import com.google.turbine.binder.lookup.Scope;
52 import com.google.turbine.binder.lookup.SimpleTopLevelIndex;
53 import com.google.turbine.binder.lookup.TopLevelIndex;
54 import com.google.turbine.binder.lookup.WildImportIndex;
55 import com.google.turbine.binder.sym.ClassSymbol;
56 import com.google.turbine.binder.sym.FieldSymbol;
57 import com.google.turbine.binder.sym.ModuleSymbol;
58 import com.google.turbine.diag.SourceFile;
59 import com.google.turbine.diag.TurbineDiagnostic;
60 import com.google.turbine.diag.TurbineError;
61 import com.google.turbine.diag.TurbineError.ErrorKind;
62 import com.google.turbine.diag.TurbineLog;
63 import com.google.turbine.model.Const;
64 import com.google.turbine.model.TurbineFlag;
65 import com.google.turbine.tree.Tree;
66 import com.google.turbine.tree.Tree.CompUnit;
67 import com.google.turbine.tree.Tree.ModDecl;
68 import com.google.turbine.type.Type;
69 import java.time.Duration;
70 import java.util.Optional;
71 import javax.annotation.processing.Processor;
72 import org.jspecify.annotations.Nullable;
73 
74 /** The entry point for analysis. */
75 public final class Binder {
76 
77   /** Binds symbols and types to the given compilation units. */
bind( ImmutableList<CompUnit> units, ClassPath classpath, ClassPath bootclasspath, Optional<String> moduleVersion)78   public static @Nullable BindingResult bind(
79       ImmutableList<CompUnit> units,
80       ClassPath classpath,
81       ClassPath bootclasspath,
82       Optional<String> moduleVersion) {
83     return bind(units, classpath, Processing.ProcessorInfo.empty(), bootclasspath, moduleVersion);
84   }
85 
86   /** Binds symbols and types to the given compilation units. */
bind( ImmutableList<CompUnit> units, ClassPath classpath, ProcessorInfo processorInfo, ClassPath bootclasspath, Optional<String> moduleVersion)87   public static @Nullable BindingResult bind(
88       ImmutableList<CompUnit> units,
89       ClassPath classpath,
90       ProcessorInfo processorInfo,
91       ClassPath bootclasspath,
92       Optional<String> moduleVersion) {
93     TurbineLog log = new TurbineLog();
94     BindingResult br = bind(log, units, classpath, processorInfo, bootclasspath, moduleVersion);
95     log.maybeThrow();
96     return br;
97   }
98 
99   /** Binds symbols and types to the given compilation units. */
bind( TurbineLog log, ImmutableList<CompUnit> units, ClassPath classpath, ProcessorInfo processorInfo, ClassPath bootclasspath, Optional<String> moduleVersion)100   public static @Nullable BindingResult bind(
101       TurbineLog log,
102       ImmutableList<CompUnit> units,
103       ClassPath classpath,
104       ProcessorInfo processorInfo,
105       ClassPath bootclasspath,
106       Optional<String> moduleVersion) {
107     BindingResult br;
108     try {
109       br =
110           bind(
111               log,
112               units,
113               /* generatedSources= */ ImmutableMap.of(),
114               /* generatedClasses= */ ImmutableMap.of(),
115               classpath,
116               bootclasspath,
117               moduleVersion);
118       if (!processorInfo.processors().isEmpty() && !units.isEmpty()) {
119         br =
120             Processing.process(
121                 log, units, classpath, processorInfo, bootclasspath, br, moduleVersion);
122       }
123     } catch (TurbineError turbineError) {
124       throw new TurbineError(
125           ImmutableList.<TurbineDiagnostic>builder()
126               .addAll(log.diagnostics())
127               .addAll(turbineError.diagnostics())
128               .build());
129     }
130     return br;
131   }
132 
bind( TurbineLog log, ImmutableList<CompUnit> units, ImmutableMap<String, SourceFile> generatedSources, ImmutableMap<String, byte[]> generatedClasses, ClassPath classpath, ClassPath bootclasspath, Optional<String> moduleVersion)133   static BindingResult bind(
134       TurbineLog log,
135       ImmutableList<CompUnit> units,
136       ImmutableMap<String, SourceFile> generatedSources,
137       ImmutableMap<String, byte[]> generatedClasses,
138       ClassPath classpath,
139       ClassPath bootclasspath,
140       Optional<String> moduleVersion) {
141     ImmutableList<PreprocessedCompUnit> preProcessedUnits = CompUnitPreprocessor.preprocess(units);
142 
143     SimpleEnv<ClassSymbol, SourceBoundClass> ienv = bindSourceBoundClasses(preProcessedUnits);
144 
145     ImmutableSet<ClassSymbol> syms = ienv.asMap().keySet();
146 
147     CompoundTopLevelIndex tli =
148         CompoundTopLevelIndex.of(
149             SimpleTopLevelIndex.of(ienv.asMap().keySet()),
150             bootclasspath.index(),
151             classpath.index());
152 
153     CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv =
154         CompoundEnv.of(classpath.env()).append(bootclasspath.env());
155 
156     CompoundEnv<ModuleSymbol, ModuleInfo> classPathModuleEnv =
157         CompoundEnv.of(classpath.moduleEnv()).append(bootclasspath.moduleEnv());
158 
159     BindPackagesResult bindPackagesResult =
160         bindPackages(log, ienv, tli, preProcessedUnits, classPathEnv);
161 
162     SimpleEnv<ClassSymbol, PackageSourceBoundClass> psenv = bindPackagesResult.classes;
163     SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules = bindPackagesResult.modules;
164 
165     Env<ClassSymbol, SourceHeaderBoundClass> henv = bindHierarchy(log, syms, psenv, classPathEnv);
166 
167     Env<ClassSymbol, SourceTypeBoundClass> tenv =
168         bindTypes(
169             log,
170             syms,
171             henv,
172             CompoundEnv.<ClassSymbol, HeaderBoundClass>of(classPathEnv).append(henv));
173 
174     tenv = PermitsBinder.bindPermits(syms, tenv);
175 
176     tenv =
177         constants(
178             syms,
179             tenv,
180             CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv),
181             log);
182     tenv =
183         disambiguateTypeAnnotations(
184             syms, tenv, CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv));
185     tenv =
186         canonicalizeTypes(
187             syms, tenv, CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv));
188 
189     ImmutableList<SourceModuleInfo> boundModules =
190         bindModules(
191             modules,
192             CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv),
193             classPathModuleEnv,
194             moduleVersion,
195             log);
196 
197     ImmutableMap.Builder<ClassSymbol, SourceTypeBoundClass> result = ImmutableMap.builder();
198     for (ClassSymbol sym : syms) {
199       result.put(sym, tenv.getNonNull(sym));
200     }
201 
202     return new BindingResult(
203         result.buildOrThrow(),
204         boundModules,
205         classPathEnv,
206         tli,
207         generatedSources,
208         generatedClasses,
209         Statistics.empty());
210   }
211 
212   /** Records enclosing declarations of member classes, and group classes by compilation unit. */
bindSourceBoundClasses( ImmutableList<PreprocessedCompUnit> units)213   static SimpleEnv<ClassSymbol, SourceBoundClass> bindSourceBoundClasses(
214       ImmutableList<PreprocessedCompUnit> units) {
215     SimpleEnv.Builder<ClassSymbol, SourceBoundClass> envBuilder = SimpleEnv.builder();
216     for (PreprocessedCompUnit unit : units) {
217       for (SourceBoundClass type : unit.types()) {
218         SourceBoundClass prev = envBuilder.put(type.sym(), type);
219         if (prev != null) {
220           throw TurbineError.format(
221               unit.source(), type.decl().position(), ErrorKind.DUPLICATE_DECLARATION, type.sym());
222         }
223       }
224     }
225     return envBuilder.build();
226   }
227 
228   static class BindPackagesResult {
229     final SimpleEnv<ClassSymbol, PackageSourceBoundClass> classes;
230     final SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules;
231 
BindPackagesResult( SimpleEnv<ClassSymbol, PackageSourceBoundClass> classes, SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules)232     BindPackagesResult(
233         SimpleEnv<ClassSymbol, PackageSourceBoundClass> classes,
234         SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules) {
235       this.classes = classes;
236       this.modules = modules;
237     }
238   }
239 
240   /** Initializes scopes for compilation unit and package-level lookup. */
bindPackages( TurbineLog log, Env<ClassSymbol, SourceBoundClass> ienv, TopLevelIndex tli, ImmutableList<PreprocessedCompUnit> units, CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv)241   private static BindPackagesResult bindPackages(
242       TurbineLog log,
243       Env<ClassSymbol, SourceBoundClass> ienv,
244       TopLevelIndex tli,
245       ImmutableList<PreprocessedCompUnit> units,
246       CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv) {
247 
248     SimpleEnv.Builder<ClassSymbol, PackageSourceBoundClass> env = SimpleEnv.builder();
249     SimpleEnv.Builder<ModuleSymbol, PackageSourceBoundModule> modules = SimpleEnv.builder();
250     Scope javaLang = tli.lookupPackage(ImmutableList.of("java", "lang"));
251     if (javaLang == null) {
252       // TODO(cushon): add support for diagnostics without a source position, and make this one
253       // of those
254       throw new IllegalArgumentException("Could not find java.lang on bootclasspath");
255     }
256     CompoundScope topLevel = CompoundScope.base(tli.scope()).append(javaLang);
257     for (PreprocessedCompUnit unit : units) {
258       ImmutableList<String> packagename =
259           ImmutableList.copyOf(Splitter.on('/').omitEmptyStrings().split(unit.packageName()));
260       Scope packageScope = tli.lookupPackage(packagename);
261       CanonicalSymbolResolver importResolver =
262           new CanonicalResolver(
263               unit.packageName(),
264               CompoundEnv.<ClassSymbol, BoundClass>of(classPathEnv).append(ienv));
265       ImportScope importScope =
266           ImportIndex.create(log.withSource(unit.source()), importResolver, tli, unit.imports());
267       ImportScope wildImportScope = WildImportIndex.create(importResolver, tli, unit.imports());
268       MemberImportIndex memberImports =
269           new MemberImportIndex(unit.source(), importResolver, tli, unit.imports());
270       ImportScope scope = ImportScope.fromScope(topLevel).append(wildImportScope);
271       // Can be null if we're compiling a package-info.java for an empty package
272       if (packageScope != null) {
273         scope = scope.append(ImportScope.fromScope(packageScope));
274       }
275       scope = scope.append(importScope);
276       if (unit.module().isPresent()) {
277         ModDecl module = unit.module().get();
278         modules.put(
279             new ModuleSymbol(module.moduleName()),
280             new PackageSourceBoundModule(module, scope, memberImports, unit.source()));
281       }
282       for (SourceBoundClass type : unit.types()) {
283         env.put(type.sym(), new PackageSourceBoundClass(type, scope, memberImports, unit.source()));
284       }
285     }
286     return new BindPackagesResult(env.build(), modules.build());
287   }
288 
289   /** Binds the type hierarchy (superclasses and interfaces) for all classes in the compilation. */
bindHierarchy( TurbineLog log, Iterable<ClassSymbol> syms, final SimpleEnv<ClassSymbol, PackageSourceBoundClass> psenv, CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv)290   private static Env<ClassSymbol, SourceHeaderBoundClass> bindHierarchy(
291       TurbineLog log,
292       Iterable<ClassSymbol> syms,
293       final SimpleEnv<ClassSymbol, PackageSourceBoundClass> psenv,
294       CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv) {
295     ImmutableMap.Builder<
296             ClassSymbol, LazyEnv.Completer<ClassSymbol, HeaderBoundClass, SourceHeaderBoundClass>>
297         completers = ImmutableMap.builder();
298     for (ClassSymbol sym : syms) {
299       completers.put(
300           sym,
301           new LazyEnv.Completer<ClassSymbol, HeaderBoundClass, SourceHeaderBoundClass>() {
302             @Override
303             public SourceHeaderBoundClass complete(
304                 Env<ClassSymbol, HeaderBoundClass> henv, ClassSymbol sym) {
305               PackageSourceBoundClass base = psenv.getNonNull(sym);
306               return HierarchyBinder.bind(log.withSource(base.source()), sym, base, henv);
307             }
308           });
309     }
310     return new LazyEnv<>(completers.buildOrThrow(), classPathEnv);
311   }
312 
bindTypes( TurbineLog log, ImmutableSet<ClassSymbol> syms, Env<ClassSymbol, SourceHeaderBoundClass> shenv, Env<ClassSymbol, HeaderBoundClass> henv)313   private static Env<ClassSymbol, SourceTypeBoundClass> bindTypes(
314       TurbineLog log,
315       ImmutableSet<ClassSymbol> syms,
316       Env<ClassSymbol, SourceHeaderBoundClass> shenv,
317       Env<ClassSymbol, HeaderBoundClass> henv) {
318     SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
319     for (ClassSymbol sym : syms) {
320       SourceHeaderBoundClass base = shenv.getNonNull(sym);
321       builder.put(sym, TypeBinder.bind(log.withSource(base.source()), henv, sym, base));
322     }
323     return builder.build();
324   }
325 
canonicalizeTypes( ImmutableSet<ClassSymbol> syms, Env<ClassSymbol, SourceTypeBoundClass> stenv, Env<ClassSymbol, TypeBoundClass> tenv)326   private static Env<ClassSymbol, SourceTypeBoundClass> canonicalizeTypes(
327       ImmutableSet<ClassSymbol> syms,
328       Env<ClassSymbol, SourceTypeBoundClass> stenv,
329       Env<ClassSymbol, TypeBoundClass> tenv) {
330     SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
331     for (ClassSymbol sym : syms) {
332       SourceTypeBoundClass base = stenv.getNonNull(sym);
333       builder.put(sym, CanonicalTypeBinder.bind(sym, base, tenv));
334     }
335     return builder.build();
336   }
337 
bindModules( SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules, CompoundEnv<ClassSymbol, TypeBoundClass> env, CompoundEnv<ModuleSymbol, ModuleInfo> moduleEnv, Optional<String> moduleVersion, TurbineLog log)338   private static ImmutableList<SourceModuleInfo> bindModules(
339       SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules,
340       CompoundEnv<ClassSymbol, TypeBoundClass> env,
341       CompoundEnv<ModuleSymbol, ModuleInfo> moduleEnv,
342       Optional<String> moduleVersion,
343       TurbineLog log) {
344     // Allow resolution of modules in the current compilation. Currently this is only needed for
345     // version strings in requires directives.
346     moduleEnv =
347         moduleEnv.append(
348             new Env<ModuleSymbol, ModuleInfo>() {
349               @Override
350               public @Nullable ModuleInfo get(ModuleSymbol sym) {
351                 PackageSourceBoundModule info = modules.get(sym);
352                 if (info != null) {
353                   return new ModuleInfo(
354                       info.module().moduleName(),
355                       moduleVersion.orElse(null),
356                       /* flags= */ 0,
357                       /* annos= */ ImmutableList.of(),
358                       /* requires= */ ImmutableList.of(),
359                       /* exports= */ ImmutableList.of(),
360                       /* opens= */ ImmutableList.of(),
361                       /* uses= */ ImmutableList.of(),
362                       /* provides= */ ImmutableList.of());
363                 }
364                 return null;
365               }
366             });
367     ImmutableList.Builder<SourceModuleInfo> bound = ImmutableList.builder();
368     for (PackageSourceBoundModule module : modules.asMap().values()) {
369       bound.add(
370           ModuleBinder.bind(
371               module, env, moduleEnv, moduleVersion, log.withSource(module.source())));
372     }
373     return bound.build();
374   }
375 
constants( ImmutableSet<ClassSymbol> syms, Env<ClassSymbol, SourceTypeBoundClass> env, CompoundEnv<ClassSymbol, TypeBoundClass> baseEnv, TurbineLog log)376   private static Env<ClassSymbol, SourceTypeBoundClass> constants(
377       ImmutableSet<ClassSymbol> syms,
378       Env<ClassSymbol, SourceTypeBoundClass> env,
379       CompoundEnv<ClassSymbol, TypeBoundClass> baseEnv,
380       TurbineLog log) {
381 
382     // Prepare to lazily evaluate constant fields in each compilation unit.
383     // The laziness is necessary since constant fields can reference other
384     // constant fields.
385     ImmutableMap.Builder<FieldSymbol, LazyEnv.Completer<FieldSymbol, Const.Value, Const.Value>>
386         completers = ImmutableMap.builder();
387     for (ClassSymbol sym : syms) {
388       SourceTypeBoundClass info = env.getNonNull(sym);
389       for (FieldInfo field : info.fields()) {
390         if (!isConst(field)) {
391           continue;
392         }
393         completers.put(
394             field.sym(),
395             new LazyEnv.Completer<FieldSymbol, Const.Value, Const.Value>() {
396               @Override
397               public Const.@Nullable Value complete(
398                   Env<FieldSymbol, Const.Value> env1, FieldSymbol k) {
399                 try {
400                   return new ConstEvaluator(
401                           sym,
402                           sym,
403                           info.memberImports(),
404                           info.source(),
405                           info.scope(),
406                           env1,
407                           baseEnv,
408                           log.withSource(info.source()))
409                       .evalFieldInitializer(
410                           // we're processing fields bound from sources in the compilation
411                           requireNonNull(field.decl()).init().get(), field.type());
412                 } catch (LazyEnv.LazyBindingError e) {
413                   // fields initializers are allowed to reference the field being initialized,
414                   // but if they do they aren't constants
415                   return null;
416                 }
417               }
418             });
419       }
420     }
421 
422     // Create an environment of constant field values that combines
423     // lazily evaluated fields in the current compilation unit with
424     // constant fields in the classpath (which don't require evaluation).
425     Env<FieldSymbol, Const.Value> constenv =
426         new LazyEnv<>(
427             completers.buildOrThrow(), SimpleEnv.<FieldSymbol, Const.Value>builder().build());
428 
429     SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
430     for (ClassSymbol sym : syms) {
431       SourceTypeBoundClass base = env.getNonNull(sym);
432       builder.put(
433           sym, new ConstBinder(constenv, sym, baseEnv, base, log.withSource(base.source())).bind());
434     }
435     return builder.build();
436   }
437 
isConst(FieldInfo field)438   static boolean isConst(FieldInfo field) {
439     if ((field.access() & TurbineFlag.ACC_FINAL) == 0) {
440       return false;
441     }
442     if (field.decl() == null) {
443       return false;
444     }
445     final Optional<Tree.Expression> init = field.decl().init();
446     if (!init.isPresent()) {
447       return false;
448     }
449     switch (field.type().tyKind()) {
450       case PRIM_TY:
451         break;
452       case CLASS_TY:
453         if (((Type.ClassTy) field.type()).sym().equals(ClassSymbol.STRING)) {
454           break;
455         }
456         // fall through
457       default:
458         return false;
459     }
460     return true;
461   }
462 
463   /**
464    * Disambiguate annotations on field types and method return types that could be declaration or
465    * type annotations.
466    */
disambiguateTypeAnnotations( ImmutableSet<ClassSymbol> syms, Env<ClassSymbol, SourceTypeBoundClass> stenv, Env<ClassSymbol, TypeBoundClass> tenv)467   private static Env<ClassSymbol, SourceTypeBoundClass> disambiguateTypeAnnotations(
468       ImmutableSet<ClassSymbol> syms,
469       Env<ClassSymbol, SourceTypeBoundClass> stenv,
470       Env<ClassSymbol, TypeBoundClass> tenv) {
471     SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
472     for (ClassSymbol sym : syms) {
473       SourceTypeBoundClass base = stenv.getNonNull(sym);
474       builder.put(sym, DisambiguateTypeAnnotations.bind(base, tenv));
475     }
476     return builder.build();
477   }
478 
479   /** Statistics about annotation processing. */
480   @AutoValue
481   public abstract static class Statistics {
482 
483     /**
484      * The total elapsed time spent in {@link Processor#init} and {@link Processor#process} across
485      * all rounds for each annotation processor.
486      */
processingTime()487     public abstract ImmutableMap<String, Duration> processingTime();
488 
489     /**
490      * Serialized protos containing processor-specific metrics. Currently only supported for Dagger.
491      */
processorMetrics()492     public abstract ImmutableMap<String, byte[]> processorMetrics();
493 
create( ImmutableMap<String, Duration> processingTime, ImmutableMap<String, byte[]> processorMetrics)494     public static Statistics create(
495         ImmutableMap<String, Duration> processingTime,
496         ImmutableMap<String, byte[]> processorMetrics) {
497       return new AutoValue_Binder_Statistics(processingTime, processorMetrics);
498     }
499 
empty()500     public static Statistics empty() {
501       return create(ImmutableMap.of(), ImmutableMap.of());
502     }
503   }
504 
505   /** The result of binding: bound nodes for sources in the compilation, and the classpath. */
506   public static class BindingResult {
507     private final ImmutableMap<ClassSymbol, SourceTypeBoundClass> units;
508     private final ImmutableList<SourceModuleInfo> modules;
509     private final CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv;
510     private final TopLevelIndex tli;
511     private final ImmutableMap<String, SourceFile> generatedSources;
512     private final ImmutableMap<String, byte[]> generatedClasses;
513     private final Statistics statistics;
514 
BindingResult( ImmutableMap<ClassSymbol, SourceTypeBoundClass> units, ImmutableList<SourceModuleInfo> modules, CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv, TopLevelIndex tli, ImmutableMap<String, SourceFile> generatedSources, ImmutableMap<String, byte[]> generatedClasses, Statistics statistics)515     public BindingResult(
516         ImmutableMap<ClassSymbol, SourceTypeBoundClass> units,
517         ImmutableList<SourceModuleInfo> modules,
518         CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv,
519         TopLevelIndex tli,
520         ImmutableMap<String, SourceFile> generatedSources,
521         ImmutableMap<String, byte[]> generatedClasses,
522         Statistics statistics) {
523       this.units = units;
524       this.modules = modules;
525       this.classPathEnv = classPathEnv;
526       this.tli = tli;
527       this.generatedSources = generatedSources;
528       this.generatedClasses = generatedClasses;
529       this.statistics = statistics;
530     }
531 
532     /** Bound nodes for sources in the compilation. */
units()533     public ImmutableMap<ClassSymbol, SourceTypeBoundClass> units() {
534       return units;
535     }
536 
modules()537     public ImmutableList<SourceModuleInfo> modules() {
538       return modules;
539     }
540 
541     /** The classpath. */
classPathEnv()542     public CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv() {
543       return classPathEnv;
544     }
545 
tli()546     public TopLevelIndex tli() {
547       return tli;
548     }
549 
generatedSources()550     public ImmutableMap<String, SourceFile> generatedSources() {
551       return generatedSources;
552     }
553 
generatedClasses()554     public ImmutableMap<String, byte[]> generatedClasses() {
555       return generatedClasses;
556     }
557 
statistics()558     public Statistics statistics() {
559       return statistics;
560     }
561 
withGeneratedClasses(ImmutableMap<String, byte[]> generatedClasses)562     public BindingResult withGeneratedClasses(ImmutableMap<String, byte[]> generatedClasses) {
563       return new BindingResult(
564           units, modules, classPathEnv, tli, generatedSources, generatedClasses, statistics);
565     }
566 
withGeneratedSources(ImmutableMap<String, SourceFile> generatedSources)567     public BindingResult withGeneratedSources(ImmutableMap<String, SourceFile> generatedSources) {
568       return new BindingResult(
569           units, modules, classPathEnv, tli, generatedSources, generatedClasses, statistics);
570     }
571 
withStatistics(Statistics statistics)572     public BindingResult withStatistics(Statistics statistics) {
573       return new BindingResult(
574           units, modules, classPathEnv, tli, generatedSources, generatedClasses, statistics);
575     }
576   }
577 
Binder()578   private Binder() {}
579 }
580