Repository: square/anvil (kotlin)

Issue:
AssistedInject factory generation elides parameter nullability
```kotlin
public class MemberDirectoryViewModel_Factory_Impl(
  private val delegateFactory: MemberDirectoryViewModel_Factory
) : MemberDirectoryViewModel.Factory {
  public override fun create(groupToken: String, group: Account.Group): MemberDirectoryViewModel =
      delegateFactory.get(groupToken, group)

  public companion object {
    @JvmStatic
    public fun create(delegateFactory: MemberDirectoryViewModel_Factory):
        Provider<MemberDirectoryViewModel.Factory> =
        InstanceFactory.create(MemberDirectoryViewModel_Factory_Impl(delegateFactory))
  }
}
```

Is generated from:

```kotlin
@AssistedFactory
interface Factory {
    fun create(groupToken: String?, group: Account.Group?): MemberDirectoryViewModel
}
```

Which causes:

```
e: [...]/MemberDirectoryViewModel_Factory_Impl.kt: (14, 8): Class 'MemberDirectoryViewModel_Factory_Impl' is not abstract and does not implement abstract member public abstract fun create(groupToken: String?, group: Account.Group?): MemberDirectoryViewModel defined in com.faithlife.mobile.memberdirectory.MemberDirectoryViewModel.Factory
e: [...]/MemberDirectoryViewModel_Factory_Impl.kt: (17, 10): 'create' overrides nothing
```

I'm eager to use the anvil dagger factory generation!

Pull request:
Fixes #189

