diff --git a/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateBinding.java b/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateBinding.java index b6f7b9ce0dc..29794b8b324 100644 --- a/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateBinding.java +++ b/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateBinding.java @@ -16,6 +16,7 @@ package dagger.internal.codegen.binding; +import androidx.room3.compiler.processing.XMethodElement; import com.google.auto.value.AutoValue; import com.google.auto.value.extension.memoized.Memoized; import com.google.common.collect.ImmutableSet; @@ -24,6 +25,7 @@ import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.xprocessing.Nullability; +import dagger.internal.codegen.xprocessing.XTypeNames; import java.util.Optional; /** A binding for a {@link BindingKind#DELEGATE}. */ @@ -49,6 +51,11 @@ public boolean requiresModuleInstance() { return false; } + public static boolean hasDelegateAnnotation(XMethodElement method) { + return method.hasAnnotation(XTypeNames.BINDS) + ; + } + @Override public abstract Builder toBuilder(); diff --git a/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateDeclaration.java b/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateDeclaration.java index 2430e33f924..d456c4f4cab 100644 --- a/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateDeclaration.java +++ b/dagger-compiler/main/java/dagger/internal/codegen/binding/DelegateDeclaration.java @@ -31,14 +31,18 @@ import dagger.internal.codegen.base.ContributionType.HasContributionType; import dagger.internal.codegen.model.DaggerAnnotation; import dagger.internal.codegen.model.DependencyRequest; -import dagger.internal.codegen.xprocessing.XTypeNames; import java.util.Optional; import javax.inject.Inject; -/** The declaration for a delegate binding established by a {@link Binds} method. */ +/** + * The declaration for a delegate binding established by a {@link Binds} + * + * or {@link Alias} + * + * method. + */ @AutoValue -public abstract class DelegateDeclaration extends Declaration - implements HasContributionType { +public abstract class DelegateDeclaration extends Declaration implements HasContributionType { abstract DependencyRequest delegateRequest(); // Note: We're using DaggerAnnotation instead of XAnnotation for its equals/hashcode @@ -64,20 +68,20 @@ public static final class Factory { this.dependencyRequestFactory = dependencyRequestFactory; } - public DelegateDeclaration create(XMethodElement bindsMethod, XTypeElement contributingModule) { - checkArgument(bindsMethod.hasAnnotation(XTypeNames.BINDS)); - XMethodType resolvedMethod = bindsMethod.asMemberOf(contributingModule.getType()); + public DelegateDeclaration create(XMethodElement method, XTypeElement contributingModule) { + checkArgument(DelegateBinding.hasDelegateAnnotation(method)); + XMethodType resolvedMethod = method.asMemberOf(contributingModule.getType()); DependencyRequest delegateRequest = dependencyRequestFactory.forRequiredResolvedVariable( - Iterables.getOnlyElement(bindsMethod.getParameters()), + Iterables.getOnlyElement(method.getParameters()), Iterables.getOnlyElement(resolvedMethod.getParameterTypes())); return new AutoValue_DelegateDeclaration( - ContributionType.fromBindingElement(bindsMethod), - keyFactory.forBindsMethod(bindsMethod, contributingModule), - Optional.of(bindsMethod), + ContributionType.fromBindingElement(method), + keyFactory.forDelegateDeclaration(method, contributingModule), + Optional.of(method), Optional.of(contributingModule), delegateRequest, - getMapKey(bindsMethod).map(DaggerAnnotation::from)); + getMapKey(method).map(DaggerAnnotation::from)); } } } diff --git a/dagger-compiler/main/java/dagger/internal/codegen/binding/KeyFactory.java b/dagger-compiler/main/java/dagger/internal/codegen/binding/KeyFactory.java index 1f624893821..279d53818ff 100644 --- a/dagger-compiler/main/java/dagger/internal/codegen/binding/KeyFactory.java +++ b/dagger-compiler/main/java/dagger/internal/codegen/binding/KeyFactory.java @@ -36,7 +36,6 @@ import androidx.room3.compiler.processing.XProcessingEnv; import androidx.room3.compiler.processing.XType; import androidx.room3.compiler.processing.XTypeElement; -import dagger.Binds; import dagger.BindsOptionalOf; import dagger.internal.codegen.base.ContributionType; import dagger.internal.codegen.base.FrameworkTypes; @@ -138,9 +137,8 @@ public Key forProducesMethod(XMethodElement method, XTypeElement contributingMod return forBindingMethod(method, contributingModule, Optional.of(XTypeNames.PRODUCER)); } - /** Returns the key bound by a {@link Binds} method. */ - Key forBindsMethod(XMethodElement method, XTypeElement contributingModule) { - checkArgument(method.hasAnnotation(XTypeNames.BINDS)); + Key forDelegateDeclaration(XMethodElement method, XTypeElement contributingModule) { + checkArgument(DelegateBinding.hasDelegateAnnotation(method)); return forBindingMethod(method, contributingModule, Optional.empty()); } diff --git a/dagger-compiler/main/java/dagger/internal/codegen/binding/ModuleDescriptor.java b/dagger-compiler/main/java/dagger/internal/codegen/binding/ModuleDescriptor.java index 867dfaf2a69..f058f42e9a2 100644 --- a/dagger-compiler/main/java/dagger/internal/codegen/binding/ModuleDescriptor.java +++ b/dagger-compiler/main/java/dagger/internal/codegen/binding/ModuleDescriptor.java @@ -152,7 +152,7 @@ public ModuleDescriptor createUncached(XTypeElement moduleElement) { if (moduleMethod.hasAnnotation(XTypeNames.PRODUCES)) { bindings.add(bindingFactory.producesMethodBinding(moduleMethod, moduleElement)); } - if (moduleMethod.hasAnnotation(XTypeNames.BINDS)) { + if (DelegateBinding.hasDelegateAnnotation(moduleMethod)) { delegates.add( bindingDelegateDeclarationFactory.create(moduleMethod, moduleElement)); } diff --git a/javatests/dagger/functional/asalias/AsAliasTest.java b/javatests/dagger/functional/asalias/AsAliasTest.java deleted file mode 100644 index 1a4f57c334c..00000000000 --- a/javatests/dagger/functional/asalias/AsAliasTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2026 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.asalias; - -import static com.google.common.truth.Truth.assertThat; - -import dagger.AsAlias; -import dagger.Binds; -import dagger.Component; -import dagger.Module; -import dagger.Subcomponent; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public final class AsAliasTest { - interface Iface {} - - static class IfaceImpl implements Iface { - @Inject - IfaceImpl() {} - } - - @Module - interface IfaceModule { - @Binds - @AsAlias - Iface bind(IfaceImpl impl); - } - - @Singleton - @Component(modules = {IfaceModule.class}) - interface ParentComponent { - ChildComponent childComponent(); - } - - @Subcomponent - interface ChildComponent { - Iface getIface(); - } - - @Test - public void asAliasInParentComponentWithImplDepsInChildComponent_bindsIfaceImpl() { - ParentComponent component = DaggerAsAliasTest_ParentComponent.create(); - ChildComponent subcomponent = component.childComponent(); - assertThat(subcomponent.getIface()).isNotNull(); - assertThat(subcomponent.getIface()).isInstanceOf(IfaceImpl.class); - } -} diff --git a/javatests/dagger/functional/asalias/BUILD b/javatests/dagger/functional/asalias/BUILD deleted file mode 100644 index f77c50c329a..00000000000 --- a/javatests/dagger/functional/asalias/BUILD +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (C) 2026 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. - -# Description: -# Tests for dagger.AsAlias. - -load( - "//:build_defs.bzl", - "DOCLINT_HTML_AND_SYNTAX", - "DOCLINT_REFERENCES", -) -load("//:test_defs.bzl", "GenJavaTests") - -package(default_visibility = ["//:src"]) - -GenJavaTests( - name = "AsAliasTest", - srcs = ["AsAliasTest.java"], - javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES, - deps = [ - "//third_party/java/dagger", - "//third_party/java/jsr330_inject", - "//third_party/java/junit", - "//third_party/java/truth", - ], -) - -GenJavaTests( - name = "ChainOfAsAliasTest", - srcs = ["ChainOfAsAliasTest.java"], - javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES, - deps = [ - "//third_party/java/dagger", - "//third_party/java/jsr330_inject", - "//third_party/java/junit", - "//third_party/java/truth", - ], -) - -GenJavaTests( - name = "SubcomponentRequestingAliasOfSingletonTest", - srcs = ["SubcomponentRequestingAliasOfSingletonTest.java"], - javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES, - deps = [ - "//third_party/java/dagger", - "//third_party/java/jsr330_inject", - "//third_party/java/junit", - "//third_party/java/truth", - ], -) diff --git a/javatests/dagger/functional/asalias/ChainOfAsAliasTest.java b/javatests/dagger/functional/asalias/ChainOfAsAliasTest.java deleted file mode 100644 index db1fbdd5c86..00000000000 --- a/javatests/dagger/functional/asalias/ChainOfAsAliasTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2026 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.asalias; - -import static com.google.common.truth.Truth.assertThat; - -import dagger.AsAlias; -import dagger.Binds; -import dagger.Component; -import dagger.Module; -import dagger.Subcomponent; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public final class ChainOfAsAliasTest { - interface A {} - - interface B extends A {} - - interface C extends B {} - - static class CImpl implements C { - @Inject - CImpl() {} - } - - @Module - interface ChainModule { - @Binds - @AsAlias - A bindA(B b); - - @Binds - @AsAlias - B bindB(C c); - - @Binds - @AsAlias - C bindC(CImpl cImpl); - } - - @Singleton - @Component(modules = {ChainModule.class}) - interface ParentComponent { - ChildComponent childComponent(); - } - - @Subcomponent - interface ChildComponent { - A getA(); - } - - @Test - public void chainOfAsAlias() { - ParentComponent component = DaggerChainOfAsAliasTest_ParentComponent.create(); - ChildComponent subcomponent = component.childComponent(); - assertThat(subcomponent.getA()).isNotNull(); - assertThat(subcomponent.getA()).isInstanceOf(CImpl.class); - } -} diff --git a/javatests/dagger/functional/asalias/SubcomponentRequestingAliasOfSingletonTest.java b/javatests/dagger/functional/asalias/SubcomponentRequestingAliasOfSingletonTest.java deleted file mode 100644 index 688864de722..00000000000 --- a/javatests/dagger/functional/asalias/SubcomponentRequestingAliasOfSingletonTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2026 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.asalias; - -import static com.google.common.truth.Truth.assertThat; - -import dagger.AsAlias; -import dagger.Binds; -import dagger.Component; -import dagger.Module; -import dagger.Provides; -import dagger.Subcomponent; -import dagger.multibindings.IntoSet; -import java.util.Set; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public final class SubcomponentRequestingAliasOfSingletonTest { - interface X {} - - interface Foo { - Set getXs(); - } - - @Singleton - static final class FooImpl implements Foo { - final Set xs; - - @Inject - FooImpl(Set xs) { - this.xs = xs; - } - - @Override - public Set getXs() { - return xs; - } - } - - @Module - abstract static class ParentModule { - @Provides - @IntoSet - static X provideX1() { - return new X() {}; - } - - @AsAlias - @Binds - abstract Foo bindFoo(FooImpl fooImpl); - } - - @Module - interface SubcomponentModule { - @Provides - @IntoSet - static X provideX2() { - return new X() {}; - } - } - - @Singleton - @Component(modules = {ParentModule.class}) - interface ParentComponent { - Foo getFoo(); - - ChildComponent childComponent(); - } - - @Subcomponent(modules = {SubcomponentModule.class}) - interface ChildComponent { - Foo getFoo(); - - Set getXs(); - } - - @Test - public void subcomponentRequestingAliasOfSingletonWithSetDependency() { - ParentComponent parentComponent = - DaggerSubcomponentRequestingAliasOfSingletonTest_ParentComponent.create(); - ChildComponent subcomponent = parentComponent.childComponent(); - assertThat(parentComponent.getFoo().getXs()).hasSize(1); - // Even though ChildComponent contributes to Set, Bar is @Singleton so it gets - // constructed with Set from ParentComponent once. - assertThat(subcomponent.getFoo().getXs()).hasSize(1); - // Requesting Set directly from ChildComponent should include contributions from - // ChildComponent, so it has size 2. - assertThat(subcomponent.getXs()).hasSize(2); - } -} diff --git a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java index 6385c593a3c..98172486725 100644 --- a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java +++ b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java @@ -554,13 +554,15 @@ public void componentWithBadModule() { .compile( subject -> { subject.hasErrorCount(2); - subject.hasErrorContaining( + subject + .hasErrorContaining( "strings is annotated with more than one of (dagger.Provides, " + "dagger.producers.Produces, dagger.Binds, " + "dagger.multibindings.Multibinds, dagger.BindsOptionalOf)") .onSource(badModule) .onLine(12); - subject.hasErrorContaining("test.BadModule has errors") + subject + .hasErrorContaining("test.BadModule has errors") .onSource(badComponent) .onLine(7); });