diff --git a/java/dagger/internal/codegen/BindingGraphConverter.java b/java/dagger/internal/codegen/BindingGraphConverter.java index a1ec286809f..533f4344beb 100644 --- a/java/dagger/internal/codegen/BindingGraphConverter.java +++ b/java/dagger/internal/codegen/BindingGraphConverter.java @@ -47,10 +47,13 @@ final class BindingGraphConverter { private final BindingDeclarationFormatter bindingDeclarationFormatter; + private final CompilerOptions compilerOptions; @Inject - BindingGraphConverter(BindingDeclarationFormatter bindingDeclarationFormatter) { + BindingGraphConverter( + BindingDeclarationFormatter bindingDeclarationFormatter, CompilerOptions compilerOptions) { this.bindingDeclarationFormatter = bindingDeclarationFormatter; + this.compilerOptions = compilerOptions; } /** @@ -72,7 +75,7 @@ private final class Traverser extends ComponentTreeTraverser { private ComponentNode currentComponent; Traverser(BindingGraph graph) { - super(graph); + super(graph, compilerOptions); } @Override diff --git a/java/dagger/internal/codegen/BindingGraphFactory.java b/java/dagger/internal/codegen/BindingGraphFactory.java index 6647eb6c2ce..bcdafcf7d82 100644 --- a/java/dagger/internal/codegen/BindingGraphFactory.java +++ b/java/dagger/internal/codegen/BindingGraphFactory.java @@ -79,22 +79,26 @@ final class BindingGraphFactory { private final InjectBindingRegistry injectBindingRegistry; private final KeyFactory keyFactory; private final BindingFactory bindingFactory; + private final CompilerOptions compilerOptions; @Inject BindingGraphFactory( DaggerElements elements, InjectBindingRegistry injectBindingRegistry, KeyFactory keyFactory, - BindingFactory bindingFactory) { + BindingFactory bindingFactory, + CompilerOptions compilerOptions) { this.elements = elements; this.injectBindingRegistry = injectBindingRegistry; this.keyFactory = keyFactory; this.bindingFactory = bindingFactory; + this.compilerOptions = compilerOptions; } /** Creates a binding graph for a root component. */ BindingGraph create(ComponentDescriptor componentDescriptor) { - checkArgument(componentDescriptor.kind().isTopLevel()); + checkArgument( + componentDescriptor.kind().isTopLevel() || compilerOptions.aheadOfTimeSubcomponents()); return create(Optional.empty(), componentDescriptor); } diff --git a/java/dagger/internal/codegen/ComponentBindingExpressions.java b/java/dagger/internal/codegen/ComponentBindingExpressions.java index a78f6acb9cc..7f72b64ef5b 100644 --- a/java/dagger/internal/codegen/ComponentBindingExpressions.java +++ b/java/dagger/internal/codegen/ComponentBindingExpressions.java @@ -84,7 +84,7 @@ final class ComponentBindingExpressions { generatedComponentModel, subcomponentNames, componentRequirementFields, - new ReferenceReleasingManagerFields(graph, generatedComponentModel), + new ReferenceReleasingManagerFields(graph, generatedComponentModel, compilerOptions), new StaticSwitchingProviders(generatedComponentModel, types), optionalFactories, types, diff --git a/java/dagger/internal/codegen/ComponentDescriptor.java b/java/dagger/internal/codegen/ComponentDescriptor.java index dea137fc89d..b2fea631ac0 100644 --- a/java/dagger/internal/codegen/ComponentDescriptor.java +++ b/java/dagger/internal/codegen/ComponentDescriptor.java @@ -442,30 +442,38 @@ static final class Factory { private final Types types; private final DependencyRequestFactory dependencyRequestFactory; private final ModuleDescriptor.Factory moduleDescriptorFactory; + private final CompilerOptions compilerOptions; @Inject Factory( DaggerElements elements, Types types, DependencyRequestFactory dependencyRequestFactory, - ModuleDescriptor.Factory moduleDescriptorFactory) { + ModuleDescriptor.Factory moduleDescriptorFactory, + CompilerOptions compilerOptions) { this.elements = elements; this.types = types; this.dependencyRequestFactory = dependencyRequestFactory; this.moduleDescriptorFactory = moduleDescriptorFactory; + this.compilerOptions = compilerOptions; } /** * Returns a component descriptor for a type annotated with either {@link Component @Component} - * or {@link ProductionComponent @ProductionComponent}. + * or {@link ProductionComponent @ProductionComponent}. This is also compatible with {@link + * Subcomponent @Subcomponent} or {@link ProductionSubcomponent @ProductionSubcomponent} when + * generating ahead-of-time subcomponents. */ - ComponentDescriptor forComponent(TypeElement componentDefinitionType) { - Optional kind = Kind.forAnnotatedElement(componentDefinitionType); + ComponentDescriptor forComponent(TypeElement componentType) { + Optional kind = Kind.forAnnotatedElement(componentType); checkArgument( - kind.isPresent() && kind.get().isTopLevel(), - "%s must be annotated with @Component or @ProductionComponent", - componentDefinitionType); - return create(componentDefinitionType, kind.get(), Optional.empty()); + kind.isPresent(), "%s must have a component or subcomponent annotation", componentType); + if (!compilerOptions.aheadOfTimeSubcomponents()) { + checkArgument(kind.get().isTopLevel(), + "%s must be annotated with @Component or @ProductionComponent.", + componentType); + } + return create(componentType, kind.get(), Optional.empty()); } private ComponentDescriptor create( diff --git a/java/dagger/internal/codegen/ComponentModelBuilder.java b/java/dagger/internal/codegen/ComponentModelBuilder.java index 237c3bfa1e8..200efb09fb8 100644 --- a/java/dagger/internal/codegen/ComponentModelBuilder.java +++ b/java/dagger/internal/codegen/ComponentModelBuilder.java @@ -79,7 +79,24 @@ static GeneratedComponentModel buildComponentModel( types, elements, compilerOptions); - return new RootComponentModelBuilder( + if (graph.componentDescriptor().kind().isTopLevel()) { + return new RootComponentModelBuilder( + types, + elements, + graph, + generatedComponentModel, + subcomponentNames, + optionalFactories, + bindingExpressions, + componentRequirementFields, + builder) + .build(); + } + checkState( + compilerOptions.aheadOfTimeSubcomponents(), + "Calling 'buildComponentModel()' on %s when not generating ahead-of-time subcomponents.", + graph.componentDescriptor().componentDefinitionType()); + return new BaseSubcomponentModelBuilder( types, elements, graph, @@ -153,7 +170,7 @@ private ComponentModelBuilder( * called once (and will throw on successive invocations). If the component must be regenerated, * use a new instance. */ - protected final GeneratedComponentModel build() { + protected GeneratedComponentModel build() { checkState( !done, "ComponentModelBuilder has already built the GeneratedComponentModel for [%s].", @@ -387,6 +404,46 @@ private DeclaredType parentType() { } } + /** Builds the model for a top-level abstract base implementation of a subcomponent. */ + // TODO(b/72748365): Implement. + private static final class BaseSubcomponentModelBuilder extends ComponentModelBuilder { + private final GeneratedComponentModel generatedComponentModel; + + BaseSubcomponentModelBuilder( + DaggerTypes types, + Elements elements, + BindingGraph graph, + GeneratedComponentModel generatedComponentModel, + SubcomponentNames subcomponentNames, + OptionalFactories optionalFactories, + ComponentBindingExpressions bindingExpressions, + ComponentRequirementFields componentRequirementFields, + Optional builder) { + super( + types, + elements, + graph, + generatedComponentModel, + subcomponentNames, + optionalFactories, + bindingExpressions, + componentRequirementFields, + builder); + this.generatedComponentModel = generatedComponentModel; + } + + @Override + protected GeneratedComponentModel build() { + return generatedComponentModel; + } + + @Override + protected void addBuilderClass(TypeSpec builder) {} + + @Override + protected void addFactoryMethods() {} + } + /** Returns the list of {@link ParameterSpec}s for the corresponding graph's factory method. */ private static ImmutableList getFactoryMethodParameterSpecs(BindingGraph graph) { return graph diff --git a/java/dagger/internal/codegen/ComponentProcessingStep.java b/java/dagger/internal/codegen/ComponentProcessingStep.java index 0b5ba2699f6..62881c3d303 100644 --- a/java/dagger/internal/codegen/ComponentProcessingStep.java +++ b/java/dagger/internal/codegen/ComponentProcessingStep.java @@ -53,6 +53,7 @@ final class ComponentProcessingStep implements ProcessingStep { private final BindingGraphConverter bindingGraphConverter; private final BindingGraphPlugins validationPlugins; private final BindingGraphPlugins spiPlugins; + private final CompilerOptions compilerOptions; @Inject ComponentProcessingStep( @@ -65,7 +66,8 @@ final class ComponentProcessingStep implements ProcessingStep { ComponentGenerator componentGenerator, BindingGraphConverter bindingGraphConverter, @Validation BindingGraphPlugins validationPlugins, - BindingGraphPlugins spiPlugins) { + BindingGraphPlugins spiPlugins, + CompilerOptions compilerOptions) { this.messager = messager; this.componentValidator = componentValidator; this.builderValidator = builderValidator; @@ -76,6 +78,7 @@ final class ComponentProcessingStep implements ProcessingStep { this.bindingGraphConverter = bindingGraphConverter; this.validationPlugins = validationPlugins; this.spiPlugins = spiPlugins; + this.compilerOptions = compilerOptions; } @Override @@ -146,6 +149,25 @@ public ImmutableSet process( rejectedElements.add(componentTypeElement); } } + + if (compilerOptions.aheadOfTimeSubcomponents()) { + for (TypeElement subcomponentTypeElement : typesIn(subcomponentElements)) { + if (!subcomponentIsClean( + subcomponentTypeElement, reportsBySubcomponent, builderReportsBySubcomponent)) { + continue; + } + try { + ComponentDescriptor componentDescriptor = + componentDescriptorFactory.forComponent(subcomponentTypeElement); + BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor); + // TODO(b/72748365): Do subgraph validation. + generateComponent(bindingGraph); + } catch (TypeNotPresentException e) { + rejectedElements.add(subcomponentTypeElement); + } + } + } + return rejectedElements.build(); } @@ -212,15 +234,27 @@ private boolean isClean( return false; } for (Element element : report.referencedSubcomponents()) { - ValidationReport subcomponentBuilderReport = builderReportsBySubcomponent.get(element); - if (subcomponentBuilderReport != null && !subcomponentBuilderReport.isClean()) { - return false; - } - ValidationReport subcomponentReport = reportsBySubcomponent.get(element); - if (subcomponentReport != null && !subcomponentReport.isClean()) { + if (!subcomponentIsClean(element, reportsBySubcomponent, builderReportsBySubcomponent)) { return false; } } return true; } + + /** Returns true if the reports associated with the subcomponent are clean. */ + private boolean subcomponentIsClean( + Element subcomponentElement, + Map> reportsBySubcomponent, + Map> builderReportsBySubcomponent) { + ValidationReport subcomponentBuilderReport = + builderReportsBySubcomponent.get(subcomponentElement); + if (subcomponentBuilderReport != null && !subcomponentBuilderReport.isClean()) { + return false; + } + ValidationReport subcomponentReport = reportsBySubcomponent.get(subcomponentElement); + if (subcomponentReport != null && !subcomponentReport.isClean()) { + return false; + } + return true; + } } diff --git a/java/dagger/internal/codegen/ComponentTreeTraverser.java b/java/dagger/internal/codegen/ComponentTreeTraverser.java index 778c651e9ff..f79c1d0cb0f 100644 --- a/java/dagger/internal/codegen/ComponentTreeTraverser.java +++ b/java/dagger/internal/codegen/ComponentTreeTraverser.java @@ -74,9 +74,10 @@ public class ComponentTreeTraverser { private final Deque bindingGraphPath = new ArrayDeque<>(); /** Constructs a traverser for a root (component, not subcomponent) binding graph. */ - public ComponentTreeTraverser(BindingGraph rootGraph) { + public ComponentTreeTraverser(BindingGraph rootGraph, CompilerOptions compilerOptions) { checkArgument( - rootGraph.componentDescriptor().kind().isTopLevel(), + rootGraph.componentDescriptor().kind().isTopLevel() + || compilerOptions.aheadOfTimeSubcomponents(), "only top-level graphs can be traversed, not %s", rootGraph.componentDescriptor().componentDefinitionType().getQualifiedName()); bindingGraphPath.add(rootGraph); diff --git a/java/dagger/internal/codegen/DaggerKythePlugin.java b/java/dagger/internal/codegen/DaggerKythePlugin.java index 98d210cc63a..26e0a8ce410 100644 --- a/java/dagger/internal/codegen/DaggerKythePlugin.java +++ b/java/dagger/internal/codegen/DaggerKythePlugin.java @@ -155,6 +155,7 @@ public void run( DaggerDaggerKythePlugin_PluginComponent.builder() .types(JavacTypes.instance(javaContext)) .elements(JavacElements.instance(javaContext)) + .compilerOptions(KytheBindingGraphFactory.createCompilerOptions()) .build() .inject(this); } @@ -168,8 +169,15 @@ interface PluginComponent { @Component.Builder interface Builder { - @BindsInstance Builder types(Types types); - @BindsInstance Builder elements(Elements elements); + @BindsInstance + Builder types(Types types); + + @BindsInstance + Builder elements(Elements elements); + + @BindsInstance + Builder compilerOptions(CompilerOptions compilerOptions); + PluginComponent build(); } } diff --git a/java/dagger/internal/codegen/KytheBindingGraphFactory.java b/java/dagger/internal/codegen/KytheBindingGraphFactory.java index 0d49637defd..984d8531c74 100644 --- a/java/dagger/internal/codegen/KytheBindingGraphFactory.java +++ b/java/dagger/internal/codegen/KytheBindingGraphFactory.java @@ -41,11 +41,13 @@ final class KytheBindingGraphFactory { private final BindingGraphFactory bindingGraphFactory; @Inject - KytheBindingGraphFactory(Types types, Elements elements) { + KytheBindingGraphFactory(Types types, Elements elements, CompilerOptions compilerOptions) { DaggerElements daggerElements = new DaggerElements(elements, types); DaggerTypes daggerTypes = new DaggerTypes(types, daggerElements); - this.componentDescriptorFactory = createComponentDescriptorFactory(daggerElements, daggerTypes); - this.bindingGraphFactory = createBindingGraphFactory(daggerTypes, daggerElements); + this.componentDescriptorFactory = + createComponentDescriptorFactory(daggerElements, daggerTypes, compilerOptions); + this.bindingGraphFactory = + createBindingGraphFactory(daggerTypes, daggerElements, compilerOptions); } /** @@ -60,8 +62,25 @@ Optional create(TypeElement type) { return Optional.empty(); } + /** Creates the {@link CompilerOptions} for use during {@link BindingGraph} construction. */ + static CompilerOptions createCompilerOptions() { + return CompilerOptions.builder() + .usesProducers(true) + .writeProducerNameInToken(true) + .nullableValidationKind(Diagnostic.Kind.NOTE) + .privateMemberValidationKind(Diagnostic.Kind.NOTE) + .staticMemberValidationKind(Diagnostic.Kind.NOTE) + .ignorePrivateAndStaticInjectionForComponent(false) + .scopeCycleValidationType(ValidationType.NONE) + .warnIfInjectionFactoryNotGeneratedUpstream(false) + .fastInit(false) + .experimentalAndroidMode2(false) + .aheadOfTimeSubcomponents(false) + .build(); + } + private static ComponentDescriptor.Factory createComponentDescriptorFactory( - DaggerElements elements, DaggerTypes types) { + DaggerElements elements, DaggerTypes types, CompilerOptions compilerOptions) { KeyFactory keyFactory = new KeyFactory(types, elements); DependencyRequestFactory dependencyRequestFactory = new DependencyRequestFactory(keyFactory, types); @@ -85,29 +104,15 @@ private static ComponentDescriptor.Factory createComponentDescriptorFactory( subcomponentDeclarationFactory, optionalBindingDeclarationFactory); return new ComponentDescriptor.Factory( - elements, types, dependencyRequestFactory, moduleDescriptorFactory); + elements, types, dependencyRequestFactory, moduleDescriptorFactory, compilerOptions); } private static BindingGraphFactory createBindingGraphFactory( - DaggerTypes types, DaggerElements elements) { + DaggerTypes types, DaggerElements elements, CompilerOptions compilerOptions) { KeyFactory keyFactory = new KeyFactory(types, elements); DependencyRequestFactory dependencyRequestFactory = new DependencyRequestFactory(keyFactory, types); Messager messager = new NullMessager(); - CompilerOptions compilerOptions = - CompilerOptions.builder() - .usesProducers(true) - .writeProducerNameInToken(true) - .nullableValidationKind(Diagnostic.Kind.NOTE) - .privateMemberValidationKind(Diagnostic.Kind.NOTE) - .staticMemberValidationKind(Diagnostic.Kind.NOTE) - .ignorePrivateAndStaticInjectionForComponent(false) - .scopeCycleValidationType(ValidationType.NONE) - .warnIfInjectionFactoryNotGeneratedUpstream(false) - .fastInit(false) - .experimentalAndroidMode2(false) - .aheadOfTimeSubcomponents(false) - .build(); BindingFactory bindingFactory = new BindingFactory(types, elements, keyFactory, dependencyRequestFactory); @@ -124,7 +129,8 @@ private static BindingGraphFactory createBindingGraphFactory( bindingFactory, compilerOptions); - return new BindingGraphFactory(elements, injectBindingRegistry, keyFactory, bindingFactory); + return new BindingGraphFactory( + elements, injectBindingRegistry, keyFactory, bindingFactory, compilerOptions); } private static class NullMessager implements Messager { diff --git a/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java b/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java index fe6962184a4..0a42fb2accb 100644 --- a/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java +++ b/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java @@ -56,10 +56,14 @@ public class ReferenceReleasingManagerFields { private final GeneratedComponentModel generatedComponentModel; ReferenceReleasingManagerFields( - BindingGraph graph, GeneratedComponentModel generatedComponentModel) { + BindingGraph graph, + GeneratedComponentModel generatedComponentModel, + CompilerOptions compilerOptions) { this.graph = checkNotNull(graph); this.generatedComponentModel = checkNotNull(generatedComponentModel); - checkArgument(graph.componentDescriptor().kind().isTopLevel()); + if (!compilerOptions.aheadOfTimeSubcomponents()) { + checkArgument(graph.componentDescriptor().kind().isTopLevel()); + } } /**