Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Significantly improve error messaging when encountering error types #53

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
**Unreleased**
--------------

- Significantly improve error messaging when encountering error types. All these cases _should_ now also show the location of the error type in source and ease debugging.

0.2.3
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.squareup.anvil.compiler.ClassScannerKsp.GeneratedProperty.ScopeProper
import com.squareup.anvil.compiler.api.AnvilCompilationException
import com.squareup.anvil.compiler.codegen.ksp.KSCallable
import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException
import com.squareup.anvil.compiler.codegen.ksp.contextualToClassName
import com.squareup.anvil.compiler.codegen.ksp.fqName
import com.squareup.anvil.compiler.codegen.ksp.getAllCallables
import com.squareup.anvil.compiler.codegen.ksp.isAbstract
Expand All @@ -24,7 +25,6 @@ import com.squareup.anvil.compiler.codegen.ksp.resolvableAnnotations
import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration
import com.squareup.anvil.compiler.codegen.ksp.scope
import com.squareup.anvil.compiler.codegen.ksp.type
import com.squareup.kotlinpoet.ksp.toClassName
import org.jetbrains.kotlin.name.FqName

internal class ClassScannerKsp {
Expand Down Expand Up @@ -105,8 +105,8 @@ internal class ClassScannerKsp {
// Check that the annotation really is present. It should always be the case, but it's
// a safety net in case the generated properties are out of sync.
clazz.resolvableAnnotations.any {
it.annotationType.resolve()
.toClassName().fqName == annotation && (scope == null || it.scope() == scope)
it.annotationType
.contextualToClassName().fqName == annotation && (scope == null || it.scope() == scope)
}
}
.onEach { clazz ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ import com.squareup.anvil.compiler.codegen.generatedAnvilSubcomponentClassId
import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor
import com.squareup.anvil.compiler.codegen.ksp.KSCallable
import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException
import com.squareup.anvil.compiler.codegen.ksp.argumentAt
import com.squareup.anvil.compiler.codegen.ksp.argumentOfTypeAt
import com.squareup.anvil.compiler.codegen.ksp.atLeastOneAnnotation
import com.squareup.anvil.compiler.codegen.ksp.classId
import com.squareup.anvil.compiler.codegen.ksp.classNameArgumentAt
import com.squareup.anvil.compiler.codegen.ksp.classNameArrayArgumentAt
import com.squareup.anvil.compiler.codegen.ksp.contextualToClassName
import com.squareup.anvil.compiler.codegen.ksp.contextualToTypeName
import com.squareup.anvil.compiler.codegen.ksp.declaringClass
import com.squareup.anvil.compiler.codegen.ksp.exclude
import com.squareup.anvil.compiler.codegen.ksp.find
Expand All @@ -54,6 +58,7 @@ import com.squareup.anvil.compiler.codegen.ksp.mergeAnnotations
import com.squareup.anvil.compiler.codegen.ksp.modules
import com.squareup.anvil.compiler.codegen.ksp.parentScope
import com.squareup.anvil.compiler.codegen.ksp.replaces
import com.squareup.anvil.compiler.codegen.ksp.reportableReturnTypeNode
import com.squareup.anvil.compiler.codegen.ksp.resolvableAnnotations
import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration
import com.squareup.anvil.compiler.codegen.ksp.returnTypeOrNull
Expand Down Expand Up @@ -83,7 +88,6 @@ import com.squareup.kotlinpoet.ksp.addOriginatingKSFile
import com.squareup.kotlinpoet.ksp.toAnnotationSpec
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.toKModifier
import com.squareup.kotlinpoet.ksp.toTypeName
import com.squareup.kotlinpoet.ksp.writeTo
import dagger.Binds
import dagger.Component
Expand Down Expand Up @@ -285,7 +289,8 @@ internal class KspContributionMerger(
)
}

val scope = (daggerMergeAnnotations + interfaceMergerAnnotations).first().scope()
val scopeHolder = (daggerMergeAnnotations + interfaceMergerAnnotations).first()
val scope = scopeHolder.scope()

val creator = mergeComponentAnnotations.ifNotEmpty {
findCreator(
Expand All @@ -299,7 +304,7 @@ internal class KspContributionMerger(

generateMergedClass(
resolver = resolver,
scope = scope.toClassName(),
scope = scope.contextualToClassName(scopeHolder),
mergeAnnotatedClass = mergeAnnotatedClass,
originatingDeclarations = originatingDeclarations,
contributedSubcomponentData = contributedSubcomponentData,
Expand Down Expand Up @@ -581,17 +586,13 @@ internal class KspContributionMerger(

val boundType = bindingFunction.returnTypeOrNull()!!.resolveKSClassDeclaration()!!
val isMultibinding =
internalBindingMarker.argumentAt("isMultibinding")?.value == true
internalBindingMarker.argumentOfTypeAt<Boolean>("isMultibinding") == true
val qualifierKey =
(internalBindingMarker.argumentAt("qualifierKey")?.value as? String?).orEmpty()
val rank = (
internalBindingMarker.argumentAt("rank")
?.value as? Int?
)
?: ContributesBinding.RANK_NORMAL
internalBindingMarker.argumentOfTypeAt<String>("qualifierKey").orEmpty()
val rank = internalBindingMarker.argumentOfTypeAt<Int>("rank") ?: ContributesBinding.RANK_NORMAL
val scope = contributedAnnotation.scope()
ContributedBinding(
scope = scope.toClassName(),
scope = scope.contextualToClassName(contributedAnnotation),
isMultibinding = isMultibinding,
bindingModule = moduleClass.toClassName(),
originClass = originClass.toClassName(),
Expand Down Expand Up @@ -668,9 +669,7 @@ internal class KspContributionMerger(
fun copyArrayValue(name: String) {
val varargArguments = annotations
.mapNotNull { annotation ->
@Suppress("UNCHECKED_CAST")
(annotation.argumentAt(name)?.value as? List<KSType>?)
?.map(KSType::toClassName)
annotation.classNameArrayArgumentAt(name)
}
.flatten()
.ifEmpty { return }
Expand Down Expand Up @@ -1216,8 +1215,7 @@ internal class KspContributionMerger(
!mergeAnnotations.any { annotation ->
// If any of the parameters are unresolved, we need to defer this class
arrayOf("modules", "dependencies", "exclude", "includes").forEach { parameter ->
@Suppress("UNCHECKED_CAST")
(annotation.argumentAt(parameter)?.value as? List<KSType>?)?.let { values ->
annotation.argumentOfTypeAt<List<KSType>>(parameter)?.let { values ->
if (values.any(KSType::isError)) return@any true
}
}
Expand Down Expand Up @@ -1484,18 +1482,16 @@ private fun checkSameScope(
private fun KSClassDeclaration.originClass(): KSClassDeclaration {
val originClassValue = find(internalBindingMarkerFqName.asString())
.singleOrNull()
?.argumentAt("originClass")
?.value
?.argumentOfTypeAt<KSType>("originClass")

val originClass = (originClassValue as? KSType?)?.resolveKSClassDeclaration()
val originClass = originClassValue?.resolveKSClassDeclaration()
return originClass ?: this
}

private fun KSAnnotation.originClass(): KSClassDeclaration? {
val originClassValue = argumentAt("originClass")
?.value
val originClassValue = argumentOfTypeAt<KSType>("originClass")

val originClass = (originClassValue as? KSType?)?.resolveKSClassDeclaration()
val originClass = originClassValue?.resolveKSClassDeclaration()
return originClass
}

Expand Down Expand Up @@ -1587,7 +1583,7 @@ private fun Creator.extend(
.returns(newClassName)
.build(),
)
} else if (returnType?.toClassName() == originalComponentClassName) {
} else if (returnType?.contextualToClassName(function.reportableReturnTypeNode) == originalComponentClassName) {
// Handles functions that return the Component class, such as
// factory create() or builder build()
addFunction(
Expand Down Expand Up @@ -1885,7 +1881,7 @@ private fun generateParentComponent(
""".trimIndent() +
parentParentComponent.getAllFunctions().mapNotNull { function ->
function.qualifiedName?.let {
"${it.asString()}(): ${function.returnTypeOrNull()?.toTypeName()}"
"${it.asString()}(): ${function.returnTypeOrNull()?.contextualToTypeName(function.reportableReturnTypeNode)}"
}
}.joinToString("\n", prefix = "\n"),
node = origin,
Expand Down Expand Up @@ -1942,12 +1938,15 @@ private data class ContributedSubcomponentData(

companion object {
fun fromAnnotation(annotation: KSAnnotation): ContributedSubcomponentData {
val originClass = (annotation.argumentAt("originClass")?.value as KSType).toClassName()
val contributor = (annotation.argumentAt("contributor")?.value as KSType?)?.toClassName()
.takeUnless { it == NOTHING }
val originClass = annotation.classNameArgumentAt("originClass") ?: throw KspAnvilException(
message = "Could not find originClass value",
node = annotation,
)
val contributor = annotation.classNameArgumentAt("contributor")
?.takeUnless { it == NOTHING }
val componentFactory =
(annotation.argumentAt("componentFactory")?.value as KSType?)?.toClassName()
.takeUnless { it == NOTHING }
annotation.classNameArgumentAt("componentFactory")
?.takeUnless { it == NOTHING }
return ContributedSubcomponentData(
originClass = originClass,
contributor = contributor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.squareup.anvil.compiler.codegen.ksp.rank
import com.squareup.anvil.compiler.codegen.ksp.replaces
import com.squareup.anvil.compiler.codegen.ksp.resolveBoundType
import com.squareup.anvil.compiler.codegen.ksp.scope
import com.squareup.anvil.compiler.codegen.ksp.scopeClassName
import com.squareup.anvil.compiler.contributesBindingFqName
import com.squareup.anvil.compiler.internal.reference.asClassName
import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences
Expand Down Expand Up @@ -97,7 +98,7 @@ internal object ContributesBindingCodeGen : AnvilApplicabilityChecker {
.toList()
.also { it.checkNoDuplicateScopeAndBoundType(clazz) }
.map {
val scope = it.scope().toClassName()
val scope = it.scopeClassName()
val boundTypeDeclaration = it.resolveBoundType(resolver, clazz)
boundTypeDeclaration.checkNotGeneric(clazz)
val boundType = boundTypeDeclaration.toClassName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.squareup.anvil.compiler.codegen.ksp.replaces
import com.squareup.anvil.compiler.codegen.ksp.resolvableAnnotations
import com.squareup.anvil.compiler.codegen.ksp.resolveBoundType
import com.squareup.anvil.compiler.codegen.ksp.scope
import com.squareup.anvil.compiler.codegen.ksp.scopeClassName
import com.squareup.anvil.compiler.contributesMultibindingFqName
import com.squareup.anvil.compiler.internal.reference.asClassName
import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences
Expand Down Expand Up @@ -89,7 +90,7 @@ internal object ContributesMultibindingCodeGen : AnvilApplicabilityChecker {
.toList()
.also { it.checkNoDuplicateScopeAndBoundType(clazz) }
.map {
val scope = it.scope().toClassName()
val scope = it.scopeClassName()

val boundTypeDeclaration = it.resolveBoundType(resolver, clazz)
boundTypeDeclaration.checkNotGeneric(clazz)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType
import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent
import com.squareup.anvil.compiler.codegen.ksp.isInterface
import com.squareup.anvil.compiler.codegen.ksp.scope
import com.squareup.anvil.compiler.codegen.ksp.scopeClassName
import com.squareup.anvil.compiler.contributesToFqName
import com.squareup.anvil.compiler.daggerModuleFqName
import com.squareup.anvil.compiler.internal.createAnvilSpec
Expand Down Expand Up @@ -140,7 +141,7 @@ internal object ContributesToCodeGen : AnvilApplicabilityChecker {
val scopes = clazz.getKSAnnotationsByType(ContributesTo::class)
.toList()
.also { it.checkNoDuplicateScope(annotatedType = clazz, isContributeAnnotation = true) }
.map { it.scope().toClassName() }
.map { it.scopeClassName() }
.distinct()
// Give it a stable sort.
.sortedBy { it.canonicalName }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.squareup.anvil.compiler.PARENT_COMPONENT
import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor
import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException
import com.squareup.anvil.compiler.codegen.ksp.classId
import com.squareup.anvil.compiler.codegen.ksp.contextualToClassName
import com.squareup.anvil.compiler.codegen.ksp.declaringClass
import com.squareup.anvil.compiler.codegen.ksp.exclude
import com.squareup.anvil.compiler.codegen.ksp.find
Expand Down Expand Up @@ -136,7 +137,10 @@ internal class KspContributesSubcomponentHandlerSymbolProcessor(
.addAnnotation(
AnnotationSpec
.builder(MergeSubcomponent::class)
.addMember("scope = %T::class", contribution.scope.toClassName())
.addMember(
"scope = %T::class",
contribution.scope.contextualToClassName(contribution.annotation),
)
.apply {
fun addClassArrayMember(
name: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.squareup.anvil.compiler.codegen.dagger.AssistedFactoryCodeGen.KspGene
import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor
import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider
import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException
import com.squareup.anvil.compiler.codegen.ksp.contextualToTypeName
import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent
import com.squareup.anvil.compiler.codegen.ksp.isInterface
import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration
Expand Down Expand Up @@ -63,7 +64,6 @@ import com.squareup.kotlinpoet.asClassName
import com.squareup.kotlinpoet.jvm.jvmStatic
import com.squareup.kotlinpoet.ksp.TypeParameterResolver
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.toTypeName
import com.squareup.kotlinpoet.ksp.toTypeParameterResolver
import com.squareup.kotlinpoet.ksp.toTypeVariableName
import com.squareup.kotlinpoet.ksp.writeTo
Expand Down Expand Up @@ -142,7 +142,9 @@ internal object AssistedFactoryCodeGen : AnvilApplicabilityChecker {
// Compute for each parameter its key.
val functionParameterKeys = function.parameterKeys
val assistedParameterKeys = assistedParameters.map {
it.toAssistedParameterKey(it.type.resolve().toTypeName(typeParameterResolver))
it.toAssistedParameterKey(
it.type.resolve().contextualToTypeName(it.type, typeParameterResolver),
)
}

// The factory function may not have two or more parameters with the same key.
Expand Down Expand Up @@ -283,11 +285,11 @@ internal object AssistedFactoryCodeGen : AnvilApplicabilityChecker {
node = originalDeclaration,
parameterKeys = originalDeclaration.parameters.mapIndexed { index, param ->
param.toAssistedParameterKey(
parameterTypes[index]!!.toTypeName(typeParameterResolver),
parameterTypes[index]!!.contextualToTypeName(param, typeParameterResolver),
)
},
parameterPairs = originalDeclaration.parameters.mapIndexed { index, param ->
param to parameterTypes[index]!!.toTypeName(typeParameterResolver)
param to parameterTypes[index]!!.contextualToTypeName(param, typeParameterResolver)
},
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import com.squareup.anvil.compiler.codegen.CheckOnlyCodeGenerator
import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor
import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider
import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException
import com.squareup.anvil.compiler.codegen.ksp.contextualToTypeName
import com.squareup.anvil.compiler.codegen.ksp.getAnnotatedFunctions
import com.squareup.anvil.compiler.codegen.ksp.getAnnotatedSymbols
import com.squareup.anvil.compiler.codegen.ksp.isExtensionDeclaration
import com.squareup.anvil.compiler.codegen.ksp.reportableReturnTypeNode
import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration
import com.squareup.anvil.compiler.codegen.ksp.returnTypeOrNull
import com.squareup.anvil.compiler.codegen.ksp.superTypesExcludingAny
Expand All @@ -31,7 +33,6 @@ import com.squareup.anvil.compiler.internal.reference.TypeReference
import com.squareup.anvil.compiler.internal.reference.allSuperTypeClassReferences
import com.squareup.anvil.compiler.internal.reference.asTypeName
import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences
import com.squareup.kotlinpoet.ksp.toTypeName
import dagger.Binds
import dagger.Module
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
Expand Down Expand Up @@ -136,14 +137,16 @@ internal object BindsMethodValidator : AnvilApplicabilityChecker {
val superTypeNames =
bindingParameter
.resolveSuperTypesExcludingAny()
.map { it.toTypeName().toString() }
.map { it.contextualToTypeName(bindingParameter).toString() }
.toList()

throw KspAnvilException(
message = Errors.bindsParameterMustBeAssignable(
bindingParameterSuperTypeNames = superTypeNames,
returnTypeName = returnType.toTypeName().toString(),
parameterType = bindingParameter.toTypeName().toString(),
returnTypeName = returnType.contextualToTypeName(
function.reportableReturnTypeNode,
).toString(),
parameterType = bindingParameter.contextualToTypeName().toString(),
),
node = function,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.google.devtools.ksp.symbol.KSValueParameter
import com.google.devtools.ksp.symbol.Visibility
import com.squareup.anvil.compiler.assistedFqName
import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException
import com.squareup.anvil.compiler.codegen.ksp.contextualToTypeName
import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType
import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent
import com.squareup.anvil.compiler.codegen.ksp.isInterface
Expand Down Expand Up @@ -55,7 +56,6 @@ import com.squareup.kotlinpoet.asClassName
import com.squareup.kotlinpoet.ksp.TypeParameterResolver
import com.squareup.kotlinpoet.ksp.toAnnotationSpec
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.toTypeName
import com.squareup.kotlinpoet.ksp.toTypeParameterResolver
import dagger.Lazy
import dagger.assisted.Assisted
Expand Down Expand Up @@ -134,7 +134,7 @@ private fun KSValueParameter.toConstructorParameter(
typeParameterResolver: TypeParameterResolver,
): ConstructorParameter {
val type = type.resolve()
val paramTypeName = type.toTypeName(typeParameterResolver)
val paramTypeName = type.contextualToTypeName(this, typeParameterResolver)
val rawType = paramTypeName.requireRawType()

val isWrappedInProvider = rawType == providerClassName
Expand Down Expand Up @@ -463,7 +463,7 @@ private fun KSPropertyDeclaration.toMemberInjectParameter(
val classParams = implementingClass.typeParameters.toTypeParameterResolver()
val resolvedType = asMemberOf(implementingType)
// TODO do we want to convert function types to lambdas?
val propertyTypeName = resolvedType.toTypeName(classParams)
val propertyTypeName = resolvedType.contextualToTypeName(this, classParams)
val rawType = propertyTypeName.requireRawType()

val isWrappedInProvider = rawType == providerClassName
Expand Down
Loading
Loading