Skip to content

Commit

Permalink
Merge pull request #666 from square/joel.improve-binding-validation-e…
Browse files Browse the repository at this point in the history
…rror-messages

Improve the error message for failed binding validations when the parameter and return type do not match
  • Loading branch information
JoelWilcox authored Dec 16, 2022
2 parents a4a932c + 7f2cac3 commit 84ba1e5
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.squareup.anvil.compiler.codegen.PrivateCodeGenerator
import com.squareup.anvil.compiler.daggerBindsFqName
import com.squareup.anvil.compiler.daggerModuleFqName
import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionFunctionReference
import com.squareup.anvil.compiler.internal.reference.ClassReference
import com.squareup.anvil.compiler.internal.reference.FunctionReference
import com.squareup.anvil.compiler.internal.reference.allSuperTypeClassReferences
import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences
Expand Down Expand Up @@ -75,28 +76,48 @@ internal class BindsMethodValidator : PrivateCodeGenerator() {
)

if (!function.parameterMatchesReturnType() && !function.receiverMatchesReturnType()) {
val returnType = function.returnType().asClassReference().shortName
val paramSuperTypes = (function.parameterSuperTypes() ?: function.receiverSuperTypes())!!
.map { it.shortName }
.toList()

val superTypesMessage = if (paramSuperTypes.size == 1) {
"has no supertypes."
} else {
"only has the following supertypes: ${paramSuperTypes.drop(1)}"
}
throw AnvilCompilationExceptionFunctionReference(
message = "@Binds methods' parameter type must be assignable to the return type",
message = "@Binds methods' parameter type must be assignable to the return type. " +
"Expected binding of type $returnType but impl parameter of type " +
"${paramSuperTypes.first()} $superTypesMessage",
functionReference = function
)
}
}

private fun FunctionReference.Psi.parameterMatchesReturnType(): Boolean {
return parameterSuperTypes()
?.contains(returnType().asClassReference())
?: false
}

private fun FunctionReference.Psi.parameterSuperTypes(): Sequence<ClassReference>? {
return parameters.singleOrNull()
?.type()
?.asClassReference()
?.allSuperTypeClassReferences(includeSelf = true)
}

private fun FunctionReference.Psi.receiverMatchesReturnType(): Boolean {
return receiverSuperTypes()
?.contains(returnType().asClassReference())
?: false
}

private fun FunctionReference.Psi.receiverMatchesReturnType(): Boolean {
private fun FunctionReference.Psi.receiverSuperTypes(): Sequence<ClassReference>? {
return function.receiverTypeReference
?.toTypeReference(declaringClass)
?.asClassReference()
?.allSuperTypeClassReferences(includeSelf = true)
?.contains(returnType().asClassReference())
?: false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,41 @@ class BindsMethodValidatorTest(

@Test
fun `a binding with an incompatible parameter type fails to compile`() {
compile(
"""
package com.squareup.test
import dagger.Binds
import dagger.Module
import javax.inject.Inject
interface Lorem
open class Ipsum
class Foo @Inject constructor() : Ipsum(), Lorem
interface Bar
@Module
abstract class BarModule {
@Binds
abstract fun bindsBar(impl: Foo): Bar
}
"""
) {
assertThat(exitCode).isError()
assertThat(messages).contains(
"@Binds methods' parameter type must be assignable to the return type"
)
if (!useDagger) {
assertThat(messages).contains(
"Expected binding of type Bar but impl parameter of type Foo only has the following " +
"supertypes: [Ipsum, Lorem]"
)
}
}
}

@Test
fun `a binding with an incompatible parameter type with no supertypes fails to compile`() {
compile(
"""
package com.squareup.test
Expand All @@ -51,6 +86,11 @@ class BindsMethodValidatorTest(
assertThat(messages).contains(
"@Binds methods' parameter type must be assignable to the return type"
)
if (!useDagger) {
assertThat(messages).contains(
"Expected binding of type Bar but impl parameter of type Foo has no supertypes."
)
}
}
}

Expand Down

0 comments on commit 84ba1e5

Please sign in to comment.