diff --git a/java/dagger/internal/codegen/binding/AssistedFactoryBinding.java b/java/dagger/internal/codegen/binding/AssistedFactoryBinding.java index 868d378b743..21220e65491 100644 --- a/java/dagger/internal/codegen/binding/AssistedFactoryBinding.java +++ b/java/dagger/internal/codegen/binding/AssistedFactoryBinding.java @@ -26,6 +26,7 @@ import dagger.internal.codegen.model.Key; import dagger.internal.codegen.model.RequestKind; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#ASSISTED_FACTORY}. */ @CheckReturnValue @@ -37,8 +38,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/AssistedInjectionBinding.java b/java/dagger/internal/codegen/binding/AssistedInjectionBinding.java index 5dd2a5bbde3..b5fef76eae3 100644 --- a/java/dagger/internal/codegen/binding/AssistedInjectionBinding.java +++ b/java/dagger/internal/codegen/binding/AssistedInjectionBinding.java @@ -28,6 +28,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#ASSISTED_INJECTION}. */ @CheckReturnValue @@ -39,8 +40,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/Binding.java b/java/dagger/internal/codegen/binding/Binding.java index d17cdd76a83..d7064852139 100644 --- a/java/dagger/internal/codegen/binding/Binding.java +++ b/java/dagger/internal/codegen/binding/Binding.java @@ -17,6 +17,7 @@ package dagger.internal.codegen.binding; import dagger.internal.codegen.model.DependencyRequest; +import java.util.Optional; /** * An abstract type for classes representing a Dagger binding. Particularly, contains the element @@ -25,9 +26,16 @@ * subtypes. */ public abstract class Binding extends BindingDeclaration { + /** Returns the optional {@link BindingType}. */ + abstract Optional optionalBindingType(); /** The {@link BindingType} of this binding. */ - public abstract BindingType bindingType(); + public final BindingType bindingType() { + if (optionalBindingType().isPresent()) { + return optionalBindingType().get(); + } + throw new AssertionError("bindingType() is not set: " + this); + } /** The {@link FrameworkType} of this binding. */ public final FrameworkType frameworkType() { diff --git a/java/dagger/internal/codegen/binding/BindingFactory.java b/java/dagger/internal/codegen/binding/BindingFactory.java index 9876201a8bb..8a57abfb299 100644 --- a/java/dagger/internal/codegen/binding/BindingFactory.java +++ b/java/dagger/internal/codegen/binding/BindingFactory.java @@ -239,10 +239,7 @@ public ProductionBinding producesMethodBinding(XMethodElement method, XTypeEleme public MultiboundMapBinding multiboundMap( Key key, Iterable multibindingContributions) { return MultiboundMapBinding.builder() - .bindingType( - multibindingRequiresProduction(key, multibindingContributions) - ? BindingType.PRODUCTION - : BindingType.PROVISION) + .optionalBindingType(multibindingBindingType(key, multibindingContributions)) .key(key) .dependencies( dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions)) @@ -257,29 +254,36 @@ public MultiboundMapBinding multiboundMap( public MultiboundSetBinding multiboundSet( Key key, Iterable multibindingContributions) { return MultiboundSetBinding.builder() - .bindingType( - multibindingRequiresProduction(key, multibindingContributions) - ? BindingType.PRODUCTION - : BindingType.PROVISION) + .optionalBindingType(multibindingBindingType(key, multibindingContributions)) .key(key) .dependencies( dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions)) .build(); } - private boolean multibindingRequiresProduction( + private Optional multibindingBindingType( Key key, Iterable multibindingContributions) { if (MapType.isMap(key)) { MapType mapType = MapType.from(key); if (mapType.valuesAreTypeOf(TypeNames.PRODUCER) || mapType.valuesAreTypeOf(TypeNames.PRODUCED)) { - return true; + return Optional.of(BindingType.PRODUCTION); } } else if (SetType.isSet(key) && SetType.from(key).elementsAreTypeOf(TypeNames.PRODUCED)) { - return true; + return Optional.of(BindingType.PRODUCTION); + } + if (Iterables.any( + multibindingContributions, + binding -> binding.optionalBindingType().equals(Optional.of(BindingType.PRODUCTION)))) { + return Optional.of(BindingType.PRODUCTION); } return Iterables.any( - multibindingContributions, binding -> binding.bindingType().equals(BindingType.PRODUCTION)); + multibindingContributions, + binding -> binding.optionalBindingType().isEmpty()) + // If a dependency is missing a BindingType then we can't determine the BindingType of this + // binding yet since it may end up depending on a production type. + ? Optional.empty() + : Optional.of(BindingType.PROVISION); } /** @@ -380,6 +384,11 @@ SubcomponentCreatorBinding subcomponentCreatorBinding( return SubcomponentCreatorBinding.builder().key(subcomponentDeclaration.key()).build(); } + /** Returns a {@link BindingKind#DELEGATE} binding. */ + DelegateBinding delegateBinding(DelegateDeclaration delegateDeclaration) { + return delegateBinding(delegateDeclaration, Optional.empty()); + } + /** * Returns a {@link BindingKind#DELEGATE} binding. * @@ -388,23 +397,31 @@ SubcomponentCreatorBinding subcomponentCreatorBinding( */ DelegateBinding delegateBinding( DelegateDeclaration delegateDeclaration, ContributionBinding actualBinding) { - return delegateBinding(delegateDeclaration, Optional.of(actualBinding)); + return delegateBinding(delegateDeclaration, delegateBindingType(Optional.of(actualBinding))); } private DelegateBinding delegateBinding( - DelegateDeclaration delegateDeclaration, Optional actualBinding) { - BindingType bindingType = delegateBindingType(actualBinding); + DelegateDeclaration delegateDeclaration, Optional optionalBindingType) { return DelegateBinding.builder() .contributionType(delegateDeclaration.contributionType()) .bindingElement(delegateDeclaration.bindingElement().get()) .contributingModule(delegateDeclaration.contributingModule().get()) .delegateRequest(delegateDeclaration.delegateRequest()) .nullability(Nullability.of(delegateDeclaration.bindingElement().get())) - .bindingType(bindingType) + .optionalBindingType(optionalBindingType) .key( - bindingType == BindingType.PRODUCTION - ? keyFactory.forDelegateBinding(delegateDeclaration, TypeNames.PRODUCER) - : keyFactory.forDelegateBinding(delegateDeclaration, TypeNames.PROVIDER)) + optionalBindingType.isEmpty() + // This is used by BindingGraphFactory which passes in an empty optionalBindingType. + // In this case, multibound map contributions will always return the key type + // without framework types, i.e. Map. + ? delegateDeclaration.key() + // This is used by LegacyBindingGraphFactory, which passes in a non-empty + // optionalBindingType. Then, KeyFactory decides whether or not multibound map + // contributions should include the factory type based on the compiler flag, + // -Adagger.useFrameworkTypeInMapMultibindingContributionKey. + : optionalBindingType.get() == BindingType.PRODUCTION + ? keyFactory.forDelegateBinding(delegateDeclaration, TypeNames.PRODUCER) + : keyFactory.forDelegateBinding(delegateDeclaration, TypeNames.PROVIDER)) .scope(injectionAnnotations.getScope(delegateDeclaration.bindingElement().get())) .build(); } @@ -414,44 +431,54 @@ private DelegateBinding delegateBinding( * no binding that satisfies the {@code @Binds} declaration. */ public DelegateBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) { - return delegateBinding(delegateDeclaration, Optional.empty()); + return delegateBinding(delegateDeclaration, Optional.of(BindingType.PROVISION)); } - private BindingType delegateBindingType(Optional actualBinding) { + private Optional delegateBindingType(Optional actualBinding) { if (actualBinding.isEmpty()) { - return BindingType.PROVISION; + return Optional.empty(); } checkArgument(actualBinding.get().bindingType() != BindingType.MEMBERS_INJECTION); - return actualBinding.get().bindingType(); + return Optional.of(actualBinding.get().bindingType()); } - /** - * Returns an {@link BindingKind#OPTIONAL} binding for {@code key}. - * - * @param requestKind the kind of request for the optional binding - * @param underlyingKeyBindings the possibly empty set of bindings that exist in the component for - * the underlying (non-optional) key - */ /** Returns an {@link BindingKind#OPTIONAL} present binding for {@code key}. */ OptionalBinding syntheticPresentOptionalDeclaration( Key key, ImmutableCollection optionalContributions) { checkArgument(!optionalContributions.isEmpty()); - RequestKind requestKind = getRequestKind(OptionalType.from(key).valueType()); - boolean isProduction = - optionalContributions.stream() - .anyMatch(binding -> binding.bindingType() == BindingType.PRODUCTION) - || requestKind.equals(RequestKind.PRODUCER) // handles producerFromProvider cases - || requestKind.equals(RequestKind.PRODUCED); // handles producerFromProvider cases return OptionalBinding.builder() - .bindingType(isProduction ? BindingType.PRODUCTION : BindingType.PROVISION) + .optionalBindingType(presentOptionalBindingType(key, optionalContributions)) .key(key) .delegateRequest(dependencyRequestFactory.forSyntheticPresentOptionalBinding(key)) .build(); } + private Optional presentOptionalBindingType( + Key key, ImmutableCollection optionalContributions) { + RequestKind requestKind = getRequestKind(OptionalType.from(key).valueType()); + if (requestKind.equals(RequestKind.PRODUCER) // handles producerFromProvider cases + || requestKind.equals(RequestKind.PRODUCED)) { // handles producerFromProvider cases + return Optional.of(BindingType.PRODUCTION); + } + if (optionalContributions.stream() + .filter(binding -> binding.optionalBindingType().isPresent()) + .anyMatch(binding -> binding.bindingType() == BindingType.PRODUCTION)) { + return Optional.of(BindingType.PRODUCTION); + } + return optionalContributions.stream() + .anyMatch(binding -> binding.optionalBindingType().isEmpty()) + // If a dependency is missing a BindingType then we can't determine the BindingType of this + // binding yet since it may end up depending on a production type. + ? Optional.empty() + : Optional.of(BindingType.PROVISION); + } + /** Returns an {@link BindingKind#OPTIONAL} absent binding for {@code key}. */ OptionalBinding syntheticAbsentOptionalDeclaration(Key key) { - return OptionalBinding.builder().key(key).bindingType(BindingType.PROVISION).build(); + return OptionalBinding.builder() + .key(key) + .optionalBindingType(Optional.of(BindingType.PROVISION)) + .build(); } /** Returns a {@link BindingKind#MEMBERS_INJECTOR} binding. */ diff --git a/java/dagger/internal/codegen/binding/BindingGraphFactory.java b/java/dagger/internal/codegen/binding/BindingGraphFactory.java index d2e9ae328c9..1a7ea5e23f1 100644 --- a/java/dagger/internal/codegen/binding/BindingGraphFactory.java +++ b/java/dagger/internal/codegen/binding/BindingGraphFactory.java @@ -58,7 +58,6 @@ import dagger.internal.codegen.model.Key; import dagger.internal.codegen.model.Scope; import java.util.ArrayDeque; -import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -122,6 +121,7 @@ private BindingGraph createBindingGraph( unreachableNodes(network.asGraph(), resolver.componentNode).forEach(network::removeNode); } + network = BindingGraphTransformations.withFixedBindingTypes(network); return BindingGraph.create( ImmutableNetwork.copyOf(network), createFullBindingGraph); @@ -137,7 +137,6 @@ private final class Resolver { final Map resolvedContributionBindings = new LinkedHashMap<>(); final Map resolvedMembersInjectionBindings = new LinkedHashMap<>(); final RequiresResolutionChecker requiresResolutionChecker = new RequiresResolutionChecker(); - final Deque cycleStack = new ArrayDeque<>(); final Queue subcomponentsToResolve = new ArrayDeque<>(); Resolver(ComponentDescriptor componentDescriptor) { @@ -383,48 +382,10 @@ private ImmutableSet createDelegateBindings( ImmutableSet delegateDeclarations) { ImmutableSet.Builder builder = ImmutableSet.builder(); for (DelegateDeclaration delegateDeclaration : delegateDeclarations) { - builder.add(createDelegateBinding(delegateDeclaration)); + builder.add(bindingFactory.delegateBinding(delegateDeclaration)); } return builder.build(); } - - /** - * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved - * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate - * bindings for the dependency key, there should still be only one binding for the delegate key. - */ - private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) { - Key delegateKey = delegateDeclaration.delegateRequest().key(); - if (cycleStack.contains(delegateKey)) { - return bindingFactory.unresolvedDelegateBinding(delegateDeclaration); - } - - ResolvedBindings resolvedDelegate; - try { - cycleStack.push(delegateKey); - resolvedDelegate = lookUpBindings(delegateKey); - } finally { - cycleStack.pop(); - } - if (resolvedDelegate.bindings().isEmpty()) { - // This is guaranteed to result in a missing binding error, so it doesn't matter if the - // binding is a Provision or Production, except if it is a @IntoMap method, in which - // case the key will be of type Map>, which will be "upgraded" into a - // Map> if it's requested in a ProductionComponent. This may result in a - // strange error, that the RHS needs to be provided with an @Inject or @Provides - // annotated method, but a user should be able to figure out if a @Produces annotation - // is needed. - // TODO(gak): revisit how we model missing delegates if/when we clean up how we model - // binding declarations - return bindingFactory.unresolvedDelegateBinding(delegateDeclaration); - } - // It doesn't matter which of these is selected, since they will later on produce a - // duplicate binding error. - ContributionBinding explicitDelegate = - (ContributionBinding) resolvedDelegate.bindings().iterator().next(); - return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate); - } - /** * Returns a {@link BindingNode} for the given binding that is owned by an ancestor component, * if one exists. Otherwise returns {@link Optional#empty()}. diff --git a/java/dagger/internal/codegen/binding/BindingGraphTransformations.java b/java/dagger/internal/codegen/binding/BindingGraphTransformations.java new file mode 100644 index 00000000000..405d6b25ed9 --- /dev/null +++ b/java/dagger/internal/codegen/binding/BindingGraphTransformations.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Dagger Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dagger.internal.codegen.binding; + +import static com.google.common.base.Preconditions.checkState; +import static dagger.internal.codegen.extension.DaggerStreams.instancesOf; +import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.common.graph.EndpointPair; +import com.google.common.graph.MutableNetwork; +import com.google.common.graph.Network; +import com.google.common.graph.NetworkBuilder; +import dagger.internal.codegen.base.TarjanSCCs; +import dagger.internal.codegen.model.BindingGraph.Edge; +import dagger.internal.codegen.model.BindingGraph.Node; +import java.util.Map; + +/** Transformations on the binding graph network. */ +final class BindingGraphTransformations { + /** Returns a network where {@link BindingType} is present for all binding nodes. */ + static MutableNetwork withFixedBindingTypes(MutableNetwork network) { + ImmutableSet bindingsToFix = bindingsWithMissingBindingTypes(network); + if (bindingsToFix.isEmpty()) { + return network; + } + + MutableNetwork fixedNetwork = withFixedBindingTypes(network, bindingsToFix); + + // Check that all bindings now have a BindingType in the fixed network. + checkState(bindingsWithMissingBindingTypes(fixedNetwork).isEmpty()); + return fixedNetwork; + } + + private static MutableNetwork withFixedBindingTypes( + Network network, ImmutableSet bindingsToFix) { + // Topologically sort the bindings so that we're guaranteed all dependencies of a binding are + // fixed before the bindings itself is fixed. + ImmutableList> topologicallySortedBindingsToFix = + TarjanSCCs.compute( + bindingsToFix, + binding -> + network.successors(binding).stream() + .flatMap(instancesOf(BindingNode.class)) + // Filter because we only care about direct dependencies on bindings that need + // to be fixed. There might be other cycles through nodes that already have a + // type, but those don't matter because it won't affect how we will fix the + // types for these bindings. + .filter(bindingsToFix::contains) + .collect(toImmutableSet())); + + Map replacements = + Maps.newHashMapWithExpectedSize(bindingsToFix.size()); + for (ImmutableSet connectedBindings : topologicallySortedBindingsToFix) { + BindingType successorBindingType = + connectedBindings.stream() + .flatMap(binding -> network.successors(binding).stream()) + .flatMap(instancesOf(BindingNode.class)) + .filter(binding -> !connectedBindings.contains(binding)) + .map(binding -> replacements.getOrDefault(binding, binding)) + .anyMatch(BindingNode::isProduction) + ? BindingType.PRODUCTION + : BindingType.PROVISION; + for (BindingNode bindingNode : connectedBindings) { + replacements.put(bindingNode, bindingNode.withBindingType(successorBindingType)); + } + } + return withReplacedBindings(network, ImmutableMap.copyOf(replacements)); + } + + private static ImmutableSet bindingsWithMissingBindingTypes( + Network network) { + return network.nodes().stream() + .flatMap(instancesOf(BindingNode.class)) + .filter(binding -> binding.delegate().optionalBindingType().isEmpty()) + .collect(toImmutableSet()); + } + + // Note: This method creates an entirely new network rather than replacing individual nodes and + // edges in the original network. We can reconsider this choice, e.g. if it turns out to be + // too inefficient, but my initial thought is that this approach is a bit nicer because it + // maintains the original node and edge iteration order, which could be nice for debugging. + private static MutableNetwork withReplacedBindings( + Network network, ImmutableMap replacementNodes) { + MutableNetwork newNetwork = NetworkBuilder.from(network).build(); + for (Node node : network.nodes()) { + newNetwork.addNode(replacementNodes.containsKey(node) ? replacementNodes.get(node) : node); + } + for (Edge edge : network.edges()) { + EndpointPair incidentNodes = network.incidentNodes(edge); + Node source = incidentNodes.source(); + Node target = incidentNodes.target(); + newNetwork.addEdge( + replacementNodes.containsKey(source) ? replacementNodes.get(source) : source, + replacementNodes.containsKey(target) ? replacementNodes.get(target) : target, + edge); + } + return newNetwork; + } + + private BindingGraphTransformations() {} +} diff --git a/java/dagger/internal/codegen/binding/BindingNode.java b/java/dagger/internal/codegen/binding/BindingNode.java index 45c06e6cb24..9818c39ff14 100644 --- a/java/dagger/internal/codegen/binding/BindingNode.java +++ b/java/dagger/internal/codegen/binding/BindingNode.java @@ -115,6 +115,16 @@ public final String toString() { return declarationFormatter.format(delegate()); } + public BindingNode withBindingType(BindingType bindingType) { + return create( + componentPath(), + ((ContributionBinding) delegate()).withBindingType(bindingType), + multibindingDeclarations(), + optionalBindingDeclarations(), + subcomponentDeclarations(), + declarationFormatter); + } + static final class Factory { private final DeclarationFormatter declarationFormatter; @@ -148,15 +158,31 @@ private BindingNode create( ImmutableSet multibindingDeclarations, ImmutableSet optionalBindingDeclarations, ImmutableSet subcomponentDeclarations) { - BindingNode node = - new AutoValue_BindingNode( - component, - delegate, - multibindingDeclarations, - optionalBindingDeclarations, - subcomponentDeclarations); - node.declarationFormatter = declarationFormatter; - return node; + return BindingNode.create( + component, + delegate, + multibindingDeclarations, + optionalBindingDeclarations, + subcomponentDeclarations, + declarationFormatter); } } + + private static BindingNode create( + ComponentPath component, + Binding delegate, + ImmutableSet multibindingDeclarations, + ImmutableSet optionalBindingDeclarations, + ImmutableSet subcomponentDeclarations, + DeclarationFormatter declarationFormatter) { + BindingNode node = + new AutoValue_BindingNode( + component, + delegate, + multibindingDeclarations, + optionalBindingDeclarations, + subcomponentDeclarations); + node.declarationFormatter = declarationFormatter; + return node; + } } diff --git a/java/dagger/internal/codegen/binding/BoundInstanceBinding.java b/java/dagger/internal/codegen/binding/BoundInstanceBinding.java index 41cba7777da..e974de23413 100644 --- a/java/dagger/internal/codegen/binding/BoundInstanceBinding.java +++ b/java/dagger/internal/codegen/binding/BoundInstanceBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#BOUND_INSTANCE}. */ @CheckReturnValue @@ -35,8 +36,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/ComponentBinding.java b/java/dagger/internal/codegen/binding/ComponentBinding.java index 2840be45f6d..a5eda78d4c9 100644 --- a/java/dagger/internal/codegen/binding/ComponentBinding.java +++ b/java/dagger/internal/codegen/binding/ComponentBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#COMPONENT}. */ @CheckReturnValue @@ -35,8 +36,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/ComponentDependencyBinding.java b/java/dagger/internal/codegen/binding/ComponentDependencyBinding.java index cd9d10a1531..9b52a2c2085 100644 --- a/java/dagger/internal/codegen/binding/ComponentDependencyBinding.java +++ b/java/dagger/internal/codegen/binding/ComponentDependencyBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#COMPONENT_DEPENDENCY}. */ @CheckReturnValue @@ -35,8 +36,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/ComponentDependencyProductionBinding.java b/java/dagger/internal/codegen/binding/ComponentDependencyProductionBinding.java index 63103bc2d00..c646accf454 100644 --- a/java/dagger/internal/codegen/binding/ComponentDependencyProductionBinding.java +++ b/java/dagger/internal/codegen/binding/ComponentDependencyProductionBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#COMPONENT_PRODUCTION}. */ @CheckReturnValue @@ -35,8 +36,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PRODUCTION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PRODUCTION); } @Override diff --git a/java/dagger/internal/codegen/binding/ComponentDependencyProvisionBinding.java b/java/dagger/internal/codegen/binding/ComponentDependencyProvisionBinding.java index dd917663046..5ae15e1b6d7 100644 --- a/java/dagger/internal/codegen/binding/ComponentDependencyProvisionBinding.java +++ b/java/dagger/internal/codegen/binding/ComponentDependencyProvisionBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#COMPONENT_PROVISION}. */ @CheckReturnValue @@ -35,8 +36,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/ContributionBinding.java b/java/dagger/internal/codegen/binding/ContributionBinding.java index d3307b8c328..9cfc722d2f3 100644 --- a/java/dagger/internal/codegen/binding/ContributionBinding.java +++ b/java/dagger/internal/codegen/binding/ContributionBinding.java @@ -16,6 +16,7 @@ package dagger.internal.codegen.binding; +import static com.google.common.base.Preconditions.checkState; import static dagger.internal.codegen.xprocessing.XElements.asMethod; import static dagger.internal.codegen.xprocessing.XElements.isAbstract; import static dagger.internal.codegen.xprocessing.XElements.isStatic; @@ -116,6 +117,31 @@ public final XType contributedType() { public abstract Builder toBuilder(); + /** Returns a new {@link ContributionBinding} with the given {@link BindingType}. */ + final ContributionBinding withBindingType(BindingType bindingType) { + checkState(optionalBindingType().isEmpty()); + switch (kind()) { + case DELEGATE: + return ((DelegateBinding) this).toBuilder() + .optionalBindingType(Optional.of(bindingType)) + .build(); + case OPTIONAL: + return ((OptionalBinding) this).toBuilder() + .optionalBindingType(Optional.of(bindingType)) + .build(); + case MULTIBOUND_MAP: + return ((MultiboundMapBinding) this).toBuilder() + .optionalBindingType(Optional.of(bindingType)) + .build(); + case MULTIBOUND_SET: + return ((MultiboundSetBinding) this).toBuilder() + .optionalBindingType(Optional.of(bindingType)) + .build(); + default: + throw new AssertionError("Unexpected binding kind: " + kind()); + } + } + /** * Base builder for {@link com.google.auto.value.AutoValue @AutoValue} subclasses of {@link * ContributionBinding}. diff --git a/java/dagger/internal/codegen/binding/DelegateBinding.java b/java/dagger/internal/codegen/binding/DelegateBinding.java index 91cb27020b6..b6f7b9ce0dc 100644 --- a/java/dagger/internal/codegen/binding/DelegateBinding.java +++ b/java/dagger/internal/codegen/binding/DelegateBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#DELEGATE}. */ @CheckReturnValue @@ -68,7 +69,7 @@ static Builder builder() { abstract static class Builder extends ContributionBinding.Builder { abstract Builder delegateRequest(DependencyRequest delegateRequest); - abstract Builder bindingType(BindingType bindingType); + abstract Builder optionalBindingType(Optional bindingType); abstract Builder contributionType(ContributionType contributionType); diff --git a/java/dagger/internal/codegen/binding/InjectionBinding.java b/java/dagger/internal/codegen/binding/InjectionBinding.java index cf4fb101ab3..657b392b3ce 100644 --- a/java/dagger/internal/codegen/binding/InjectionBinding.java +++ b/java/dagger/internal/codegen/binding/InjectionBinding.java @@ -28,6 +28,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#INJECTION}. */ @CheckReturnValue @@ -39,8 +40,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java index 1c692db4336..17580ee14f1 100644 --- a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java +++ b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java @@ -58,8 +58,8 @@ public Optional contributingModule() { public abstract ImmutableSortedSet injectionSites(); @Override - public BindingType bindingType() { - return BindingType.MEMBERS_INJECTION; + public Optional optionalBindingType() { + return Optional.of(BindingType.MEMBERS_INJECTION); } @Override diff --git a/java/dagger/internal/codegen/binding/MembersInjectorBinding.java b/java/dagger/internal/codegen/binding/MembersInjectorBinding.java index ec0072b4946..cd9a68d3535 100644 --- a/java/dagger/internal/codegen/binding/MembersInjectorBinding.java +++ b/java/dagger/internal/codegen/binding/MembersInjectorBinding.java @@ -28,6 +28,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#MEMBERS_INJECTOR}. */ @CheckReturnValue @@ -39,8 +40,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/MultiboundMapBinding.java b/java/dagger/internal/codegen/binding/MultiboundMapBinding.java index 39e10de0949..0a8c971c557 100644 --- a/java/dagger/internal/codegen/binding/MultiboundMapBinding.java +++ b/java/dagger/internal/codegen/binding/MultiboundMapBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#MULTIBOUND_MAP}. */ @CheckReturnValue @@ -65,6 +66,6 @@ abstract static class Builder extends ContributionBinding.Builder { abstract Builder dependencies(ImmutableSet dependencies); - abstract Builder bindingType(BindingType bindingType); + abstract Builder optionalBindingType(Optional optionalBindingType); } } diff --git a/java/dagger/internal/codegen/binding/MultiboundSetBinding.java b/java/dagger/internal/codegen/binding/MultiboundSetBinding.java index a55be5c6430..607ade81507 100644 --- a/java/dagger/internal/codegen/binding/MultiboundSetBinding.java +++ b/java/dagger/internal/codegen/binding/MultiboundSetBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#MULTIBOUND_SET}. */ @CheckReturnValue @@ -65,6 +66,6 @@ abstract static class Builder extends ContributionBinding.Builder { abstract Builder dependencies(ImmutableSet dependencies); - abstract Builder bindingType(BindingType bindingType); + abstract Builder optionalBindingType(Optional optionalBindingType); } } diff --git a/java/dagger/internal/codegen/binding/OptionalBinding.java b/java/dagger/internal/codegen/binding/OptionalBinding.java index a0e0f5fe9b9..172db511b67 100644 --- a/java/dagger/internal/codegen/binding/OptionalBinding.java +++ b/java/dagger/internal/codegen/binding/OptionalBinding.java @@ -81,6 +81,6 @@ static Builder builder() { abstract static class Builder extends ContributionBinding.Builder { abstract Builder delegateRequest(DependencyRequest delegateRequest); - abstract Builder bindingType(BindingType bindingType); + abstract Builder optionalBindingType(Optional optionalBindingType); } } diff --git a/java/dagger/internal/codegen/binding/ProductionBinding.java b/java/dagger/internal/codegen/binding/ProductionBinding.java index a75f5cff672..574a8645665 100644 --- a/java/dagger/internal/codegen/binding/ProductionBinding.java +++ b/java/dagger/internal/codegen/binding/ProductionBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#PRODUCTION}. */ @CheckReturnValue @@ -35,10 +36,9 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PRODUCTION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PRODUCTION); } - @Override @Memoized public ContributionType contributionType() { diff --git a/java/dagger/internal/codegen/binding/ProvisionBinding.java b/java/dagger/internal/codegen/binding/ProvisionBinding.java index 5a3c37d6521..7644155ad28 100644 --- a/java/dagger/internal/codegen/binding/ProvisionBinding.java +++ b/java/dagger/internal/codegen/binding/ProvisionBinding.java @@ -23,6 +23,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#PROVISION}. */ @CheckReturnValue @@ -34,8 +35,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override diff --git a/java/dagger/internal/codegen/binding/SubcomponentCreatorBinding.java b/java/dagger/internal/codegen/binding/SubcomponentCreatorBinding.java index dae115dabdf..b236163d2f7 100644 --- a/java/dagger/internal/codegen/binding/SubcomponentCreatorBinding.java +++ b/java/dagger/internal/codegen/binding/SubcomponentCreatorBinding.java @@ -24,6 +24,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import java.util.Optional; /** A binding for a {@link BindingKind#SUBCOMPONENT_CREATOR}. */ @CheckReturnValue @@ -35,8 +36,8 @@ public BindingKind kind() { } @Override - public BindingType bindingType() { - return BindingType.PROVISION; + public Optional optionalBindingType() { + return Optional.of(BindingType.PROVISION); } @Override