Repository: square/anvil (kotlin)

Issue:
Dagger factory generator breaks in modules containing `-` in name
### Current behavior

Here `app-display` is the consuming app module and `display-legacy` is the producing library module. The generated code expects class `FakeRotationModule_Companion_FakeRotation$display_legacy_debugFactory`.
```
> Task :app-display:compileDebugJavaWithJavac FAILED
C:\gradle\build\...\app-display\generated\source\kapt\debug\...DaggerHomeComponent.java:6: error: cannot find symbol
import ....FakeRotationModule_Companion_FakeRotation$display_legacy_debugFactory;
                                                         ^
  symbol:   class FakeRotationModule_Companion_FakeRotation$display_legacy_debugFactory
  location: package ...
```
The factory exists on disk with a dash; Anvil generates class `FakeRotationModule_Companion_FakeRotation$display-legacy_debugFactory`.

![image](https://user-images.githubusercontent.com/4589773/202015156-f7a9a509-38f5-45eb-a810-43e8993787e8.png)

### What's likely happening

`-` is a valid part of a Kotlin identifier so the source file is generated with a dash. Dagger would generate an underscore instead. This mismatch causes compile-time errors when attempting to generate a component from Anvil-generated `@Module`s in Gradle modules whose names contain `-`.

### Expected behavior

Anvil should use Java validation rules for class names when generating Dagger factories.

### Workarounds

* Use only valid Java identifiers as module names
* Use kapt and actual Dagger compiler

Pull request:
… involving a dash-separated module name

Fixes #653

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 c1983b855..4751a692b 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
@@ -333,7 +333,8 @@ internal class ProvidesMethodFactoryGenerator : PrivateCodeGenerator() {
   }
 
   private fun ModuleDescriptor.mangledNameSuffix(): String {
-    val name = name.asString()
+    // We replace - with _ to maintain interoperability with Dagger's expected generated identifiers
+    val name = name.asString().replace('-', '_')
     return if (name.startsWith('<') && name.endsWith('>')) {
       name.substring(1, name.length - 1)
     } else {


Test patch:
diff --git a/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt b/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt
index acb7fa7fd..ac60c1dc0 100644
--- a/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt
+++ b/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt
@@ -219,7 +219,8 @@ public fun compileAnvil(
   enableExperimentalAnvilApis: Boolean = true,
   previousCompilationResult: Result? = null,
   codeGenerators: List<CodeGenerator> = emptyList(),
-  block: Result.() -> Unit = { }
+  moduleName: String? = null,
+  block: Result.() -> Unit = { },
 ): Result {
   return AnvilCompilation()
     .apply {
@@ -229,6 +230,9 @@ public fun compileAnvil(
         if (workingDir != null) {
           this.workingDir = workingDir
         }
+        if (moduleName != null) {
+          this.moduleName = moduleName
+        }
       }
 
       if (previousCompilationResult != null) {
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 e4288427f..e74fb9cbf 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
@@ -862,6 +862,38 @@ public final class DaggerModule1_ProvideString$mainFactory implements Factory<St
     }
   }
 
+  @Test
+  fun `a factory class is generated for an internal provider method with a mangled name in a object in a module with a dash-separated name`() {
+    compile(
+      """
+      package com.squareup.test
+
+      @dagger.Module
+      object DaggerModule1 {
+        @dagger.Provides internal fun provideString(): String = "abc"
+      }
+      """,
+      moduleName = "with-dashes",
+    ) {
+      val factoryClass = daggerModule1.moduleFactoryClass("provideString\$with_dashes")
+
+      val constructor = factoryClass.declaredConstructors.single()
+      assertThat(constructor.parameterTypes.toList()).isEmpty()
+
+      val staticMethods = factoryClass.declaredMethods.filter { it.isStatic }
+
+      val factoryInstance = staticMethods.single { it.name == "create" }
+        .invoke(null)
+      assertThat(factoryInstance::class.java).isEqualTo(factoryClass)
+
+      val providedString = staticMethods.single { it.name == "provideString\$with_dashes" }
+        .invoke(null) as String
+
+      assertThat(providedString).isEqualTo("abc")
+      assertThat((factoryInstance as Factory<String>).get()).isEqualTo("abc")
+    }
+  }
+
   @Test
   fun `the factory does not contain the mangled name if the function is internal and uses @PublishedApi`() {
     compile(
@@ -3472,7 +3504,8 @@ public final class DaggerModule1_ProvideFunctionFactory implements Factory<Set<S
     @Language("kotlin") vararg sources: String,
     enableDagger: Boolean = useDagger,
     previousCompilationResult: Result? = null,
-    block: Result.() -> Unit = { }
+    moduleName: String? = null,
+    block: Result.() -> Unit = { },
   ): Result = compileAnvil(
     sources = sources,
     enableDaggerAnnotationProcessor = enableDagger,
@@ -3480,6 +3513,7 @@ public final class DaggerModule1_ProvideFunctionFactory implements Factory<Set<S
     useIR = USE_IR,
     allWarningsAsErrors = WARNINGS_AS_ERRORS,
     block = block,
-    previousCompilationResult = previousCompilationResult
+    previousCompilationResult = previousCompilationResult,
+    moduleName = moduleName
   )
 }