From 5a77d2e92ba9dd124a6f43469e74a0c32a8a01c0 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Tue, 21 Jun 2016 19:40:26 +0200 Subject: [PATCH] Change to single ScriptTemplateDefinition annotation and separate AcceptedAnnotations annotation on resolver --- .../jetbrains/kotlin/script/scriptTemplate.kt | 50 +++++++++++-------- .../jetbrains/kotlin/scripts/ScriptTest2.kt | 17 ++++--- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt index 7d19d1681cf..4b2c2917cca 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt @@ -34,11 +34,13 @@ import java.lang.reflect.Method import java.lang.reflect.Proxy import java.util.* import kotlin.reflect.KClass +import kotlin.reflect.memberFunctions import kotlin.reflect.memberProperties @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) -annotation class ScriptFilePattern(val pattern: String) +annotation class ScriptTemplateDefinition(val resolver: KClass, + val scriptFilePattern: String) interface ScriptDependenciesResolver { fun resolve(scriptFile: File?, @@ -48,12 +50,14 @@ interface ScriptDependenciesResolver { ): KotlinScriptExternalDependencies? = null } -@Target(AnnotationTarget.CLASS) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) -annotation class ScriptDependenciesResolverClass(val resolver: KClass, - vararg val supportedAnnotationClasses: KClass) +annotation class AcceptedAnnotations(vararg val supportedAnnotationClasses: KClass) data class KotlinScriptDefinitionFromTemplate(val template: KClass, val environment: Map?) : KotlinScriptDefinition { + + private val definitionAnnotation by lazy { template.annotations.mapNotNull { it as? ScriptTemplateDefinition }.firstOrNull() } + override val name = template.simpleName!! override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List = @@ -66,32 +70,34 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, val getScriptParameters(scriptDescriptor).map { it.name } override fun isScript(file: TF): Boolean = - template.annotations.any { (it as? ScriptFilePattern)?.let { Regex(it.pattern).matches(getFileName(file)) } ?: false } + definitionAnnotation?.let { Regex(it.scriptFilePattern).matches(getFileName(file)) } ?: false // TODO: implement other strategy - e.g. try to extract something from match with ScriptFilePattern override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, KotlinParserDefinition.STD_SCRIPT_EXT) + private class ResolverWithAcceptedAnnotations(val resolverClass: KClass) { + val resolver by lazy { resolverClass.constructors.first().call() } + val acceptedAnnotations by lazy { + val resolveMethodName = ScriptDependenciesResolver::class.memberFunctions.first().name + resolverClass.memberFunctions.find { it.name == resolveMethodName }?.annotations + ?.mapNotNull { it as? AcceptedAnnotations } + ?.flatMap { + val v = it.supportedAnnotationClasses + v.toList() // TODO: find out why if inlined, it fails with "java.lang.Class cannot be cast to kotlin.reflect.KClass" + } + ?: emptyList() + } + } + private val dependenciesResolvers by lazy { - template.annotations.mapNotNull { it as? ScriptDependenciesResolverClass }.map { Pair(it, it.resolver.constructors.first().call()) } + definitionAnnotation?.resolver?.let { listOf(ResolverWithAcceptedAnnotations(it)) } ?: emptyList() } private val supportedAnnotationClasses: List> by lazy { - template.annotations.mapNotNull { it as? ScriptDependenciesResolverClass } - .flatMap { - // it.supportedAnnotationClasses.asIterable() // TODO: find out why it fails with "java.lang.Class cannot be cast to kotlin.reflect.KClass" - it.supportedAnnotationClasses.asIterable2() - } + dependenciesResolvers.flatMap { it.acceptedAnnotations } .distinctBy { it.qualifiedName } } - private fun Array>.asIterable2(): ArrayList> { - val res = arrayListOf>() - for (x in this) { - res.add(x) - } - return res - } - override fun getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? { val fileAnnotations = getAnnotationEntries(file, project) .map { KtAnnotationWrapper(it) } @@ -110,12 +116,12 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, val Pair(it.first, InvalidScriptResolverAnnotation(it.second.name, it.second.valueArguments, ex)) } } - val fileDeps = dependenciesResolvers.mapNotNull { resolver -> + val fileDeps = dependenciesResolvers.mapNotNull { resolverWrapper -> val supportedAnnotations = annotations.mapNotNull { ann -> val annFQN = ann.first.qualifiedName - if (resolver.first.supportedAnnotationClasses.asIterable2().any { it.qualifiedName == annFQN }) ann.second else null + if (resolverWrapper.acceptedAnnotations.any { it.qualifiedName == annFQN }) ann.second else null } - resolver.second.resolve(getFile(file), supportedAnnotations, environment, previousDependencies) + resolverWrapper.resolver.resolve(getFile(file), supportedAnnotations, environment, previousDependencies) } return KotlinScriptExternalDependenciesUnion(fileDeps) } diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt index f4aebad76a5..154a97a1162 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler import org.jetbrains.kotlin.codegen.CompilationException import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.addKotlinSourceRoot -import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.script.* import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.KotlinTestUtils @@ -120,6 +119,7 @@ class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolver { private val kotlinPaths by lazy { PathUtil.getKotlinPathsForCompiler() } + @AcceptedAnnotations(depends::class) override fun resolve(scriptFile: File?, annotations: Iterable, environment: Map?, @@ -145,16 +145,19 @@ class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolver { ?: emptyList() } -@ScriptFilePattern(".*\\.kts") -@ScriptDependenciesResolverClass(TestKotlinScriptDependenciesResolver::class, depends::class) +@ScriptTemplateDefinition( + scriptFilePattern =".*\\.kts", + resolver = TestKotlinScriptDependenciesResolver::class) abstract class ScriptWithIntParam(num: Int) -@ScriptFilePattern(".*\\.kts") -@ScriptDependenciesResolverClass(TestKotlinScriptDependenciesResolver::class, depends::class) +@ScriptTemplateDefinition( + scriptFilePattern =".*\\.kts", + resolver = TestKotlinScriptDependenciesResolver::class) abstract class ScriptWithClassParam(param: TestParamClass) -@ScriptFilePattern(".*\\.kts") -@ScriptDependenciesResolverClass(TestKotlinScriptDependenciesResolver::class, depends::class) +@ScriptTemplateDefinition( + scriptFilePattern =".*\\.kts", + resolver = TestKotlinScriptDependenciesResolver::class) abstract class ScriptWithBaseClass(num: Int, passthrough: Int) : TestDSLClassWithParam(passthrough) @Target(AnnotationTarget.FILE)