Repository: evant/kotlin-inject
Pull request #25 (2020-08-01 05:08:57)

Update ksp and support type aliases


Patch:
diff --git a/README.md b/README.md
index f6ddc93..5d62949 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ dependencies {
 ### Expiramental KSP Support 
 
 You can use [ksp](https://github.com/android/kotlin/tree/ksp/libraries/tools/kotlin-symbol-processing-api) instead of 
-kapt. Currently everything except type aliases and function injection is implemented.
+kapt. Currently everything except function injection is implemented.
 
 `settings.gradle`
 ```groovy
@@ -70,8 +70,8 @@ pluginManagement {
 `build.gradle`
 ```groovy
 plugins {
-    id 'org.jetbrains.kotlin.jvm' version "1.4-M1"
-    id 'org.jetbrains.kotlin.ksp' version "1.4-M1-dev-experimental-20200716"
+    id 'org.jetbrains.kotlin.jvm' version "1.4.0-rc"
+    id 'org.jetbrains.kotlin.ksp' version "1.4.0-rc-dev-experimental-20200731"
 }
 
 repositories {
diff --git a/integration-tests-kapt/src/test/kotlin/me/tatarka/inject/test/TypeAliasTest.kt b/integration-tests/src/test/kotlin/me/tatarka/inject/test/TypeAliasTest.kt
similarity index 100%
rename from integration-tests-kapt/src/test/kotlin/me/tatarka/inject/test/TypeAliasTest.kt
rename to integration-tests/src/test/kotlin/me/tatarka/inject/test/TypeAliasTest.kt
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 6a13346..77ae2ac 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
@@ -6,21 +6,21 @@ import kotlin.reflect.KClass
 interface AstProvider {
     val messenger: Messenger
 
-    fun findFunctions(name: String): List<AstFunction>
+    fun findFunctions(packageName: String, functionName: String): List<AstFunction>
 
     fun declaredTypeOf(klass: KClass<*>, vararg astTypes: AstType): AstType
 
-    fun warn(message: String, element: AstElement? = null) = messenger.warn(message, element)
+    fun warn(message: String, element: AstElement) = messenger.warn(message, element)
 
-    fun error(message: String, element: AstElement?) = messenger.error(message, element)
+    fun error(message: String, element: AstElement) = messenger.error(message, element)
 
     fun TypeSpec.Builder.addOriginatingElement(astClass: AstClass): TypeSpec.Builder
 }
 
 interface Messenger {
-    fun warn(message: String, element: AstElement? = null)
+    fun warn(message: String, element: AstElement)
 
-    fun error(message: String, element: AstElement?)
+    fun error(message: String, element: AstElement)
 }
 
 sealed class AstElement : AstAnnotated {
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/FailedToGenerateException.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/FailedToGenerateException.kt
index bf74609..b1c76d6 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/FailedToGenerateException.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/FailedToGenerateException.kt
@@ -1,3 +1,3 @@
 package me.tatarka.inject.compiler
 
-class FailedToGenerateException(message: String, val element: AstElement?) : Exception(message)
+class FailedToGenerateException(message: String, val element: AstElement) : Exception(message)
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 b32a1a5..e8e7b40 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
@@ -427,7 +427,9 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
             val typeAliasName = key.type.typeAliasName
             if (typeAliasName != null) {
                 // Check to see if we have a function matching the type alias
-                val functions = findFunctions(typeAliasName)
+                val packageName = typeAliasName.substringBeforeLast('.')
+                val simpleName = typeAliasName.substringAfterLast('.')
+                val functions = findFunctions(packageName, simpleName)
                 val injectedFunction = functions.find { it.hasAnnotation<Inject>() }
                 if (injectedFunction != null) {
                     return Result.NamedFunction(
@@ -450,7 +452,7 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
     }
 
     data class Context(
-        val source: AstClass? = null,
+        val source: AstClass,
         val collector: TypeCollector,
         val scopeInterface: AstClass? = null,
         val args: List<Pair<AstType, String>> = emptyList(),
@@ -499,7 +501,7 @@ fun AstClass.scopeClass(messenger: Messenger): AstClass? {
                 elementScopeClass = parentClass
             } else {
                 messenger.error("Cannot apply scope: $parentScope", parentClass)
-                messenger.error("as scope: ${elementScopeClass!!.scopeType()} is already applied", elementScopeClass)
+                messenger.error("as scope: ${elementScopeClass!!.scopeType()} is already applied", elementScopeClass!!)
             }
         }
     }
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 b2cd812..9f1513f 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
@@ -37,20 +37,18 @@ interface ModelAstProvider :
         return ModelAstClass(this@ModelAstProvider, this, metadata?.toKmClass())
     }
 
-    override fun findFunctions(name: String): List<AstFunction> {
-        val packageName = name.substringBeforeLast('.')
-        val simpleName = name.substringAfterLast('.')
+    override fun findFunctions(packageName: String, functionName: String): List<AstFunction> {
         val packageElement = elements.getPackageElement(packageName)
         val results = mutableListOf<AstFunction>()
         for (element in ElementFilter.typesIn(packageElement.enclosedElements)) {
             for (function in ElementFilter.methodsIn(element.enclosedElements)) {
-                if (function.simpleName.contentEquals(simpleName)
+                if (function.simpleName.contentEquals(functionName)
                     && function.modifiers.contains(Modifier.STATIC) && function.modifiers.contains(Modifier.STATIC) && function.modifiers.contains(
                         Modifier.FINAL
                     )
                 ) {
                     val metadata = element.metadata?.toKmPackage() ?: continue
-                    val kmFunction = metadata.functions.find { it.name == simpleName } ?: continue
+                    val kmFunction = metadata.functions.find { it.name == functionName } ?: continue
                     results.add(ModelAstFunction(this, element, function, kmFunction))
                 }
             }
@@ -78,16 +76,16 @@ interface ModelAstProvider :
 }
 
 class ModelAstMessenger(private val messager: Messager) : Messenger {
-    override fun warn(message: String, element: AstElement?) {
+    override fun warn(message: String, element: AstElement) {
         print(Diagnostic.Kind.WARNING, message, element)
     }
 
-    override fun error(message: String, element: AstElement?) {
+    override fun error(message: String, element: AstElement) {
         print(Diagnostic.Kind.ERROR, message, element)
     }
 
-    private fun print(kind: Diagnostic.Kind, message: String, element: AstElement?) {
-        messager.printMessage(kind, message, (element as? ModelAstElement)?.element)
+    private fun print(kind: Diagnostic.Kind, message: String, element: AstElement) {
+        messager.printMessage(kind, message, (element as ModelAstElement).element)
     }
 }
 
diff --git a/kotlin-inject-compiler-ksp/build.gradle b/kotlin-inject-compiler-ksp/build.gradle
index cc903eb..1040383 100644
--- a/kotlin-inject-compiler-ksp/build.gradle
+++ b/kotlin-inject-compiler-ksp/build.gradle
@@ -1,12 +1,12 @@
 plugins {
-    id 'org.jetbrains.kotlin.jvm' version '1.4-M1'
+    id 'org.jetbrains.kotlin.jvm' version '1.4.0-rc'
 }
 
 dependencies {
     implementation project(':kotlin-inject-runtime')
     implementation project(':kotlin-inject-compiler-core')
     implementation "org.jetbrains.kotlin:kotlin-stdlib"
-    implementation 'org.jetbrains.kotlin:kotlin-symbol-processing-api:1.4-M1-dev-experimental-20200716'
+    implementation 'org.jetbrains.kotlin:kotlin-symbol-processing-api:1.4.0-rc-dev-experimental-20200731'
 }
 
 sourceCompatibility = 1.8
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 c7c2573..de82f6f 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
@@ -4,21 +4,27 @@ import com.squareup.kotlinpoet.FileSpec
 import me.tatarka.inject.annotations.Component
 import me.tatarka.inject.compiler.*
 import org.jetbrains.kotlin.ksp.processing.CodeGenerator
+import org.jetbrains.kotlin.ksp.processing.KSPLogger
 import org.jetbrains.kotlin.ksp.processing.Resolver
 import org.jetbrains.kotlin.ksp.processing.SymbolProcessor
 import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
-import org.jetbrains.kotlin.ksp.symbol.KSType
-import java.io.FileWriter
 
 class InjectProcessor : SymbolProcessor, KSAstProvider {
 
     private lateinit var options: Options
     private lateinit var codeGenerator: CodeGenerator
     override lateinit var resolver: Resolver
+    override lateinit var logger: KSPLogger
 
-    override fun init(options: Map<String, String>, kotlinVersion: KotlinVersion, codeGenerator: CodeGenerator) {
+    override fun init(
+        options: Map<String, String>,
+        kotlinVersion: KotlinVersion,
+        codeGenerator: CodeGenerator,
+        logger: KSPLogger
+    ) {
         this.options = Options.from(options)
         this.codeGenerator = codeGenerator
+        this.logger = logger
     }
 
     override fun process(resolver: Resolver) {
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 7ad631c..012108f 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
@@ -2,9 +2,11 @@ package me.tatarka.inject.compiler.ksp
 
 import com.squareup.kotlinpoet.*
 import me.tatarka.inject.compiler.*
+import org.jetbrains.kotlin.ksp.findActualType
 import org.jetbrains.kotlin.ksp.getDeclaredFunctions
 import org.jetbrains.kotlin.ksp.getDeclaredProperties
 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 kotlin.reflect.KClass
@@ -13,15 +15,27 @@ interface KSAstProvider : AstProvider {
 
     val resolver: Resolver
 
+    val logger: KSPLogger
+
     override val messenger: KSAstMessenger
-        get() = KSAstMessenger
+        get() = KSAstMessenger.also {
+            it.logger = logger
+        }
 
     fun KSClassDeclaration.toAstClass(): AstClass {
         return KSAstClass(this@KSAstProvider, this)
     }
 
-    override fun findFunctions(name: String): List<AstFunction> {
-        return emptyList()
+    override fun findFunctions(packageName: String, functionName: String): List<AstFunction> {
+        return resolver.getAllFiles().filter { it.packageName.asString() == packageName }
+            .flatMap { it.declarations }
+            .mapNotNull { declaration ->
+                if (declaration is KSFunctionDeclaration && declaration.simpleName.asString() == functionName) {
+                    KSAstFunction(this, declaration)
+                } else {
+                    null
+                }
+            }
     }
 
     override fun declaredTypeOf(klass: KClass<*>, vararg astTypes: AstType): AstType {
@@ -36,12 +50,14 @@ interface KSAstProvider : AstProvider {
 
 object KSAstMessenger : Messenger {
     private val errorMessages = mutableListOf<Message>()
+    internal lateinit var logger: KSPLogger
 
-    override fun warn(message: String, element: AstElement?) {
-        //TODO https://github.com/android/kotlin/issues/1
+    override fun warn(message: String, element: AstElement) {
+        logger.warn(message, (element as KSAstAnnotated).declaration)
     }
 
-    override fun error(message: String, element: AstElement?) {
+    override fun error(message: String, element: AstElement) {
+        logger.error(message, (element as KSAstAnnotated).declaration)
         errorMessages.add(Message(message, element))
     }
 
@@ -270,14 +286,19 @@ private class KSAstType(provider: KSAstProvider) : AstType(), KSAstAnnotated, KS
 
     override val declaration: KSDeclaration get() = type.declaration
 
-    override val name: String
-        get() = type.declaration.qualifiedName!!.asString()
+    override val name: String by lazy {
+        when (val declaration = type.declaration) {
+            is KSClassDeclaration -> declaration.qualifiedName!!.asString()
+            is KSTypeAlias -> declaration.findActualType().qualifiedName!!.asString()
+            else -> throw IllegalArgumentException("unknown declaration: $declaration")
+        }
+    }
 
     override val annotations: List<AstAnnotation>
         get() = TODO("Not yet implemented")
 
     override val typeAliasName: String?
-        get() = null //TODO
+        get() = (declaration as? KSTypeAlias)?.qualifiedName?.asString()
 
     override val arguments: List<AstType>
         get() = type.arguments.map {
@@ -293,7 +314,11 @@ private class KSAstType(provider: KSAstProvider) : AstType(), KSAstAnnotated, KS
     }
 
     override fun toAstClass(): AstClass {
-        return (declaration as KSClassDeclaration).toAstClass()
+        return when (val declaration = declaration) {
+            is KSClassDeclaration -> declaration.toAstClass()
+            is KSTypeAlias -> declaration.findActualType().toAstClass()
+            else -> throw IllegalArgumentException("unknown declaration: $declaration")
+        }
     }
 
     override fun asTypeName(): TypeName {
@@ -314,7 +339,11 @@ private class KSAstType(provider: KSAstProvider) : AstType(), KSAstAnnotated, KS
     }
 }
 
-private class KSAstParam(provider: KSAstProvider, val parent: KSDeclaration, override val declaration: KSVariableParameter) : AstParam(),
+private class KSAstParam(
+    provider: KSAstProvider,
+    val parent: KSDeclaration,
+    override val declaration: KSVariableParameter
+) : AstParam(),
     KSAstAnnotated, KSAstProvider by provider {
 
     override val name: String
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 00e6116..1f65a12 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
@@ -5,6 +5,7 @@ import com.squareup.kotlinpoet.KModifier
 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.*
 import org.jetbrains.kotlin.ksp.visitor.KSDefaultVisitor
 import kotlin.reflect.KClass
@@ -34,9 +35,8 @@ fun KSDeclaration.asClassName(): ClassName {
 
 fun KSDeclaration.isAbstract() = when (this) {
     is KSFunctionDeclaration -> isAbstract
-    is KSPropertyDeclaration -> Modifier.ABSTRACT in modifiers ||
-            (parentDeclaration as? KSClassDeclaration)?.classKind == ClassKind.INTERFACE
-    is KSClassDeclaration -> Modifier.ABSTRACT in modifiers
+    is KSPropertyDeclaration -> isAbstract()
+    is KSClassDeclaration -> isAbstract()
     else -> false
 }
 
@@ -55,20 +55,16 @@ fun KSTypeReference.memberOf(enclosingClass: KSClassDeclaration): KSTypeReferenc
 }
 
 fun KSType.asTypeName(): TypeName {
+
     return declaration.accept(object : KSDefaultVisitor<Unit, TypeName>() {
 
         override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit): TypeName {
-            val rawType = classDeclaration.asClassName()
-            if (classDeclaration.typeParameters.isEmpty()) {
-                return rawType
-            }
-            val typeArgumentNames = mutableListOf<TypeName>()
-            for (typeArgument in arguments) {
-                typeArgumentNames += typeArgument.type!!.resolve()!!.asTypeName()
-            }
-            return rawType.parameterizedBy(typeArgumentNames)
+            return fromDeclaration(classDeclaration)
         }
 
+        override fun visitTypeAlias(typeAlias: KSTypeAlias, data: Unit): TypeName {
+            return fromDeclaration(typeAlias)
+        }
         override fun visitTypeParameter(typeParameter: KSTypeParameter, data: Unit): TypeName {
             return TypeVariableName(
                 name = typeParameter.name.asString(),
@@ -81,6 +77,18 @@ fun KSType.asTypeName(): TypeName {
             )
         }
 
+        private fun fromDeclaration(declaration: KSDeclaration): TypeName {
+            val rawType = declaration.asClassName()
+            if (declaration.typeParameters.isEmpty()) {
+                return rawType
+            }
+            val typeArgumentNames = mutableListOf<TypeName>()
+            for (typeArgument in arguments) {
+                typeArgumentNames += typeArgument.type!!.resolve()!!.asTypeName()
+            }
+            return rawType.parameterizedBy(typeArgumentNames)
+        }
+
         override fun defaultHandler(node: KSNode, data: Unit): TypeName {
             throw IllegalArgumentException("Unexpected node: $node")
         }


Test patch:
diff --git a/compiler-tests/src/test/kotlin/me/tatarka/inject/test/ProjectCompiler.kt b/compiler-tests/src/test/kotlin/me/tatarka/inject/test/ProjectCompiler.kt
index fb513ee..671d53b 100644
--- a/compiler-tests/src/test/kotlin/me/tatarka/inject/test/ProjectCompiler.kt
+++ b/compiler-tests/src/test/kotlin/me/tatarka/inject/test/ProjectCompiler.kt
@@ -11,7 +11,7 @@ class ProjectCompiler(private val root: File, private val target: Target) {
     private lateinit var sourceDir: File
 
     fun setup(): ProjectCompiler {
-        val kotlinVersion = if (target == Target.ksp) "1.4-M1" else "1.3.70"
+        val kotlinVersion = if (target == Target.ksp) "1.4.0-rc" else "1.3.70"
 
         val settingsFile = root.resolve("settings.gradle")
 
@@ -69,7 +69,7 @@ class ProjectCompiler(private val root: File, private val target: Target) {
 
         val buildFile = dir.resolve("build.gradle")
 
-        val pluginVersion = if (target == Target.ksp) "1.4-M1-dev-experimental-20200716" else kotlinVersion
+        val pluginVersion = if (target == Target.ksp) "1.4.0-rc-dev-experimental-20200731" else kotlinVersion
 
         buildFile.writeText(
             """
diff --git a/integration-tests-ksp/build.gradle b/integration-tests-ksp/build.gradle
index 0bb03d5..f62da74 100644
--- a/integration-tests-ksp/build.gradle
+++ b/integration-tests-ksp/build.gradle
@@ -1,6 +1,6 @@
 plugins {
-    id 'org.jetbrains.kotlin.jvm' version '1.4-M1'
-    id("org.jetbrains.kotlin.ksp") version "1.4-M1-dev-experimental-20200716"
+    id 'org.jetbrains.kotlin.jvm' version '1.4.0-rc'
+    id("org.jetbrains.kotlin.ksp") version "1.4.0-rc-dev-experimental-20200731"
 }
 
 dependencies {