Repository: square/anvil (kotlin)

Issue:
generateDaggerFactories sometimes creates kotlin.Lazy instead of dagger.Lazy
Kotlin 1.4.30
Anvil 2.1.0

reproducer: https://github.com/RBusarow/AnvilFactoriesLazy

Given this code:

``` Kotlin
class OkHttpClient @Inject constructor()

class Retrofit(private val client: OkHttpClient)

@Module
@ContributesTo(AppScope::class)
object RetrofitModule {

  @Provides
  fun provideRetrofit(
    lazyClient: dagger.Lazy<OkHttpClient>
  ): Retrofit = Retrofit(lazyClient.get())
}
```

Compilation fails with this error message:
```
/lib/build/anvil/src-gen-main/com/reproducer/RetrofitModule_ProvideRetrofitFactory.kt: (26, 67): Type mismatch: inferred type is kotlin.Lazy<OkHttpClient> but dagger.Lazy<OkHttpClient> was expected
```

And the generated factory is:
``` Kotlin
package com.reproducer

import dagger.`internal`.Factory
import dagger.`internal`.Preconditions
import javax.inject.Provider
import kotlin.Lazy
import kotlin.Suppress
import kotlin.jvm.JvmStatic

public class RetrofitModule_ProvideRetrofitFactory(
  private val param0: Provider<Lazy<OkHttpClient>>
) : Factory<Retrofit> {
  public override fun `get`(): Retrofit = provideRetrofit(param0.get())

  public companion object {
    @JvmStatic
    public fun create(param0: Provider<Lazy<OkHttpClient>>): RetrofitModule_ProvideRetrofitFactory =
        RetrofitModule_ProvideRetrofitFactory(param0)

    @JvmStatic
    public fun provideRetrofit(param0: Lazy<OkHttpClient>): Retrofit =
        Preconditions.checkNotNull(RetrofitModule.provideRetrofit(param0),
        "Cannot return null from a non-@Nullable @Provides method")
  }
}
```

This only happens if the function parameter is the qualified `dagger.Lazy<T>`.

All these alternatives work fine:
- `import dagger.Lazy` with a function parameter of `Lazy<Foo>`
- `import dagger.Lazy as DaggerLazy` with a function parameter of `DaggerLazy<Foo>`
- `typalias DaggerLazy<T> = dagger.Lazy<T>` with a function parameter of `DaggerLazy<Foo>`

Pull request:
Until now we ignored the package and only evaluated the class name, which lead to wrong imports.

Fixes #198

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 d8da56edf..e2ea2f21d 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
@@ -201,7 +201,18 @@ internal fun PsiElement.requireFqName(
     is KtUserType -> {
       val isGenericType = children.any { it is KtTypeArgumentList }
       if (isGenericType) {
-        referencedName ?: failTypeHandling()
+        // For an expression like Lazy<Abc> the qualifier will be null. If the qualifier exists,
+        // then it refers to package and the referencedName refers to the class name, e.g.
+        // a KtUserType "abc.def.GenericType<String>" has three children: a qualifier "abc.def",
+        // the referencedName "GenericType" and the KtTypeArgumentList.
+        val packageName = qualifier?.text
+        val className = referencedName
+
+        if (packageName != null) {
+          return FqName("$packageName.$className")
+        }
+
+        className ?: failTypeHandling()
       } else {
         val text = text
 


Test patch:
diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt
index e2a23cef8..6d79f269f 100644
--- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt
+++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt
@@ -1016,6 +1016,48 @@ public final class DaggerModule1_ProvideStringFactory implements Factory<String>
     }
   }
 
+  @Test fun `a factory class is generated for a provider method with a lazy parameter using a fully qualified name`() { // ktlint-disable max-line-length
+    compile(
+      """
+      package com.squareup.test
+      
+      import dagger.Module
+      import dagger.Provides
+      import javax.inject.Named
+      
+      @Module
+      class DaggerModule1 {
+        @Provides fun provideString(
+          param: dagger.Lazy<String> 
+        ): String = param.get()
+      }
+      """
+    ) {
+      val factoryClass = daggerModule1.moduleFactoryClass("provideString")
+
+      val constructor = factoryClass.declaredConstructors.single()
+      assertThat(constructor.parameterTypes.toList())
+        .containsExactly(daggerModule1, Provider::class.java)
+        .inOrder()
+
+      val staticMethods = factoryClass.declaredMethods.filter { it.isStatic }
+
+      val module = daggerModule1.newInstanceNoArgs()
+
+      val factoryInstance = staticMethods.single { it.name == "create" }
+        .invoke(null, module, Provider { "a" })
+        as Factory<String>
+      assertThat(factoryInstance::class.java).isEqualTo(factoryClass)
+
+      val providedString = staticMethods.single { it.name == "provideString" }
+        .invoke(null, module, Lazy<CharSequence> { "a" })
+        as String
+
+      assertThat(providedString).isEqualTo("a")
+      assertThat(factoryInstance.get()).isEqualTo("a")
+    }
+  }
+
   @Test fun `a factory class is generated for a provider method with generic parameters`() {
     /*
 package com.squareup.test;