diff --git a/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java b/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java index bf8e94f2add..26246ffba46 100644 --- a/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java +++ b/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java @@ -16,11 +16,14 @@ package dagger.internal.codegen.xprocessing; +import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; import androidx.room.compiler.processing.XExecutableParameterElement; import androidx.room.compiler.processing.XType; import androidx.room.compiler.processing.XTypeElement; +import com.google.common.collect.ImmutableSet; +import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; @@ -53,5 +56,23 @@ public static ParameterSpec toParameterSpec(XExecutableParameterElement param) { return ParameterSpec.builder(param.getType().getTypeName(), param.getJvmName()).build(); } + public static ParameterSpec toParameterSpec( + XExecutableParameterElement parameter, XType parameterType) { + Nullability nullability = Nullability.of(parameter); + ImmutableSet typeUseNullableAnnotations = + nullability.typeUseNullableAnnotations().stream() + .map(annotation -> AnnotationSpec.builder(annotation).build()) + .collect(toImmutableSet()); + ImmutableSet nonTypeUseNullableAnnotations = + nullability.nonTypeUseNullableAnnotations().stream() + .map(annotation -> AnnotationSpec.builder(annotation).build()) + .collect(toImmutableSet()); + return ParameterSpec.builder( + parameterType.getTypeName().annotated(typeUseNullableAnnotations.asList()), + parameter.getJvmName()) + .addAnnotations(nonTypeUseNullableAnnotations) + .build(); + } + private JavaPoetExt() {} } diff --git a/java/dagger/internal/codegen/xprocessing/MethodSpecs.java b/java/dagger/internal/codegen/xprocessing/MethodSpecs.java index cc8c2f45915..405b73a7f0f 100644 --- a/java/dagger/internal/codegen/xprocessing/MethodSpecs.java +++ b/java/dagger/internal/codegen/xprocessing/MethodSpecs.java @@ -16,15 +16,15 @@ package dagger.internal.codegen.xprocessing; +import static dagger.internal.codegen.xprocessing.JavaPoetExt.toParameterSpec; import static javax.lang.model.element.Modifier.PROTECTED; import static javax.lang.model.element.Modifier.PUBLIC; +import androidx.room.compiler.processing.XExecutableParameterElement; import androidx.room.compiler.processing.XMethodElement; import androidx.room.compiler.processing.XMethodType; import androidx.room.compiler.processing.XType; import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; -import com.squareup.javapoet.TypeName; // TODO(bcorso): Consider moving these methods into XProcessing library. /** A utility class for {@link MethodSpec} helper methods. */ @@ -46,9 +46,9 @@ public static MethodSpec.Builder overriding(XMethodElement method, XType owner) builder.addModifiers(PROTECTED); } for (int i = 0; i < methodType.getParameterTypes().size(); i++) { - String parameterName = method.getParameters().get(i).getJvmName(); - TypeName parameterType = methodType.getParameterTypes().get(i).getTypeName(); - builder.addParameter(ParameterSpec.builder(parameterType, parameterName).build()); + XExecutableParameterElement parameter = method.getParameters().get(i); + XType parameterType = methodType.getParameterTypes().get(i); + builder.addParameter(toParameterSpec(parameter, parameterType)); } method.getThrownTypes().stream().map(XType::getTypeName).forEach(builder::addException); return builder; diff --git a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java index 65929e7d926..dfe74bb61b6 100644 --- a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java +++ b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java @@ -33,6 +33,13 @@ public static Collection parameters() { return CompilerMode.TEST_PARAMETERS; } + private static final Source NON_TYPE_USE_NULLABLE = + CompilerTests.javaSource( + "test.Nullable", // force one-string-per-line format + "package test;", + "", + "public @interface Nullable {}"); + @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); private final CompilerMode compilerMode; @@ -73,6 +80,38 @@ public void bindsInstance() throws Exception { }); } + @Test + public void testBindsNullableInstance() throws Exception { + Source component = + CompilerTests.javaSource( + "test.TestComponent", + "package test;", + "", + "import dagger.BindsInstance;", + "import dagger.Component;", + "", + "@Component", + "interface TestComponent {", + " @Component.Factory", + " interface Factory {", + " TestComponent create(@BindsInstance @Nullable Bar arg);", + "}", + "}"); + Source bar = + CompilerTests.javaSource( + "test.Bar", // force one-string-per-line format + "package test;", + "", + "interface Bar {}"); + CompilerTests.daggerCompiler(component, bar, NON_TYPE_USE_NULLABLE) + .withProcessingOptions(compilerMode.processorOptions()) + .compile( + subject -> { + subject.hasErrorCount(0); + subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); + }); + } + @Test public void instanceModuleMethod() throws Exception { Source module = diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_DEFAULT_MODE_test.DaggerTestComponent new file mode 100644 index 00000000000..2fe8226e104 --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_DEFAULT_MODE_test.DaggerTestComponent @@ -0,0 +1,42 @@ +package test; + +import dagger.internal.DaggerGenerated; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static TestComponent.Factory factory() { + return new Factory(); + } + + private static final class Factory implements TestComponent.Factory { + @Override + public TestComponent create(@Nullable Bar arg) { + return new TestComponentImpl(arg); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + private TestComponentImpl(Bar argParam) { + + + } + } +} \ No newline at end of file diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent new file mode 100644 index 00000000000..0feb62c2de5 --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent @@ -0,0 +1,42 @@ +package test; + +import dagger.internal.DaggerGenerated; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static TestComponent.Factory factory() { + return new Factory(); + } + + private static final class Factory implements TestComponent.Factory { + @Override + public TestComponent create(@Nullable Bar arg) { + return new TestComponentImpl(arg); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + private TestComponentImpl(Bar argParam) { + + + } + } +} diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_DEFAULT_MODE_test.DaggerTestComponent new file mode 100644 index 00000000000..0feb62c2de5 --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_DEFAULT_MODE_test.DaggerTestComponent @@ -0,0 +1,42 @@ +package test; + +import dagger.internal.DaggerGenerated; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static TestComponent.Factory factory() { + return new Factory(); + } + + private static final class Factory implements TestComponent.Factory { + @Override + public TestComponent create(@Nullable Bar arg) { + return new TestComponentImpl(arg); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + private TestComponentImpl(Bar argParam) { + + + } + } +} diff --git a/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent new file mode 100644 index 00000000000..0feb62c2de5 --- /dev/null +++ b/javatests/dagger/internal/codegen/goldens/ComponentRequirementFieldTest_testBindsTypeUseNullableInstance_FAST_INIT_MODE_test.DaggerTestComponent @@ -0,0 +1,42 @@ +package test; + +import dagger.internal.DaggerGenerated; +import javax.annotation.processing.Generated; + +@DaggerGenerated +@Generated( + value = "dagger.internal.codegen.ComponentProcessor", + comments = "https://dagger.dev" +) +@SuppressWarnings({ + "unchecked", + "rawtypes", + "KotlinInternal", + "KotlinInternalInJava", + "cast", + "deprecation" +}) +final class DaggerTestComponent { + private DaggerTestComponent() { + } + + public static TestComponent.Factory factory() { + return new Factory(); + } + + private static final class Factory implements TestComponent.Factory { + @Override + public TestComponent create(@Nullable Bar arg) { + return new TestComponentImpl(arg); + } + } + + private static final class TestComponentImpl implements TestComponent { + private final TestComponentImpl testComponentImpl = this; + + private TestComponentImpl(Bar argParam) { + + + } + } +}