From 1847e83c6875ce22380d6bc354ace16919a9f60c Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Mon, 27 Jul 2026 19:38:16 -0700 Subject: [PATCH] Persist the nullness of parameters for AssistedFactory overrides RELNOTES=n/a PiperOrigin-RevId: 954972878 --- .../AssistedFactoryRequestRepresentation.java | 4 +- .../writing/AssistedInjectionParameters.java | 21 ++-- .../internal/codegen/AssistedFactoryTest.java | 49 ++++++++++ .../test.DaggerTestComponent_DEFAULT_MODE | 66 +++++++++++++ .../test.DaggerTestComponent_FAST_INIT_MODE | 92 ++++++++++++++++++ .../test.DaggerTestComponent_KT_DEFAULT_MODE | 69 ++++++++++++++ ...test.DaggerTestComponent_KT_FAST_INIT_MODE | 95 +++++++++++++++++++ 7 files changed, 389 insertions(+), 7 deletions(-) create mode 100644 javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_DEFAULT_MODE create mode 100644 javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_FAST_INIT_MODE create mode 100644 javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_DEFAULT_MODE create mode 100644 javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_FAST_INIT_MODE diff --git a/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java b/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java index df89fa2c224..e84c3f43d87 100644 --- a/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java +++ b/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java @@ -97,7 +97,9 @@ private XTypeSpec anonymousfactoryImpl( XTypeSpecs.anonymousClassBuilder() .addFunction( overridingWithoutParameters(factoryMethod, factoryType, compilerOptions) - .addParameters(assistedFactoryParameterSpecs(binding, shardImplementation)) + .addParameters( + assistedFactoryParameterSpecs( + binding, shardImplementation, compilerOptions)) .addStatement( "return %L", requiresCast(returnType, shardImplementation.name()) diff --git a/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java b/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java index 9bb18dc1dec..ca3e4cbf9ea 100644 --- a/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java +++ b/dagger-compiler/main/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java @@ -32,8 +32,10 @@ import dagger.internal.codegen.binding.AssistedInjectionAnnotations; import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFactoryMetadata; import dagger.internal.codegen.binding.Binding; +import dagger.internal.codegen.compileroption.CompilerOptions; import dagger.internal.codegen.model.BindingKind; import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation; +import dagger.internal.codegen.xprocessing.Nullability; import dagger.internal.codegen.xprocessing.XParameterSpecs; import java.util.List; @@ -47,7 +49,7 @@ final class AssistedInjectionParameters { * dagger.assisted.AssistedInject}-annotated constructor. */ public static ImmutableList assistedFactoryParameterSpecs( - Binding binding, ShardImplementation shardImplementation) { + Binding binding, ShardImplementation shardImplementation, CompilerOptions compilerOptions) { checkArgument(binding.kind() == BindingKind.ASSISTED_FACTORY); XTypeElement factory = asTypeElement(binding.bindingElement().get()); AssistedFactoryMetadata metadata = AssistedFactoryMetadata.create(factory.getType()); @@ -60,7 +62,8 @@ public static ImmutableList assistedFactoryParameterSpecs( .map(metadata.assistedInjectAssistedParametersMap()::get) .collect(toImmutableList()), factoryMethodType.getParameterTypes(), - shardImplementation); + shardImplementation, + compilerOptions); } /** @@ -71,18 +74,22 @@ public static ImmutableList assistedFactoryParameterSpecs( * dagger.assisted.AssistedInject}-annotated constructor. */ public static ImmutableList assistedParameterSpecs( - Binding binding, ShardImplementation shardImplementation) { + Binding binding, ShardImplementation shardImplementation, CompilerOptions compilerOptions) { checkArgument(binding.kind() == BindingKind.ASSISTED_INJECTION); XConstructorElement constructor = asConstructor(binding.bindingElement().get()); XConstructorType constructorType = constructor.asMemberOf(binding.key().type().xprocessing()); return assistedParameterSpecs( - constructor.getParameters(), constructorType.getParameterTypes(), shardImplementation); + constructor.getParameters(), + constructorType.getParameterTypes(), + shardImplementation, + compilerOptions); } private static ImmutableList assistedParameterSpecs( List paramElements, List paramTypes, - ShardImplementation shardImplementation) { + ShardImplementation shardImplementation, + CompilerOptions compilerOptions) { ImmutableList.Builder assistedParameterSpecs = ImmutableList.builder(); for (int i = 0; i < paramElements.size(); i++) { XExecutableParameterElement paramElement = paramElements.get(i); @@ -91,7 +98,9 @@ private static ImmutableList assistedParameterSpecs( assistedParameterSpecs.add( XParameterSpecs.of( shardImplementation.getUniqueFieldNameForAssistedParam(paramElement), - paramType.asTypeName())); + paramType.asTypeName(), + Nullability.of(paramElement), + compilerOptions)); } } return assistedParameterSpecs.build(); diff --git a/javatests/dagger/internal/codegen/AssistedFactoryTest.java b/javatests/dagger/internal/codegen/AssistedFactoryTest.java index 333b20f0126..eb60e57fcf2 100644 --- a/javatests/dagger/internal/codegen/AssistedFactoryTest.java +++ b/javatests/dagger/internal/codegen/AssistedFactoryTest.java @@ -102,6 +102,55 @@ public void testAssistedFactory() throws Exception { }); } + @Test + public void testAssistedFactory_nullableAssistedParam() throws Exception { + Source foo = + CompilerTests.javaSource( + "test.Foo", + "package test;", + "", + "import dagger.assisted.Assisted;", + "import dagger.assisted.AssistedInject;", + "import javax.annotation.Nullable;", + "", + "class Foo {", + " @AssistedInject", + " Foo(@Assisted @Nullable String str) {}", + "}"); + + Source fooFactory = + CompilerTests.javaSource( + "test.FooFactory", + "package test;", + "", + "import dagger.assisted.AssistedFactory;", + "", + "@AssistedFactory", + "interface FooFactory {", + " Foo create(String factoryStr);", + "}"); + + Source component = + CompilerTests.javaSource( + "test.TestComponent", + "package test;", + "", + "import dagger.Component;", + "", + "@Component", + "interface TestComponent {", + " FooFactory fooFactory();", + "}"); + + CompilerTests.daggerCompiler(foo, fooFactory, component) + .withProcessingOptions(compilerMode.processorOptions()) + .compile( + subject -> { + subject.hasErrorCount(0); + subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); + }); + } + @Test public void testAssistedFactoryCycle() throws Exception { Source foo = diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_DEFAULT_MODE b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_DEFAULT_MODE new file mode 100644 index 00000000000..213d6d04149 --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_DEFAULT_MODE @@ -0,0 +1,66 @@ +package test; + +import dagger.internal.DaggerGenerated; +import dagger.internal.Provider; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation", + "nullness:initialization.field.uninitialized" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static Builder builder() { + return new Builder(); + } + + public static TestComponent create() { + return new Builder().build(); + } + + static final class Builder { + private Builder() { + } + + public TestComponent build() { + return new TestComponentImpl(); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + Foo_Factory fooProvider; + + Provider fooFactoryProvider; + + TestComponentImpl() { + + initialize(); + + } + + @SuppressWarnings("unchecked") + private void initialize() { + this.fooProvider = Foo_Factory.create(); + this.fooFactoryProvider = FooFactory_Impl.createFactoryProvider(fooProvider); + } + + @Override + public FooFactory fooFactory() { + return fooFactoryProvider.get(); + } + } +} diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_FAST_INIT_MODE b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_FAST_INIT_MODE new file mode 100644 index 00000000000..612f98fb768 --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_FAST_INIT_MODE @@ -0,0 +1,92 @@ +package test; + +import dagger.internal.DaggerGenerated; +import dagger.internal.Provider; +import dagger.internal.SingleCheck; +import javax.annotation.Nullable; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation", + "nullness:initialization.field.uninitialized" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static Builder builder() { + return new Builder(); + } + + public static TestComponent create() { + return new Builder().build(); + } + + static final class Builder { + private Builder() { + } + + public TestComponent build() { + return new TestComponentImpl(); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + Provider fooFactoryProvider; + + TestComponentImpl() { + + initialize(); + + } + + @SuppressWarnings("unchecked") + private void initialize() { + this.fooFactoryProvider = SingleCheck.provider(new SwitchingProvider(testComponentImpl, 0)); + } + + @Override + public FooFactory fooFactory() { + return fooFactoryProvider.get(); + } + + private static final class SwitchingProvider implements Provider { + private final TestComponentImpl testComponentImpl; + + private final int id; + + SwitchingProvider(TestComponentImpl testComponentImpl, int id) { + this.testComponentImpl = testComponentImpl; + this.id = id; + } + + @Override + @SuppressWarnings("unchecked") + public T get() { + switch (id) { + case 0: // test.FooFactory + return (T) new FooFactory() { + @Override + public Foo create(@Nullable String str) { + return new Foo(str); + } + }; + + default: throw new AssertionError(id); + } + } + } + } +} diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_DEFAULT_MODE b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_DEFAULT_MODE new file mode 100644 index 00000000000..d062c3e7b20 --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_DEFAULT_MODE @@ -0,0 +1,69 @@ +package test; + +import dagger.internal.DaggerGenerated; +import dagger.internal.Provider; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation", + "nullness:initialization.field.uninitialized" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static Builder builder() { + return new Builder(); + } + + public static TestComponent create() { + return new Builder().build(); + } + + static final class Builder { + private Builder() { + } + + public TestComponent build() { + return new TestComponentImpl(); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + Foo_Factory fooProvider; + + /** + * {@code Provider} + */ + Provider fooFactoryProvider; + + TestComponentImpl() { + + initialize(); + + } + + @SuppressWarnings("unchecked") + private void initialize() { + this.fooProvider = Foo_Factory.create(); + this.fooFactoryProvider = FooFactory_Impl.createFactoryProvider(fooProvider); + } + + @Override + public FooFactory fooFactory() { + return (FooFactory) ((Object) (fooFactoryProvider.get())); + } + } +} diff --git a/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_FAST_INIT_MODE b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_FAST_INIT_MODE new file mode 100644 index 00000000000..19564f3e33b --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/AssistedFactoryTest/testAssistedFactory_nullableAssistedParam/test.DaggerTestComponent_KT_FAST_INIT_MODE @@ -0,0 +1,95 @@ +package test; + +import dagger.internal.DaggerGenerated; +import dagger.internal.Provider; +import dagger.internal.SingleCheck; +import javax.annotation.Nullable; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation", + "nullness:initialization.field.uninitialized" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static Builder builder() { + return new Builder(); + } + + public static TestComponent create() { + return new Builder().build(); + } + + static final class Builder { + private Builder() { + } + + public TestComponent build() { + return new TestComponentImpl(); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + /** + * {@code Provider} + */ + Provider fooFactoryProvider; + + TestComponentImpl() { + + initialize(); + + } + + @SuppressWarnings("unchecked") + private void initialize() { + this.fooFactoryProvider = SingleCheck.provider(new SwitchingProvider<>(testComponentImpl, 0)); + } + + @Override + public FooFactory fooFactory() { + return (FooFactory) ((Object) (fooFactoryProvider.get())); + } + + private static final class SwitchingProvider implements Provider { + private final TestComponentImpl testComponentImpl; + + private final int id; + + SwitchingProvider(TestComponentImpl testComponentImpl, int id) { + this.testComponentImpl = testComponentImpl; + this.id = id; + } + + @Override + @SuppressWarnings("unchecked") + public T get() { + switch (id) { + case 0: // test.FooFactory + return (T) new FooFactory() { + @Override + public Foo create(@Nullable String str) { + return (Foo) (Foo_Factory.newInstance(str)); + } + }; + + default: throw new AssertionError(id); + } + } + } + } +}