Repository: evant/kotlin-inject
Pull request #62 (2020-09-22 17:37:42)

support javax.inject.Qualifier
  #9


Patch:
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt
index 03da341..7b19230 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt
@@ -29,13 +29,13 @@ interface Messenger {
 sealed class AstElement : AstAnnotated {
     inline fun <reified T : Annotation> hasAnnotation() = hasAnnotation(T::class.qualifiedName!!)
 
-    inline fun <reified T : Annotation> typeAnnotatedWith(): AstClass? = typeAnnotatedWith(T::class.qualifiedName!!)
+    inline fun <reified T : Annotation> annotationAnnotatedWith(): AstAnnotation? = annotationAnnotatedWith(T::class.qualifiedName!!)
 }
 
 interface AstAnnotated {
     fun hasAnnotation(className: String): Boolean
 
-    fun typeAnnotatedWith(className: String): AstClass?
+    fun annotationAnnotatedWith(className: String): AstAnnotation?
 }
 
 abstract class AstBasicElement : AstElement() {
@@ -179,7 +179,9 @@ abstract class AstType : AstElement() {
     }
 }
 
-abstract class AstAnnotation : AstElement()
+abstract class AstAnnotation : AstElement() {
+    abstract val type: AstType
+}
 
 abstract class AstParam : AstElement() {
 
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
index bab3bdd..5e462d5 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
@@ -88,7 +88,7 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
 
                                     codeBlock.add(
                                         provide(
-                                            key = TypeKey(returnType),
+                                            key = TypeKey(returnType, method.qualifier(options)),
                                             context = context
                                         )
                                     )
@@ -241,14 +241,14 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
             when (method) {
                 is AstProperty -> {
                     if (receiverParamType != null) {
-                        codeBlock.add(provide(key = TypeKey(receiverParamType), context = context))
+                        codeBlock.add(provide(key = TypeKey(receiverParamType, method.qualifier(options)), context = context))
                         codeBlock.add(".")
                     }
                     codeBlock.add("%N", method.name)
                 }
                 is AstFunction -> {
                     if (receiverParamType != null) {
-                        codeBlock.add(provide(key = TypeKey(receiverParamType), context = context))
+                        codeBlock.add(provide(key = TypeKey(receiverParamType, method.qualifier(options)), context = context))
                         codeBlock.add(".")
                     }
                     codeBlock.add("%N(", method.name)
@@ -259,7 +259,7 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
                         }
                         codeBlock.add(
                             provide(
-                                key = TypeKey(param.type),
+                                key = TypeKey(param.type, param.qualifier(options)),
                                 context = context
                             ) { context, key -> context.findWithIndex(key, i, size) })
                     }
@@ -286,7 +286,7 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
             if (i != 0) {
                 codeBlock.add(",")
             }
-            codeBlock.add(provide(key = TypeKey(param.type), context = context) { context, key ->
+            codeBlock.add(provide(key = TypeKey(param.type, param.qualifier(options)), context = context) { context, key ->
                 context.findWithIndex(key, i, size)
             })
         }
@@ -369,7 +369,7 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
                     if (i != 0) {
                         add(",")
                     }
-                    add(provide(TypeKey(param.type), context.withArgs(argList)) { context, key ->
+                    add(provide(TypeKey(param.type, param.qualifier(options)), context.withArgs(argList)) { context, key ->
                         context.findWithIndex(key, i, size)
                     })
                 }
@@ -419,7 +419,7 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
                     )
                 }
             }
-            val fKey = TypeKey(resolveType.arguments.last())
+            val fKey = TypeKey(resolveType.arguments.last(), key.qualifier)
             return Result.Function(
                 element = key.type.toAstClass(),
                 key = fKey,
@@ -427,7 +427,7 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
             )
         }
         if (key.type.packageName == "kotlin" && key.type.simpleName == "Lazy") {
-            val lKey = TypeKey(key.type.arguments[0])
+            val lKey = TypeKey(key.type.arguments[0], key.qualifier)
             return Result.Lazy(key = lKey)
         }
         return null
@@ -515,14 +515,14 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
 }
 
 