Patch:
diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/KotlinPoet.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/KotlinPoet.kt
index a634d124c..eaff3edc0 100644
--- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/KotlinPoet.kt
+++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/KotlinPoet.kt
@@ -188,7 +188,7 @@ fun KotlinType.asTypeName(): TypeName {
   if (isTypeParameter()) return TypeVariableName(toString())
 
   val className = classDescriptorForType().asClassName()
-  if (arguments.isEmpty()) return className
+  if (arguments.isEmpty()) return className.copy(nullable = isMarkedNullable)
 
   val argumentTypeNames = arguments.map { typeProjection ->
     if (typeProjection.isStarProjection) {
@@ -198,7 +198,7 @@ fun KotlinType.asTypeName(): TypeName {
     }
   }
 
-  return className.parameterizedBy(argumentTypeNames)
+  return className.parameterizedBy(argumentTypeNames).copy(nullable = isMarkedNullable)
 }
 
 internal data class Parameter(


Test patch:
diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt b/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt
index ccf98f4da..b9be36abb 100644
--- a/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt
+++ b/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt
@@ -235,7 +235,7 @@ internal fun Array<KClass<*>>.withoutAnvilModule(): List<KClass<*>> = toList().w
 internal fun Collection<KClass<*>>.withoutAnvilModule(): List<KClass<*>> =
   filterNot { FqName(it.qualifiedName!!).isAnvilModule() }
 
-internal fun Any.invokeGet(vararg args: Any): Any {
+internal fun Any.invokeGet(vararg args: Any?): Any {
   val method = this::class.java.declaredMethods.single { it.name == "get" }
   return method.invoke(this, *args)
 }
diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt
index 888d92ca2..29a89d0a8 100644
--- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt
+++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt
@@ -488,6 +488,118 @@ public final class AssistedServiceFactory_Impl<T extends CharSequence> implement
     }
   }
 
+  @Test fun `an implementation for a factory class with nullable parameters is generated`() {
+    /*
+package com.squareup.test;
+
+import javax.annotation.processing.Generated;
+import javax.inject.Provider;
+
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class AssistedService_Factory {
+  private final Provider<Integer> p0_52215Provider;
+
+  public AssistedService_Factory(Provider<Integer> p0_52215Provider) {
+    this.p0_52215Provider = p0_52215Provider;
+  }
+
+  public AssistedService get(String string) {
+    return newInstance(p0_52215Provider.get(), string);
+  }
+
+  public static AssistedService_Factory create(Provider<Integer> p0_52215Provider) {
+    return new AssistedService_Factory(p0_52215Provider);
+  }
+
+  public static AssistedService newInstance(int p0_52215, String string) {
+    return new AssistedService(p0_52215, string);
+  }
+}
+     */
+    /*
+package com.squareup.test;
+
+import dagger.internal.InstanceFactory;
+import javax.annotation.processing.Generated;
+import javax.inject.Provider;
+
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class AssistedServiceFactory_Impl implements AssistedServiceFactory {
+  private final AssistedService_Factory delegateFactory;
+
+  AssistedServiceFactory_Impl(AssistedService_Factory delegateFactory) {
+    this.delegateFactory = delegateFactory;
+  }
+
+  @Override
+  public AssistedService create(String string) {
+    return delegateFactory.get(string);
+  }
+
+  public static Provider<AssistedServiceFactory> create(AssistedService_Factory delegateFactory) {
+    return InstanceFactory.create(new AssistedServiceFactory_Impl(delegateFactory));
+  }
+}
+     */
+    compile(
+      """
+      package com.squareup.test
+      
+      import dagger.assisted.Assisted
+      import dagger.assisted.AssistedFactory
+      import dagger.assisted.AssistedInject
+      
+      class AssistedService @AssistedInject constructor(
+        val int: Int,
+        @Assisted val string: String?
+      )
+      
+      @AssistedFactory
+      interface AssistedServiceFactory {
+        fun create(string: String?): AssistedService
+      }
+      """
+    ) {
+      val factoryImplClass = assistedServiceFactory.implClass()
+      val generatedFactoryInstance = assistedService.factoryClass()
+        .declaredConstructors.single().newInstance(Provider { 5 })
+
+      val constructor = factoryImplClass.declaredConstructors.single()
+      assertThat(constructor.parameterTypes.toList())
+        .containsExactly(assistedService.factoryClass())
+
+      val staticMethods = factoryImplClass.declaredMethods.filter { it.isStatic }
+      assertThat(staticMethods).hasSize(1)
+
+      val factoryProvider = staticMethods.single { it.name == "create" }
+        .invoke(null, generatedFactoryInstance) as Provider<*>
+      assertThat(factoryProvider.get()::class.java).isEqualTo(factoryImplClass)
+
+      val factoryImplInstance = constructor.use { it.newInstance(generatedFactoryInstance) }
+
+      val assistedServiceInstance = factoryImplClass.declaredMethods
+        .filterNot { it.isStatic }
+        .single { it.name == "create" }
+        .invoke(factoryImplInstance, null)
+
+      assertThat(assistedServiceInstance::class.java).isEqualTo(assistedService)
+    }
+  }
+
   @Test fun `an assisted inject type must be returned`() {
     compile(
       """
diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt
index 254c9e1fa..1275fffc1 100644
--- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt
+++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt
@@ -460,6 +460,85 @@ public final class AssistedService_Factory {
     }
   }
 
+  @Test fun `a factory class is generated for nullable parameters`() {
+    /*
+package com.squareup.test;
+
+import javax.annotation.processing.Generated;
+import javax.inject.Provider;
+
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class AssistedService_Factory {
+  private final Provider<Integer> p0_52215Provider;
+
+  public AssistedService_Factory(Provider<Integer> p0_52215Provider) {
+    this.p0_52215Provider = p0_52215Provider;
+  }
+
+  public AssistedService get(String string) {
+    return newInstance(p0_52215Provider.get(), string);
+  }
+
+  public static AssistedService_Factory create(Provider<Integer> p0_52215Provider) {
+    return new AssistedService_Factory(p0_52215Provider);
+  }
+
+  public static AssistedService newInstance(Integer p0_52215, String string) {
+    return new AssistedService(p0_52215, string);
+  }
+}
+     */
+    compile(
+      """
+      package com.squareup.test
+      
+      import dagger.assisted.Assisted
+      import dagger.assisted.AssistedInject
+      
+      class AssistedService @AssistedInject constructor(
+        val int: Int?,
+        @Assisted val string: String?
+      ) {
+        override fun equals(other: Any?): Boolean {
+          if (this === other) return true
+          if (javaClass != other?.javaClass) return false
+      
+          other as AssistedService
+      
+          if (int != other.int) return false
+          if (string != other.string) return false
+      
+          return true
+        } 
+      }
+      """
+    ) {
+      val factoryClass = assistedService.factoryClass()
+
+      val constructor = factoryClass.declaredConstructors.single()
+      assertThat(constructor.parameterTypes.toList()).containsExactly(Provider::class.java)
+
+      val staticMethods = factoryClass.declaredMethods.filter { it.isStatic }
+      assertThat(staticMethods).hasSize(2)
+
+      val factoryInstance = staticMethods.single { it.name == "create" }
+        .invoke(null, Provider { null })
+      assertThat(factoryInstance::class.java).isEqualTo(factoryClass)
+
+      val newInstance = staticMethods.single { it.name == "newInstance" }
+        .invoke(null, null, null)
+
+      assertThat(factoryInstance.invokeGet(null)).isEqualTo(newInstance)
+    }
+  }
+
   @Test fun `two assisted inject constructors aren't supported`() {
     compile(
       """