Repository: square/anvil (kotlin)

Issue:
Incorrect factory generated for class with type parameters
Given I have a class with a type parameter:
```
abstract class MyFragment<T> : Fragment() {

    @Inject
    lateinit var something: Something
```

Anvil will generated a factory as:
```
class MyFragment_MembersInjector(
        private val param0: Provider<Something>
) : MembersInjector<MyFragment> {
    override fun injectMembers(instance: MyFragment) {
        injectSomething(instance, param0.get())
    }

    companion object {
        @JvmStatic
        fun create(param0: Provider<Something>): MyFragment_MembersInjector =
            MyFragment_MembersInjector(param0)

        @JvmStatic
        @InjectedFieldSignature("com.foo.MyFragment")
        fun injectSomething(instance: MyFragment, something: Something) {
            instance.something = something
        }
    }
}
```
which doesn't compile. I'm no expert, but I believe adding a `<*>` to the generated code when there's a type parameter should be enough to fix this

Pull request:
Fixes #91.

Patch:
diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/PsiUtils.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/PsiUtils.kt
index 390de7fbd..60dfc32c6 100644
--- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/PsiUtils.kt
+++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/PsiUtils.kt
@@ -247,3 +247,5 @@ fun KtTypeReference.isGenericType(): Boolean {
 }
 
 fun KtTypeReference.isFunctionType(): Boolean = typeElement is KtFunctionType
+
+fun KtClassOrObject.isGenericClass(): Boolean = typeParameterList != null
diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorGenerator.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorGenerator.kt
index a9f7c0b7b..be1f980a5 100644
--- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorGenerator.kt
+++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorGenerator.kt
@@ -6,6 +6,7 @@ import com.squareup.anvil.compiler.codegen.addGeneratedByComment
 import com.squareup.anvil.compiler.codegen.asTypeName
 import com.squareup.anvil.compiler.codegen.classesAndInnerClasses
 import com.squareup.anvil.compiler.codegen.hasAnnotation
+import com.squareup.anvil.compiler.codegen.isGenericClass
 import com.squareup.anvil.compiler.codegen.mapToParameter
 import com.squareup.anvil.compiler.codegen.replaceImports
 import com.squareup.anvil.compiler.codegen.requireFqName
@@ -21,6 +22,7 @@ import com.squareup.kotlinpoet.KModifier.OVERRIDE
 import com.squareup.kotlinpoet.KModifier.PRIVATE
 import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
 import com.squareup.kotlinpoet.PropertySpec
+import com.squareup.kotlinpoet.STAR
 import com.squareup.kotlinpoet.TypeSpec
 import com.squareup.kotlinpoet.asClassName
 import com.squareup.kotlinpoet.jvm.jvmStatic
@@ -70,6 +72,13 @@ internal class MembersInjectorGenerator : CodeGenerator {
     val packageName = clazz.containingKtFile.packageFqName.asString()
     val className = "${clazz.generateClassName()}_MembersInjector"
     val classType = clazz.asTypeName()
+        .let {
+          if (it is ClassName && clazz.isGenericClass()) {
+            it.parameterizedBy(STAR)
+          } else {
+            it
+          }
+        }
 
     val parameters = injectProperties.mapToParameter(module)
 


Test patch:
diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt
index f9633d697..584a29dcf 100644
--- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt
+++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt
@@ -559,6 +559,64 @@ public final class OuterClass_InjectClass_MembersInjector implements MembersInje
     }
   }
 
+  @Test fun `a factory class is generated for a field injection with a generic class`() {
+    /*
+package com.squareup.test;
+
+import dagger.MembersInjector;
+import dagger.internal.InjectedFieldSignature;
+import javax.annotation.Generated;
+import javax.inject.Provider;
+
+@Generated(
+    value = "dagger.internal.codegen.ComponentProcessor",
+    comments = "https://dagger.dev"
+)
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class InjectClass_MembersInjector<T> implements MembersInjector<InjectClass<T>> {
+  private final Provider<String> stringProvider;
+
+  public InjectClass_MembersInjector(Provider<String> stringProvider) {
+    this.stringProvider = stringProvider;
+  }
+
+  public static <T> MembersInjector<InjectClass<T>> create(Provider<String> stringProvider) {
+    return new InjectClass_MembersInjector<T>(stringProvider);}
+
+  @Override
+  public void injectMembers(InjectClass<T> instance) {
+    injectString(instance, stringProvider.get());
+  }
+
+  @InjectedFieldSignature("com.squareup.test.InjectClass.string")
+  public static <T> void injectString(InjectClass<T> instance, String string) {
+    instance.string = string;
+  }
+}
+     */
+
+    compile(
+        """
+        package com.squareup.test
+        
+        import javax.inject.Inject
+        
+        abstract class InjectClass<T> {
+          @Inject lateinit var string: String
+        }
+        """
+    ) {
+      val membersInjector = injectClass.membersInjector()
+
+      val constructor = membersInjector.declaredConstructors.single()
+      assertThat(constructor.parameterTypes.toList())
+          .containsExactly(Provider::class.java)
+    }
+  }
+
   @OptIn(ExperimentalStdlibApi::class)
   private fun Class<*>.staticInjectMethod(memberName: String): Method {
     // We can't check the @InjectedFieldSignature annotation unfortunately, because it has class