Inline assisted binding private method in fast init mode.
RELNOTES=n/a
PiperOrigin-RevId: 409516899
diff --git a/java/dagger/internal/codegen/binding/BindingGraph.java b/java/dagger/internal/codegen/binding/BindingGraph.java
index c9a0ce9..019a3b5 100644
--- a/java/dagger/internal/codegen/binding/BindingGraph.java
+++ b/java/dagger/internal/codegen/binding/BindingGraph.java
@@ -44,7 +44,6 @@
import dagger.spi.model.BindingGraph.DependencyEdge;
import dagger.spi.model.BindingGraph.Edge;
import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.BindingKind;
import dagger.spi.model.ComponentPath;
import dagger.spi.model.DaggerTypeElement;
import dagger.spi.model.DependencyRequest;
@@ -158,7 +157,7 @@
network().successors(node).stream().sorted(nodeOrder()).collect(toImmutableList()));
}
- public boolean hasframeworkRequest(Binding binding) {
+ public boolean hasFrameworkRequest(Binding binding) {
return frameworkTypeBindings.contains(binding);
}
@@ -166,31 +165,6 @@
ImmutableNetwork<Node, Edge> network, ImmutableSet<dagger.spi.model.Binding> bindings) {
Set<Binding> frameworkRequestBindings = new HashSet<>();
for (dagger.spi.model.Binding binding : bindings) {
- // When a delegator binding received an instance request, it will manually create an
- // instance request for its delegated binding in direct instance binding representation. It
- // is possible a provider.get() expression will be returned to satisfy the request for the
- // delegated binding. In this case, the returned expression should have a type cast, because
- // the returned expression's type can be Object. The type cast is handled by
- // DelegateRequestRepresentation. If we change to use framework instance binding
- // representation to handle the delegate bindings, then we will be missing the type cast.
- // Because in this case, when requesting an instance for the delegator binding, framework
- // instance binding representation will manually create a provider request for delegated
- // binding first, then use DerivedFromFrameworkInstanceRequestRepresentaion to wrap that
- // provider expression. Then we will still have a provider.get(), but it is generated with
- // two different request representation, so the type cast step is skipped. As the result, we
- // can't directly switch the delegation binding to always use the framework instance if a
- // framework request already exists. So I'm adding an temporary exemption for delegate
- // binding here to make it still use the old generation logic. We might be able to remove
- // the exemption when we handle the type cast differently.
- // TODO(wanyingd): fix the type cast problem and remove the exemption for delegate binding.
- if (binding.kind().equals(BindingKind.DELEGATE)
- // In fast init mode, for Assisted injection binding, since we manually create a direct
- // instance when the request type is a Provider, then there can't really be any
- // framework requests for the binding.
- // TODO(wanyingd): inline assisted injection binding expression in assisted factory.
- || binding.kind().equals(BindingKind.ASSISTED_INJECTION)) {
- continue;
- }
ImmutableList<DependencyEdge> edges =
network.inEdges(binding).stream()
.flatMap(instancesOf(DependencyEdge.class))
diff --git a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
index 81ba316..a83b618 100644
--- a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
@@ -18,10 +18,11 @@
import static com.google.auto.common.MoreElements.asType;
import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethod;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryParameterSpecs;
+import static dagger.internal.codegen.writing.AssistedInjectionParameters.assistedFactoryParameterSpecs;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -31,13 +32,14 @@
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.BindingRequest;
+import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.RequestKind;
+import java.util.Optional;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
@@ -49,18 +51,24 @@
*/
final class AssistedFactoryRequestRepresentation extends RequestRepresentation {
private final ProvisionBinding binding;
- private final ComponentRequestRepresentations componentRequestRepresentations;
+ private final BindingGraph graph;
+ private final SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory;
private final DaggerElements elements;
private final DaggerTypes types;
+ private final ComponentImplementation componentImplementation;
@AssistedInject
AssistedFactoryRequestRepresentation(
@Assisted ProvisionBinding binding,
- ComponentRequestRepresentations componentRequestRepresentations,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ SimpleMethodRequestRepresentation.Factory simpleMethodRequestRepresentationFactory,
DaggerTypes types,
DaggerElements elements) {
this.binding = checkNotNull(binding);
- this.componentRequestRepresentations = componentRequestRepresentations;
+ this.graph = graph;
+ this.componentImplementation = componentImplementation;
+ this.simpleMethodRequestRepresentationFactory = simpleMethodRequestRepresentationFactory;
this.elements = elements;
this.types = types;
}
@@ -69,18 +77,22 @@
Expression getDependencyExpression(ClassName requestingClass) {
// An assisted factory binding should have a single request for an assisted injection type.
DependencyRequest assistedInjectionRequest = getOnlyElement(binding.provisionDependencies());
+ // Get corresponding assisted injection binding.
+ Optional<Binding> localBinding = graph.localContributionBinding(assistedInjectionRequest.key());
+ checkArgument(
+ localBinding.isPresent(),
+ "assisted factory should have a dependency on an assisted injection binding");
Expression assistedInjectionExpression =
- ((AssistedPrivateMethodRequestRepresentation)
- componentRequestRepresentations.getRequestRepresentation(
- BindingRequest.bindingRequest(
- assistedInjectionRequest.key(), RequestKind.INSTANCE)))
- .getAssistedDependencyExpression(requestingClass.peerClass(""));
+ simpleMethodRequestRepresentationFactory
+ .create((ProvisionBinding) localBinding.get())
+ .getDependencyExpression(requestingClass.peerClass(""));
return Expression.create(
assistedInjectionExpression.type(),
- CodeBlock.of("$L", anonymousfactoryImpl(assistedInjectionExpression)));
+ CodeBlock.of("$L", anonymousfactoryImpl(localBinding.get(), assistedInjectionExpression)));
}
- private TypeSpec anonymousfactoryImpl(Expression assistedInjectionExpression) {
+ private TypeSpec anonymousfactoryImpl(
+ Binding assistedBinding, Expression assistedInjectionExpression) {
TypeElement factory = asType(binding.bindingElement().get());
DeclaredType factoryType = asDeclared(binding.key().type().java());
ExecutableElement factoryMethod = assistedFactoryMethod(factory, elements);
@@ -96,7 +108,12 @@
.returns(factoryOverride.returnType)
.addAnnotations(factoryOverride.annotations)
.addExceptions(factoryOverride.exceptions)
- .addParameters(assistedFactoryParameterSpecs(binding, elements, types))
+ .addParameters(
+ assistedFactoryParameterSpecs(
+ binding,
+ elements,
+ types,
+ componentImplementation.shardImplementation(assistedBinding)))
.addStatement("return $L", assistedInjectionExpression.codeBlock())
.build());
diff --git a/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
index 3b39bde..c117628 100644
--- a/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
+++ b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
@@ -20,12 +20,15 @@
import static com.google.auto.common.MoreTypes.asDeclared;
import static com.google.auto.common.MoreTypes.asExecutable;
import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
+import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFactoryMetadata;
import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.spi.model.BindingKind;
@@ -38,6 +41,34 @@
/** Utility class for generating unique assisted parameter names for a component shard. */
final class AssistedInjectionParameters {
/**
+ * Returns the list of assisted factory parameters as {@link ParameterSpec}s.
+ *
+ * <p>The type of each parameter will be the resolved type given by the binding key, and the name
+ * of each parameter will be the name given in the {@link
+ * dagger.assisted.AssistedInject}-annotated constructor.
+ */
+ public static ImmutableList<ParameterSpec> assistedFactoryParameterSpecs(
+ Binding binding,
+ DaggerElements elements,
+ DaggerTypes types,
+ ShardImplementation shardImplementation) {
+ checkArgument(binding.kind() == BindingKind.ASSISTED_FACTORY);
+ AssistedFactoryMetadata metadata =
+ AssistedFactoryMetadata.create(binding.bindingElement().get().asType(), elements, types);
+ ExecutableType factoryMethodType =
+ asExecutable(
+ types.asMemberOf(asDeclared(binding.key().type().java()), metadata.factoryMethod()));
+ return assistedParameterSpecs(
+ // Use the order of the parameters from the @AssistedFactory method but use the parameter
+ // names of the @AssistedInject constructor.
+ metadata.assistedFactoryAssistedParameters().stream()
+ .map(metadata.assistedInjectAssistedParametersMap()::get)
+ .collect(toImmutableList()),
+ factoryMethodType.getParameterTypes(),
+ shardImplementation);
+ }
+
+ /**
* Returns the list of assisted parameters as {@link ParameterSpec}s.
*
* <p>The type of each parameter will be the resolved type given by the binding key, and the name
diff --git a/java/dagger/internal/codegen/writing/AssistedPrivateMethodRequestRepresentation.java b/java/dagger/internal/codegen/writing/AssistedPrivateMethodRequestRepresentation.java
deleted file mode 100644
index aa117db..0000000
--- a/java/dagger/internal/codegen/writing/AssistedPrivateMethodRequestRepresentation.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2021 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameterSpecs;
-import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
-import static dagger.internal.codegen.writing.AssistedInjectionParameters.assistedParameterSpecs;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.PRIVATE_METHOD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeName;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.RequestKind;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression that wraps private method call for assisted fatory creation. */
-final class AssistedPrivateMethodRequestRepresentation extends MethodRequestRepresentation {
- private final ShardImplementation shardImplementation;
- private final ContributionBinding binding;
- private final BindingRequest request;
- private final RequestRepresentation wrappedRequestRepresentation;
- private final CompilerOptions compilerOptions;
- private final DaggerTypes types;
- private String methodName;
-
- @AssistedInject
- AssistedPrivateMethodRequestRepresentation(
- @Assisted BindingRequest request,
- @Assisted ContributionBinding binding,
- @Assisted RequestRepresentation wrappedRequestRepresentation,
- ComponentImplementation componentImplementation,
- DaggerTypes types,
- CompilerOptions compilerOptions) {
- super(componentImplementation.shardImplementation(binding), types);
- checkArgument(binding.kind() == BindingKind.ASSISTED_INJECTION);
- checkArgument(request.requestKind() == RequestKind.INSTANCE);
- this.binding = checkNotNull(binding);
- this.request = checkNotNull(request);
- this.wrappedRequestRepresentation = checkNotNull(wrappedRequestRepresentation);
- this.shardImplementation = componentImplementation.shardImplementation(binding);
- this.compilerOptions = compilerOptions;
- this.types = types;
- }
-
- Expression getAssistedDependencyExpression(ClassName requestingClass) {
- return Expression.create(
- returnType(),
- requestingClass.equals(shardImplementation.name())
- ? CodeBlock.of(
- "$N($L)", methodName(), parameterNames(assistedParameterSpecs(binding, types)))
- : CodeBlock.of(
- "$L.$N($L)",
- shardImplementation.shardFieldReference(),
- methodName(),
- parameterNames(assistedParameterSpecs(binding, types))));
- }
-
- @Override
- protected CodeBlock methodCall() {
- throw new IllegalStateException("This should not be accessed");
- }
-
- @Override
- protected TypeMirror returnType() {
- return types.accessibleType(binding.contributedType(), shardImplementation.name());
- }
-
- private String methodName() {
- if (methodName == null) {
- // Have to set methodName field before implementing the method in order to handle recursion.
- methodName = shardImplementation.getUniqueMethodName(request);
-
- // TODO(bcorso): Fix the order that these generated methods are written to the component.
- shardImplementation.addMethod(
- PRIVATE_METHOD,
- methodBuilder(methodName)
- .addModifiers(PRIVATE)
- .addParameters(assistedParameterSpecs(binding, types, shardImplementation))
- .returns(TypeName.get(returnType()))
- .addStatement(
- "return $L",
- wrappedRequestRepresentation
- .getDependencyExpression(shardImplementation.name())
- .codeBlock())
- .build());
- }
- return methodName;
- }
-
- @AssistedFactory
- static interface Factory {
- AssistedPrivateMethodRequestRepresentation create(
- BindingRequest request,
- ContributionBinding binding,
- RequestRepresentation wrappedRequestRepresentation);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentImplementation.java b/java/dagger/internal/codegen/writing/ComponentImplementation.java
index af645f4..2f4d2d6 100644
--- a/java/dagger/internal/codegen/writing/ComponentImplementation.java
+++ b/java/dagger/internal/codegen/writing/ComponentImplementation.java
@@ -431,6 +431,7 @@
private final UniqueNameSet componentFieldNames = new UniqueNameSet();
private final UniqueNameSet componentMethodNames = new UniqueNameSet();
private final UniqueNameSet componentClassNames = new UniqueNameSet();
+ private final UniqueNameSet assistedParamNames = new UniqueNameSet();
private final List<CodeBlock> initializations = new ArrayList<>();
private final Map<Key, CodeBlock> cancellations = new LinkedHashMap<>();
private final Map<VariableElement, String> uniqueAssistedName = new LinkedHashMap<>();
@@ -443,6 +444,7 @@
private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
private final List<Supplier<TypeSpec>> typeSuppliers = new ArrayList<>();
+ private boolean initialized = false; // This is used for initializing assistedParamNames.
private ShardImplementation(ClassName name) {
this.name = name;
@@ -580,11 +582,26 @@
return componentFieldNames.getUniqueName(name);
}
+ String getUniqueAssistedParamName(String name) {
+ if (!initialized) {
+ // Assisted params will be used in switching provider, so they can't conflict with component
+ // field names in switching provider. {@link UniqueNameSet#getUniqueName} will add the
+ // component field names to the unique set if it does not exists. If the name already exists
+ // in the set, then a dedupe will be performed automatically on the passed in name, and the
+ // newly created unique name will then be added to the set.
+ componentFieldsByImplementation()
+ .values()
+ .forEach(fieldSpec -> assistedParamNames.getUniqueName(fieldSpec.name));
+ initialized = true;
+ }
+ return assistedParamNames.getUniqueName(name);
+ }
+
public String getUniqueFieldNameForAssistedParam(VariableElement element) {
if (uniqueAssistedName.containsKey(element)) {
return uniqueAssistedName.get(element);
}
- String name = getUniqueFieldName(element.getSimpleName().toString());
+ String name = getUniqueAssistedParamName(element.getSimpleName().toString());
uniqueAssistedName.put(element, name);
return name;
}
diff --git a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
index b899768..c90d813 100644
--- a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
@@ -27,7 +27,6 @@
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.BindingKind;
import dagger.spi.model.RequestKind;
import java.util.HashMap;
import java.util.Map;
@@ -44,8 +43,6 @@
immediateFutureRequestRepresentationFactory;
private final PrivateMethodRequestRepresentation.Factory
privateMethodRequestRepresentationFactory;
- private final AssistedPrivateMethodRequestRepresentation.Factory
- assistedPrivateMethodRequestRepresentationFactory;
private final UnscopedDirectInstanceRequestRepresentationFactory
unscopedDirectInstanceRequestRepresentationFactory;
private final Map<BindingRequest, RequestRepresentation> requestRepresentations = new HashMap<>();
@@ -58,8 +55,6 @@
ComponentMethodRequestRepresentation.Factory componentMethodRequestRepresentationFactory,
ImmediateFutureRequestRepresentation.Factory immediateFutureRequestRepresentationFactory,
PrivateMethodRequestRepresentation.Factory privateMethodRequestRepresentationFactory,
- AssistedPrivateMethodRequestRepresentation.Factory
- assistedPrivateMethodRequestRepresentationFactory,
UnscopedDirectInstanceRequestRepresentationFactory
unscopedDirectInstanceRequestRepresentationFactory) {
this.binding = binding;
@@ -70,8 +65,6 @@
this.privateMethodRequestRepresentationFactory = privateMethodRequestRepresentationFactory;
this.unscopedDirectInstanceRequestRepresentationFactory =
unscopedDirectInstanceRequestRepresentationFactory;
- this.assistedPrivateMethodRequestRepresentationFactory =
- assistedPrivateMethodRequestRepresentationFactory;
}
public RequestRepresentation getRequestRepresentation(BindingRequest request) {
@@ -82,7 +75,9 @@
private RequestRepresentation getRequestRepresentationUncached(BindingRequest request) {
switch (request.requestKind()) {
case INSTANCE:
- return instanceRequestRepresentation();
+ return requiresMethodEncapsulation(binding)
+ ? wrapInMethod(unscopedDirectInstanceRequestRepresentationFactory.create(binding))
+ : unscopedDirectInstanceRequestRepresentationFactory.create(binding);
case FUTURE:
return immediateFutureRequestRepresentationFactory.create(
@@ -95,19 +90,6 @@
}
}
- private RequestRepresentation instanceRequestRepresentation() {
- RequestRepresentation directInstanceExpression =
- unscopedDirectInstanceRequestRepresentationFactory.create(binding);
- if (binding.kind() == BindingKind.ASSISTED_INJECTION) {
- BindingRequest request = bindingRequest(binding.key(), RequestKind.INSTANCE);
- return assistedPrivateMethodRequestRepresentationFactory.create(
- request, binding, directInstanceExpression);
- }
- return requiresMethodEncapsulation(binding)
- ? wrapInMethod(RequestKind.INSTANCE, directInstanceExpression)
- : directInstanceExpression;
- }
-
/**
* Returns a binding expression that uses a given one as the body of a method that users call. If
* a component provision method matches it, it will be the method implemented. If it does not
@@ -115,14 +97,13 @@
* binding method will be written. If the binding doesn't match a component method and is not
* modifiable, then a new private method will be written.
*/
- RequestRepresentation wrapInMethod(
- RequestKind requestKind, RequestRepresentation bindingExpression) {
+ RequestRepresentation wrapInMethod(RequestRepresentation bindingExpression) {
// If we've already wrapped the expression, then use the delegate.
if (bindingExpression instanceof MethodRequestRepresentation) {
return bindingExpression;
}
- BindingRequest request = bindingRequest(binding.key(), requestKind);
+ BindingRequest request = bindingRequest(binding.key(), RequestKind.INSTANCE);
Optional<ComponentMethodDescriptor> matchingComponentMethod =
graph.componentDescriptor().firstMatchingComponentMethod(request);
diff --git a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
index 22970ab..1e87838 100644
--- a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
@@ -29,6 +29,7 @@
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.spi.model.BindingKind;
import dagger.spi.model.RequestKind;
/**
@@ -90,7 +91,31 @@
// form a loop. There are also difficulties introduced by manually created framework requests.
// TODO(wanyingd): refactor framework instance so that we don't need to generate both direct
// instance and framework instance representation for the same binding.
- if (isFastInit && graph.topLevelBindingGraph().hasframeworkRequest(binding)) {
+ if (isFastInit
+ && graph.topLevelBindingGraph().hasFrameworkRequest(binding)
+ // When a delegator binding receives an instance request, it will manually create an
+ // instance request for its delegated binding in direct instance binding representation. It
+ // is possible a provider.get() expression will be returned to satisfy the request for the
+ // delegated binding. In this case, the returned expression should have a type cast, because
+ // the returned expression's type can be Object. The type cast is handled by
+ // DelegateRequestRepresentation.
+ //
+ // If framework instance binding representation is used to handle the delegate bindings
+ // instead of direct instance, then the type cast will be skipped.
+ //
+ // Because in this case, when requesting an instance for the delegator binding, framework
+ // instance binding representation will manually create a provider request for delegated
+ // binding first, then use DerivedFromFrameworkInstanceRequestRepresentaion to wrap that
+ // provider expression. Eventually, the returned expression will still be a provider.get(),
+ // but it is generated with two different request representations, so the type cast step is
+ // skipped, and a type cast error will be thrown.
+ //
+ // That's why a temporary exemption for delegate binding is needed to make it still use the
+ // old generation logic. The exemption might be removable if the code is changed to handle
+ // the type case differently.
+ // TODO(b/206111117): fix the type cast problem and remove the exemption for delegate
+ // binding.
+ && !binding.kind().equals(BindingKind.DELEGATE)) {
return false;
}
@@ -100,15 +125,13 @@
// InstanceFactory.create(Foo_MembersInjector.create(...)).
// TODO(b/199889259): Consider optimizing this for fastInit mode.
case ASSISTED_FACTORY:
- return false;
// Assisted factory binding can be requested with framework request, and it is essentially a
// provider for assisted injection binding. So we will always return framework instance for
// assisted factory bindings.
+ return false;
case ASSISTED_INJECTION:
- // We still return direct instance for assisted injection binding in fast init mode, because
- // we want to avoid requiring dependencies as providers in fast init for now. This might
- // change after we merge fast init mode and default mode.
- return isFastInit;
+ throw new IllegalStateException(
+ "Assisted injection binding shouldn't be requested with an instance request.");
default:
// We don't need to use Provider#get() if there's no caching, so use a direct instance.
// TODO(bcorso): This can be optimized in cases where we know a Provider field already
diff --git a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
index c58e3d1..6437774 100644
--- a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
+++ b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
@@ -115,11 +115,11 @@
case ASSISTED_FACTORY:
return assistedFactoryRequestRepresentationFactory.create((ProvisionBinding) binding);
- case ASSISTED_INJECTION:
case INJECTION:
case PROVISION:
return simpleMethodRequestRepresentationFactory.create((ProvisionBinding) binding);
+ case ASSISTED_INJECTION:
case MEMBERS_INJECTOR:
case MEMBERS_INJECTION:
case COMPONENT_PRODUCTION:
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java b/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java
new file mode 100644
index 0000000..af9b40e
--- /dev/null
+++ b/javatests/dagger/functional/assisted/AssistedFactoryDuplicatedParamNamesTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 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.functional.assisted;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.BindsInstance;
+import dagger.Component;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AssistedFactoryDuplicatedParamNamesTest {
+ static final class Foo {
+ private final String arg;
+ private final Bar bar;
+
+ @AssistedInject
+ Foo(@Assisted String arg, Bar bar) {
+ this.arg = arg;
+ this.bar = bar;
+ }
+
+ Bar getBar() {
+ return bar;
+ }
+
+ String getArg() {
+ return arg;
+ }
+ }
+
+ static final class Bar {}
+
+ @AssistedFactory
+ interface FooFactory {
+ Foo create(String arg);
+ }
+
+ @Component
+ interface TestComponent {
+ @Component.Factory
+ interface Factory {
+ TestComponent create(@BindsInstance Bar arg);
+ }
+
+ FooFactory fooFactory();
+ }
+
+ @Test
+ public void duplicatedParameterNames_doesNotConflict() {
+ String str = "test";
+ Bar bar = new Bar();
+
+ Foo foo =
+ DaggerAssistedFactoryDuplicatedParamNamesTest_TestComponent.factory()
+ .create(bar)
+ .fooFactory()
+ .create(str);
+
+ assertThat(foo.getArg()).isEqualTo(str);
+ assertThat(foo.getBar()).isEqualTo(bar);
+ }
+}
diff --git a/javatests/dagger/internal/codegen/AssistedFactoryTest.java b/javatests/dagger/internal/codegen/AssistedFactoryTest.java
index a78c051..565e1cd 100644
--- a/javatests/dagger/internal/codegen/AssistedFactoryTest.java
+++ b/javatests/dagger/internal/codegen/AssistedFactoryTest.java
@@ -102,10 +102,6 @@
" private final DaggerTestComponent testComponent = this;",
" private Provider<FooFactory> fooFactoryProvider;",
"",
- " private Foo foo(String str) {",
- " return new Foo(str, new Bar());",
- " }",
- "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.fooFactoryProvider = SingleCheck.provider(new"
@@ -129,7 +125,7 @@
" return (T) new FooFactory() {",
" @Override",
" public Foo create(String str) {",
- " return testComponent.foo(str);",
+ " return new Foo(str, new Bar());",
" }",
" };",
"",
@@ -226,10 +222,6 @@
" return new Bar(fooFactoryProvider.get());",
" }",
"",
- " private Foo foo(String str) {",
- " return new Foo(str, bar());",
- " }",
- "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.fooFactoryProvider = SingleCheck.provider(new"
@@ -253,7 +245,7 @@
" return (T) new FooFactory() {",
" @Override",
" public Foo create(String str) {",
- " return testComponent.foo(str);",
+ " return new Foo(str, testComponent.bar())",
" }",
" };",
"",
@@ -293,24 +285,21 @@
}
@Test
- public void testInjectParamDuplicateNames() {
- JavaFileObject componentSrc =
+ public void assistedParamConflictsWithComponentFieldName_successfulyDeduped() {
+ JavaFileObject foo =
JavaFileObjects.forSourceLines(
- "test.TestComponent",
+ "test.Foo",
"package test;",
"",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
+ "import dagger.assisted.Assisted;",
+ "import dagger.assisted.AssistedInject;",
+ "import javax.inject.Provider;",
"",
- "@Component",
- "interface TestComponent {",
- " @Component.Factory",
- " interface Factory {",
- " TestComponent create(@BindsInstance Bar arg);",
- " }",
- " FooFactory getFooFactory();",
+ "class Foo {",
+ " @AssistedInject",
+ " Foo(@Assisted String testComponent, Provider<Bar> bar) {}",
"}");
- JavaFileObject factorySrc =
+ JavaFileObject fooFactory =
JavaFileObjects.forSourceLines(
"test.FooFactory",
"package test;",
@@ -318,51 +307,49 @@
"import dagger.assisted.AssistedFactory;",
"",
"@AssistedFactory",
- "public interface FooFactory {",
- " Foo create(Integer arg);",
+ "interface FooFactory {",
+ " Foo create(String factoryStr);",
"}");
- JavaFileObject barSrc =
- JavaFileObjects.forSourceLines("test.Bar", "package test;", "", "interface Bar {}");
- JavaFileObject injectSrc =
+ JavaFileObject bar =
JavaFileObjects.forSourceLines(
- "test.Foo",
+ "test.Bar",
"package test;",
"",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
+ "import javax.inject.Inject;",
"",
- "class Foo {",
- " @AssistedInject",
- " Foo(Bar bar, @Assisted Integer arg) {}",
+ "class Bar {",
+ " @Inject Bar() {}",
"}");
- JavaFileObject generatedSrc =
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " FooFactory fooFactory();",
+ "}");
+ JavaFileObject generatedComponent =
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines("package test;", "", GeneratedLines.generatedAnnotations())
.addLinesIn(
FAST_INIT_MODE,
"final class DaggerTestComponent implements TestComponent {",
- " private final Bar arg2;",
" private final DaggerTestComponent testComponent = this;",
" private Provider<FooFactory> fooFactoryProvider;",
"",
- " private DaggerTestComponent(Bar argParam) {",
- " this.arg2 = argParam;",
- " initialize(argParam);",
- " }",
- "",
- " private Foo foo(Integer arg) {",
- " return new Foo(arg2, arg);",
- " }",
- "",
" @SuppressWarnings(\"unchecked\")",
- " private void initialize(final Bar argParam) {",
- " this.fooFactoryProvider = SingleCheck.provider(new"
- + " SwitchingProvider<FooFactory>(testComponent, 0));",
+ " private void initialize() {",
+ " this.barProvider = new SwitchingProvider<>(testComponent, 1);",
+ " this.fooFactoryProvider = SingleCheck.provider(",
+ " new SwitchingProvider<FooFactory>(testComponent, 0));",
" }",
"",
" @Override",
- " public FooFactory getFooFactory() {",
+ " public FooFactory fooFactory() {",
" return fooFactoryProvider.get();",
" }",
"",
@@ -370,7 +357,6 @@
" private final DaggerTestComponent testComponent;",
" private final int id;",
"",
- "",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
@@ -378,11 +364,11 @@
" case 0:",
" return (T) new FooFactory() {",
" @Override",
- " public Foo create(Integer arg) {",
- " return testComponent.foo(arg);",
+ " public Foo create(String testComponent2) {",
+ " return new Foo(testComponent2, testComponent.barProvider);",
" }",
" };",
- "",
+ " case 1: return (T) new Bar();",
" default: throw new AssertionError(id);",
" }",
" }",
@@ -391,201 +377,31 @@
.addLinesIn(
DEFAULT_MODE,
"final class DaggerTestComponent implements TestComponent {",
- " private final DaggerTestComponent testComponent = this;",
- " private Provider<Bar> argProvider;",
+ "",
" private Foo_Factory fooProvider;",
+ "",
" private Provider<FooFactory> fooFactoryProvider;",
"",
- " private DaggerTestComponent(Bar argParam) {",
- " initialize(argParam);",
- " }",
- "",
- " public static TestComponent.Factory factory() {",
- " return new Factory();",
- " }",
- "",
" @SuppressWarnings(\"unchecked\")",
- " private void initialize(final Bar argParam) {",
- " this.argProvider = InstanceFactory.create(argParam);",
- " this.fooProvider = Foo_Factory.create(argProvider);",
+ " private void initialize() {",
+ " this.fooProvider = Foo_Factory.create(Bar_Factory.create());",
" this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
" }",
"",
" @Override",
- " public FooFactory getFooFactory() {",
+ " public FooFactory fooFactory() {",
" return fooFactoryProvider.get();",
" }",
- "",
- " private static final class Factory implements TestComponent.Factory {",
- " @Override",
- " public TestComponent create(Bar arg) {",
- " Preconditions.checkNotNull(arg);",
- " return new DaggerTestComponent(arg);",
- " }",
- " }",
"}")
.build();
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
- .compile(componentSrc, factorySrc, barSrc, injectSrc);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedSrc);
- }
- @Test
- public void testAssistParamDuplicateNames() {
- JavaFileObject componentSrc =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " @Component.Factory",
- " interface Factory {",
- " TestComponent create(@BindsInstance Bar arg);",
- " }",
- " Bar getBar();",
- " FooFactory getFooFactory();",
- "}");
- JavaFileObject factorySrc =
- JavaFileObjects.forSourceLines(
- "test.FooFactory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "public interface FooFactory {",
- " Foo create(Integer arg);",
- "}");
- JavaFileObject barSrc =
- JavaFileObjects.forSourceLines("test.Bar", "package test;", "", "interface Bar {}");
- JavaFileObject injectSrc =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(Bar bar, @Assisted Integer arg) {}",
- "}");
- JavaFileObject generatedSrc =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines("package test;", "", GeneratedLines.generatedAnnotations())
- .addLinesIn(
- FAST_INIT_MODE,
- "final class DaggerTestComponent implements TestComponent {",
- " private final Bar arg;",
- " private final DaggerTestComponent testComponent = this;",
- " private Provider<FooFactory> fooFactoryProvider;",
- "",
- " private DaggerTestComponent(Bar argParam) {",
- " this.arg = argParam;",
- " initialize(argParam);",
- " }",
- "",
- " private Foo foo(Integer arg2) {",
- " return new Foo(arg, arg2);",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(final Bar argParam) {",
- " this.fooFactoryProvider = SingleCheck.provider(new"
- + " SwitchingProvider<FooFactory>(testComponent, 0));",
- " }",
- "",
- " @Override",
- " public Bar getBar() {",
- " return arg;",
- " }",
- "",
- " @Override",
- " public FooFactory getFooFactory() {",
- " return fooFactoryProvider.get();",
- " }",
- "",
- " private static final class SwitchingProvider<T> implements Provider<T> {",
- " private final DaggerTestComponent testComponent;",
- " private final int id;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) new FooFactory() {",
- " @Override",
- " public Foo create(Integer arg) {",
- " return testComponent.foo(arg);",
- " }",
- " };",
- "",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}")
- .addLinesIn(
- DEFAULT_MODE,
- "final class DaggerTestComponent implements TestComponent {",
- " private final Bar arg;",
- " private final DaggerTestComponent testComponent = this;",
- " private Provider<Bar> argProvider;",
- " private Foo_Factory fooProvider;",
- " private Provider<FooFactory> fooFactoryProvider;",
- "",
- " private DaggerTestComponent(Bar argParam) {",
- " this.arg = argParam;",
- " initialize(argParam);",
- " }",
- "",
- " public static TestComponent.Factory factory() {",
- " return new Factory();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(final Bar argParam) {",
- " this.argProvider = InstanceFactory.create(argParam);",
- " this.fooProvider = Foo_Factory.create(argProvider);",
- " this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
- " }",
- "",
- " @Override",
- " public Bar getBar() {",
- " return arg;",
- " }",
- "",
- " @Override",
- " public FooFactory getFooFactory() {",
- " return fooFactoryProvider.get();",
- " }",
- "",
- " private static final class Factory implements TestComponent.Factory {",
- " @Override",
- " public TestComponent create(Bar arg) {",
- " Preconditions.checkNotNull(arg);",
- " return new DaggerTestComponent(arg);",
- " }",
- " }",
- "}")
- .build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
- .compile(componentSrc, factorySrc, barSrc, injectSrc);
+ compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, fooFactory, component);
+
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedSrc);
+ .containsElementsIn(generatedComponent);
}
@Test
@@ -733,10 +549,6 @@
" private final DaggerTestComponent testComponent = this;",
" private Provider<FooFactory<String>> fooFactoryProvider;",
"",
- " private Foo<String> fooOfString(String arg) {",
- " return new Foo<String>(arg);",
- " }",
- "",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.fooFactoryProvider = SingleCheck.provider(new"
@@ -759,7 +571,7 @@
" case 0: return (T) new FooFactory<String>() {",
" @Override",
" public Foo<String> create(String arg) {",
- " return testComponent.fooOfString(arg);",
+ " return new Foo<String>(arg)",
" }",
" };",
"",