Repository: square/anvil (kotlin)

Issue:
False positive check leads to compilation fail
First of all thanks for quick support for dagger's AssistedInject! 

We did a migration to it with `2.0.12-SNAPSHOT` anvil version and everything worked fine, but with update to stable 2.0.12 compilation started failing with `@Provides methods cannot be abstract` error. 

Module failed to compile looks like this: 
```
@Module
@ContributesTo(AppComponent::class)
interface Module {

    @Binds
    @Singleton
    fun bindsDependency(i: DependencyImpl): Dependency

    companion object {
        @Provides
        @Singleton
        fun providesDepB(depA: DepA): DepB = DepB(depA)
    }
}
```
This code is valid with both dagger kapt and anvil 2.0.11. 

It looks like it was introduced in #186  https://github.com/square/anvil/pull/186/files#diff-c59935dc466bb8ab8c74b8e866de744af48eeddaa9340add1833bb09776ff354R63
and `@Provides` function should be filtered if it's inside companion object

Pull request:
This was a false positive.

Fixes #187

Patch:
diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryGenerator.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryGenerator.kt
index 87534a5fb..fe058d492 100644
--- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryGenerator.kt
+++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryGenerator.kt
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.lexer.KtTokens.ABSTRACT_KEYWORD
 import org.jetbrains.kotlin.psi.KtCallableDeclaration
 import org.jetbrains.kotlin.psi.KtClassOrObject
 import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtFunction
 import org.jetbrains.kotlin.psi.KtObjectDeclaration
 import org.jetbrains.kotlin.psi.KtProperty
 import org.jetbrains.kotlin.psi.psiUtil.parents
@@ -61,12 +62,7 @@ internal class ProvidesMethodFactoryGenerator : PrivateCodeGenerator() {
           .asSequence()
           .filter { it.hasAnnotation(daggerProvidesFqName) }
           .onEach { function ->
-            if (clazz.isInterface() || function.hasModifier(ABSTRACT_KEYWORD)) {
-              throw AnvilCompilationException(
-                "@Provides methods cannot be abstract",
-                element = function
-              )
-            }
+            checkFunctionIsNotAbstract(clazz, function)
           }
           .also { functions ->
             // Check for duplicate function names.
@@ -293,4 +289,28 @@ internal class ProvidesMethodFactoryGenerator : PrivateCodeGenerator() {
 
     return createGeneratedFile(codeGenDir, packageName, className, content)
   }
+
+  private fun checkFunctionIsNotAbstract(
+    clazz: KtClassOrObject,
+    function: KtFunction
+  ) {
+    fun fail(): Nothing = throw AnvilCompilationException(
+      "@Provides methods cannot be abstract",
+      element = function
+    )
+
+    // If the function is abstract, then it's an error.
+    if (function.hasModifier(ABSTRACT_KEYWORD)) fail()
+
+    // If the class is not an interface and doesn't use the abstract keyword, then there is
+    // no issue.
+    if (!clazz.isInterface()) return
+
+    // If the parent of the function is a companion object, then the function inside of the
+    // interface is not abstract.
+    val parentClass = function.parents.filterIsInstance<KtClassOrObject>().firstOrNull() ?: return
+    if (parentClass is KtObjectDeclaration && parentClass.isCompanion()) return
+
+    fail()
+  }
 }


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 846bc10a0..e2a23cef8 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
@@ -2883,6 +2883,27 @@ public final class DaggerModule1_GetStringFactory implements Factory<String> {
     }
   }
 
+  @Test fun `an interface with a companion object is allowed to contain a provider method`() {
+    compile(
+      """
+      package com.squareup.test
+      
+      import dagger.Module
+      import dagger.Provides
+      
+      @Module
+      interface DaggerModule1 {
+        companion object {
+          @Provides fun provideString(): String = ""
+        }      
+      }
+      """
+    ) {
+      val factoryClass = daggerModule1.moduleFactoryClass("provideString", companion = true)
+      assertThat(factoryClass).isNotNull()
+    }
+  }
+
   @Suppress("CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS")
   private fun compile(
     vararg sources: String,