Skip to content

Commit

Permalink
Improve error message for failed binding validations when the paramet…
Browse files Browse the repository at this point in the history
…erand return type do not match
  • Loading branch information
JoelWilcox committed Dec 16, 2022
1 parent a4a932c commit 3ee77e4
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 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,43 @@ 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()

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 return type of $returnType but impl parameter of type " +
"${paramSuperTypes.first()} only has the following supertypes: $paramSuperTypes",
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 @@ -37,7 +37,9 @@ class BindsMethodValidatorTest(
import dagger.Module
import javax.inject.Inject
class Foo @Inject constructor()
interface Lorem
open class Ipsum
class Foo @Inject constructor() : Ipsum(), Lorem
interface Bar
@Module
Expand All @@ -51,6 +53,12 @@ class BindsMethodValidatorTest(
assertThat(messages).contains(
"@Binds methods' parameter type must be assignable to the return type"
)
if (!useDagger) {
assertThat(messages).contains(
"Expected return type of Bar but impl parameter of type Foo only has the following " +
"supertypes: [Foo, Ipsum, Lorem]"
)
}
}
}

Expand Down

0 comments on commit 3ee77e4

Please sign in to comment.