-fun AstElement.scopeType(options: Options): AstClass? {
+fun AstElement.scopeType(options: Options): AstType? {
     if (options.enableJavaxAnnotations) {
-        val type = typeAnnotatedWith("javax.inject.Scope")
-        if (type != null) {
-            return type
+        val annotation = annotationAnnotatedWith("javax.inject.Scope")
+        if (annotation != null) {
+            return annotation.type
         }
     }
-    return typeAnnotatedWith<Scope>()
+    return annotationAnnotatedWith<Scope>()?.type
 }
 
 private fun String.asScopedProp(): String = "_" + decapitalize()
@@ -540,6 +540,14 @@ fun AstClass.isInject(options: Options): Boolean {
     return hasAnnotation<Inject>()
 }
 
+fun AstElement.qualifier(options: Options): Any? {
+    return if (options.enableJavaxAnnotations) {
+        annotationAnnotatedWith("javax.inject.Qualifier")
+    } else {
+        null
+    }
+}
+
 fun AstMethod.isProvider(): Boolean =
     !hasAnnotation<Provides>() && AstModifier.ABSTRACT in modifiers && when (this) {
         is AstFunction -> parameters.isEmpty()
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
index ca4bb8c..6359dd9 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
@@ -31,7 +31,7 @@ class TypeCollector private constructor(private val provider: AstProvider, priva
     private val _scoped = mutableListOf<AstType>()
 
     // Map of scoped components and the accessors to obtain them
-    private val scopedAccessors = mutableMapOf<AstClass, ScopedComponent>()
+    private val scopedAccessors = mutableMapOf<AstType, ScopedComponent>()
 
     private fun collectTypes(
         astClass: AstClass,
@@ -99,7 +99,7 @@ class TypeCollector private constructor(private val provider: AstProvider, priva
                 val type = method.returnTypeFor(astClass)
                 if (type.packageName == "kotlin" && type.simpleName == "Pair") {
                     val typeArgs = method.returnTypeFor(astClass).arguments
-                    val mapType = TypeKey(declaredTypeOf(Map::class, typeArgs[0], typeArgs[1]))
+                    val mapType = TypeKey(declaredTypeOf(Map::class, typeArgs[0], typeArgs[1]), method.qualifier(options))
                     addContainerType(mapType, mapOf, method, accessor, scopedComponent)
                 } else {
                     error("@IntoMap must have return type of type Pair", method)
@@ -110,7 +110,7 @@ class TypeCollector private constructor(private val provider: AstProvider, priva
                 addContainerType(setType, setOf, method, accessor, scopedComponent)
             } else {
                 val returnType = method.returnTypeFor(astClass)
-                val key = TypeKey(returnType)
+                val key = TypeKey(returnType, method.qualifier(options))
                 addMethod(key, method, accessor, scopedComponent)
                 if (scopeType != null) {
                     _scoped.add(returnType)
@@ -120,7 +120,7 @@ class TypeCollector private constructor(private val provider: AstProvider, priva
 
         for (method in providerMethods) {
             val returnType = method.returnTypeFor(astClass)
-            val key = TypeKey(returnType)
+            val key = TypeKey(returnType, method.qualifier(options))
             if (isComponent) {
                 addProviderMethod(key, method, accessor)
             } else {
@@ -230,7 +230,7 @@ sealed class TypeCreator(val source: AstElement) {
     class Constructor(
         val constructor: AstConstructor,
         val accessor: String? = null,
-        val scope: AstClass? = null,
+        val scope: AstType? = null,
         val scopedComponent: AstClass? = null
     ) :
         TypeCreator(constructor)
@@ -238,7 +238,7 @@ sealed class TypeCreator(val source: AstElement) {
     class Method(
         val method: AstMethod,
         val accessor: String? = null,
-        val scope: AstClass? = null,
+        val scope: AstType? = null,
         val scopedComponent: AstClass? = null
     ) : TypeCreator(method)
 
diff --git a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt
index 01245d0..cc12c34 100644
--- a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt
+++ b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt
@@ -1,11 +1,7 @@
 package me.tatarka.inject.compiler.kapt
 
 import me.tatarka.inject.annotations.Component
-import me.tatarka.inject.compiler.AstClass
-import me.tatarka.inject.compiler.FailedToGenerateException
-import me.tatarka.inject.compiler.InjectGenerator
-import me.tatarka.inject.compiler.scopeClass
-import me.tatarka.inject.compiler.scopeType
+import me.tatarka.inject.compiler.*
 import javax.annotation.processing.RoundEnvironment
 import javax.lang.model.element.TypeElement
 
@@ -45,8 +41,8 @@ class InjectCompiler : BaseInjectCompiler() {
         return false
     }
 
-    private fun scopedClasses(scopeType: AstClass, env: RoundEnvironment): List<AstClass> {
-        return env.getElementsAnnotatedWith(scopeType.element).mapNotNull {
+    private fun scopedClasses(scopeType: AstType, env: RoundEnvironment): List<AstClass> {
+        return env.getElementsAnnotatedWith(scopeType.toAstClass().element).mapNotNull {
             (it as? TypeElement)?.toAstClass()
         }
     }
diff --git a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt
index bcc549f..2916cb3 100644
--- a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt
+++ b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt
@@ -4,8 +4,8 @@ import com.squareup.kotlinpoet.*
 import com.squareup.kotlinpoet.ClassName
 import kotlinx.metadata.*
 import kotlinx.metadata.jvm.annotations
-import kotlinx.metadata.jvm.syntheticMethodForAnnotations
 import me.tatarka.inject.compiler.*
+import java.util.*
 import javax.annotation.processing.Messager
 import javax.annotation.processing.ProcessingEnvironment
 import javax.lang.model.element.*
@@ -132,8 +132,10 @@ private interface ModelAstElement : ModelAstProvider, AstAnnotated {
         return element.hasAnnotation(className)
     }
 
-    override fun typeAnnotatedWith(className: String): AstClass? {
-        return element.typeAnnotatedWith(className)?.toAstClass()
+    override fun annotationAnnotatedWith(className: String): AstAnnotation? {
+        return element.annotationAnnotatedWith(className)?.let {
+            ModelAstAnnotation(this, it, null)
+        }
     }
 }
 
@@ -170,7 +172,7 @@ private class PrimitiveModelAstClass(
     }
 
     override fun hasAnnotation(className: String): Boolean = false
-    override fun typeAnnotatedWith(className: String): AstClass? = null
+    override fun annotationAnnotatedWith(className: String): AstAnnotation? = null
 }
 
 private class ModelAstClass(
@@ -463,17 +465,15 @@ private class ModelAstType(
         }
 
     override val annotations: List<AstAnnotation> by lazy {
-        if (kmType != null) {
-            kmType.annotations.map { annotation ->
-                val mirror = provider.elements.getTypeElement(annotation.className.replace('/', '.'))
-                ModelAstAnnotation(
-                    this,
-                    mirror.asType() as DeclaredType,
-                    annotation
-                )
-            }
-        } else {
-            emptyList()
+        val typeAnnotations = type.annotationMirrors
+        val kmTypeAnnotations = kmType?.annotations
+        typeAnnotations.mapIndexed { index, annotation ->
+            val kmAnnotation = kmTypeAnnotations?.get(index)
+            ModelAstAnnotation(
+                this,
+                annotation,
+                kmAnnotation
+            )
         }
     }
 
@@ -539,25 +539,33 @@ private class ModelAstType(
 
 private class ModelAstAnnotation(
     provider: ModelAstProvider,
-    val annotationType: DeclaredType,
-    private val kmAnnotation: KmAnnotation
+    val mirror: AnnotationMirror,
+    private val kmAnnotation: KmAnnotation?
 ) : AstAnnotation(),
     ModelAstElement, ModelAstProvider by provider {
-    override val element: Element get() = types.asElement(annotationType)
+    override val element: Element get() = types.asElement(mirror.annotationType)
+
+    override val type: AstType
+        get() = ModelAstType(this, mirror.annotationType, kmAnnotation?.type)
 
     override fun equals(other: Any?): Boolean {
         if (other !is ModelAstAnnotation) return false
-        return kmAnnotation == other.kmAnnotation
+        return kmAnnotation == other.kmAnnotation && mirror.eqv(other.mirror)
     }
 
     override fun hashCode(): Int {
-        return kmAnnotation.hashCode()
+        return Objects.hash(kmAnnotation, mirror.annotationType)
     }
 
     override fun toString(): String {
-        return "@$annotationType(${
-            kmAnnotation.arguments.toList()
-                .joinToString(separator = ", ") { (name, value) -> "$name=${value.value}" }
+        return "@${mirror.annotationType}(${
+            if (kmAnnotation != null) {
+                kmAnnotation.arguments.toList()
+                    .joinToString(separator = ", ") { (name, value) -> "$name=${value.value}" }
+            } else {
+                mirror.elementValues.toList()
+                    .joinToString(separator = ", ") { (element, value) -> "${element.simpleName}=${value.value}" }
+            }
         })"
     }
 }
diff --git a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt
index 8ea5616..93b1d75 100644
--- a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt
+++ b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt
@@ -5,10 +5,7 @@ import com.squareup.kotlinpoet.ClassName
 import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
 import kotlinx.metadata.*
 import kotlinx.metadata.jvm.*
-import javax.lang.model.element.Element
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.Modifier
-import javax.lang.model.element.TypeElement
+import javax.lang.model.element.*
 import javax.lang.model.type.*
 import javax.lang.model.util.SimpleTypeVisitor7
 
@@ -16,10 +13,10 @@ fun Element.hasAnnotation(className: String): Boolean {
     return annotationMirrors.any { it.annotationType.toString() == className }
 }
 
-fun Element.typeAnnotatedWith(className: String) =
+fun Element.annotationAnnotatedWith(className: String) =
     annotationMirrors.find {
         it.annotationType.asElement().hasAnnotation(className)
-    }?.annotationType?.asElement() as? TypeElement
+    }
 
 val TypeElement.metadata: KotlinClassMetadata?
     get() {
@@ -217,4 +214,18 @@ fun KmType.asTypeName(): TypeName? {
     } else {
         className.parameterizedBy(arguments.map { it.type!!.asTypeName()!! })
     }.copy(nullable = isNullable)
+}
+
+fun AnnotationMirror.eqv(other: AnnotationMirror): Boolean {
+    if (annotationType != other.annotationType) {
+        return false
+    }
+    val values = elementValues.values
+    val otherValues = other.elementValues.values
+
+    if (values.size != otherValues.size) {
+        return false
+    }
+
+    return values.zip(otherValues).all { (a, b) -> a.value == b.value }
 }
\ No newline at end of file
diff --git a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt
index 41b37e5..2e0a343 100644
--- a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt
+++ b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt
@@ -54,8 +54,8 @@ class InjectProcessor : SymbolProcessor, KSAstProvider {
         }
     }
 
-    private fun scopedClasses(scopeType: AstClass, resolver: Resolver): List<AstClass> {
-        return resolver.getSymbolsWithAnnotation(scopeType.asClassName().toString()).mapNotNull {
+    private fun scopedClasses(scopeType: AstType, resolver: Resolver): List<AstClass> {
+        return resolver.getSymbolsWithAnnotation(scopeType.toAstClass().asClassName().toString()).mapNotNull {
             (it as? KSClassDeclaration)?.toAstClass()
         }
     }
diff --git a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt
index caf5dad..d9bbd4f 100644
--- a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt
+++ b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.ksp.isPrivate
 import org.jetbrains.kotlin.ksp.processing.KSPLogger
 import org.jetbrains.kotlin.ksp.processing.Resolver
 import org.jetbrains.kotlin.ksp.symbol.*
+import java.util.*
 import kotlin.reflect.KClass
 
 interface KSAstProvider : AstProvider {
@@ -111,8 +112,10 @@ private interface KSAstAnnotated : AstAnnotated, KSAstProvider {
         return declaration.hasAnnotation(className)
     }
 
-    override fun typeAnnotatedWith(className: String): AstClass? {
-        return (declaration.typeAnnotatedWith(className)?.declaration as? KSClassDeclaration)?.toAstClass()
+    override fun annotationAnnotatedWith(className: String): AstAnnotation? {
+        return declaration.annotationAnnotatedWith(className)?.let {
+            KSAstAnnotation(this, it)
+        }
     }
 }
 
@@ -271,9 +274,13 @@ private class KSAstProperty(provider: KSAstProvider, override val declaration: K
                 || declaration.hasAnnotation(className, AnnotationUseSiteTarget.GET)
     }
 
-    override fun typeAnnotatedWith(className: String): AstClass? {
-        return (declaration.getter?.typeAnnotatedWith(className)?.declaration as? KSClassDeclaration)?.toAstClass()
-            ?: (declaration.typeAnnotatedWith(className, AnnotationUseSiteTarget.GET)?.declaration as? KSClassDeclaration)?.toAstClass()
+    override fun annotationAnnotatedWith(className: String): AstAnnotation? {
+        return (declaration.getter?.annotationAnnotatedWith(className) ?: declaration.annotationAnnotatedWith(
+            className,
+            AnnotationUseSiteTarget.GET
+        ))?.let {
+            KSAstAnnotation(this, it)
+        }
     }
 
     override fun equals(other: Any?): Boolean {
@@ -396,6 +403,33 @@ private class KSAstParam(
     override fun toString(): String = "$name: $type"
 }
 
+private class KSAstAnnotation(provider: KSAstProvider, val annotation: KSAnnotation) : AstAnnotation(),
+    KSAstProvider by provider {
+
+    override val type: AstType
+        get() = KSAstType(this, annotation.annotationType)
+
+    override fun hasAnnotation(className: String): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun annotationAnnotatedWith(className: String): AstAnnotation? {
+        TODO("Not yet implemented")
+    }
+
+    override fun equals(other: Any?): Boolean {
+        return other is KSAstAnnotation && annotation.eqv(other.annotation)
+    }
+
+    override fun hashCode(): Int {
+        return toString().hashCode()
+    }
+
+    override fun toString(): String {
+        return "${annotation}(${annotation.arguments.joinToString(", ") { arg -> "${arg.name?.asString()}=${arg.value}" }})"
+    }
+}
+
 private fun collectModifiers(declaration: KSDeclaration): Set<AstModifier> {
     return mutableSetOf<AstModifier>().apply {
         if (declaration.isPrivate()) {
diff --git a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt
index c89cccb..40befbb 100644
--- a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt
+++ b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt
@@ -6,26 +6,16 @@ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
 import com.squareup.kotlinpoet.TypeName
 import com.squareup.kotlinpoet.TypeVariableName
 import org.jetbrains.kotlin.ksp.isAbstract
-import org.jetbrains.kotlin.ksp.symbol.AnnotationUseSiteTarget
-import org.jetbrains.kotlin.ksp.symbol.KSAnnotated
-import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
-import org.jetbrains.kotlin.ksp.symbol.KSDeclaration
-import org.jetbrains.kotlin.ksp.symbol.KSFunctionDeclaration
-import org.jetbrains.kotlin.ksp.symbol.KSNode
-import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
-import org.jetbrains.kotlin.ksp.symbol.KSType
-import org.jetbrains.kotlin.ksp.symbol.KSTypeAlias
-import org.jetbrains.kotlin.ksp.symbol.KSTypeParameter
-import org.jetbrains.kotlin.ksp.symbol.KSTypeReference
-import org.jetbrains.kotlin.ksp.symbol.Nullability
-import org.jetbrains.kotlin.ksp.symbol.Variance
+import org.jetbrains.kotlin.ksp.symbol.*
 import org.jetbrains.kotlin.ksp.visitor.KSDefaultVisitor
 
-fun KSAnnotated.typeAnnotatedWith(className: String, useSiteTarget: AnnotationUseSiteTarget? = null): KSType? {
+fun KSAnnotated.annotationAnnotatedWith(className: String, useSiteTarget: AnnotationUseSiteTarget? = null): KSAnnotation? {
     for (annotation in annotations) {
-        val t = annotation.annotationType.resolve()
-        if (t?.declaration?.hasAnnotation(className, useSiteTarget) == true) {
-            return t
+        if (annotation.useSiteTarget == useSiteTarget) {
+            val t = annotation.annotationType.resolve()
+            if (t?.declaration?.hasAnnotation(className) == true) {
+                return annotation
+            }
         }
     }
     return null
@@ -108,3 +98,7 @@ fun KSType.asTypeName(): TypeName {
     }, Unit)
 }
 
+fun KSAnnotation.eqv(other: KSAnnotation): Boolean {
+    return annotationType.resolve() == other.annotationType.resolve() &&
+            arguments == other.arguments
+}
\ No newline at end of file


Test patch:
diff --git a/integration-tests/src/test/kotlin/me/tatarka/inject/test/JavaxAnnotationTest.kt b/integration-tests/src/test/kotlin/me/tatarka/inject/test/JavaxAnnotationTest.kt
index f9ae181..950d7ff 100644
--- a/integration-tests/src/test/kotlin/me/tatarka/inject/test/JavaxAnnotationTest.kt
+++ b/integration-tests/src/test/kotlin/me/tatarka/inject/test/JavaxAnnotationTest.kt
@@ -1,9 +1,12 @@
 package me.tatarka.inject.test
 
 import assertk.assertThat
+import assertk.assertions.isEqualTo
 import assertk.assertions.isNotNull
 import me.tatarka.inject.annotations.Component
+import me.tatarka.inject.annotations.Provides
 import javax.inject.Inject
+import javax.inject.Named
 import javax.inject.Scope
 import kotlin.test.Test
 
@@ -19,6 +22,22 @@ abstract class JavaxComponent {
     abstract val foo: JavaxFoo
 }
 
+@Component
+abstract class NamedComponent {
+
+    @get:Named("one")
+    abstract val one: String
+
+    @get:Named("two")
+    abstract val two: String
+
+    val provide1: String
+        @Provides @Named("one") get() = "one"
+
+    val provide2: String
+        @Provides @Named("two") get() = "two"
+}
+
 class JavaxAnnotationTest {
 
     @Test
@@ -27,4 +46,12 @@ class JavaxAnnotationTest {
 
         assertThat(component.foo).isNotNull()
     }
+
+    @Test
+    fun generates_a_component_that_supports_the_named_qualifier() {
+        val component = NamedComponent::class.create()
+
+        assertThat(component.one).isEqualTo("one")
+        assertThat(component.two).isEqualTo("two")
+    }
 }
\ No newline at end of file