Move scripting support classes to the scripting compiler impl module
This commit is contained in:
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.configuration
|
||||
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource
|
||||
import java.io.File
|
||||
|
||||
object ScriptingConfigurationKeys {
|
||||
|
||||
val SCRIPT_DEFINITIONS = CompilerConfigurationKey.create<List<KotlinScriptDefinition>>("script definitions")
|
||||
|
||||
val SCRIPT_DEFINITIONS_SOURCES =
|
||||
CompilerConfigurationKey.create<List<ScriptDefinitionsSource>>("script definitions sources")
|
||||
|
||||
val DISABLE_SCRIPTING_PLUGIN_OPTION: CompilerConfigurationKey<Boolean> =
|
||||
CompilerConfigurationKey.create("Disable scripting plugin")
|
||||
|
||||
val SCRIPT_DEFINITIONS_CLASSES: CompilerConfigurationKey<List<String>> =
|
||||
CompilerConfigurationKey.create("Script definition classes")
|
||||
|
||||
val SCRIPT_DEFINITIONS_CLASSPATH: CompilerConfigurationKey<List<File>> =
|
||||
CompilerConfigurationKey.create("Additional classpath for the script definitions")
|
||||
|
||||
val DISABLE_SCRIPT_DEFINITIONS_FROM_CLASSPATH_OPTION: CompilerConfigurationKey<Boolean> =
|
||||
CompilerConfigurationKey.create("Do not extract script definitions from the compilation classpath")
|
||||
|
||||
val LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION: CompilerConfigurationKey<MutableMap<String, Any?>> =
|
||||
CompilerConfigurationKey.create("Script resolver environment")
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.configuration
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.scripting.definitions.loadScriptTemplatesFromClasspath
|
||||
|
||||
const val KOTLIN_SCRIPTING_PLUGIN_ID = "kotlin.scripting"
|
||||
|
||||
fun configureScriptDefinitions(
|
||||
scriptTemplates: List<String>,
|
||||
configuration: CompilerConfiguration,
|
||||
baseClassloader: ClassLoader,
|
||||
messageCollector: MessageCollector,
|
||||
scriptResolverEnv: Map<String, Any?>
|
||||
) {
|
||||
// TODO: consider using escaping to allow kotlin escaped names in class names
|
||||
val templatesFromClasspath = loadScriptTemplatesFromClasspath(
|
||||
scriptTemplates, configuration.jvmClasspathRoots, emptyList(), baseClassloader, scriptResolverEnv, messageCollector
|
||||
)
|
||||
configuration.addAll(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, templatesFromClasspath.toList())
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.definitions
|
||||
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType
|
||||
import com.intellij.openapi.util.UserDataHolderBase
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.location.ScriptExpectedLocation
|
||||
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
||||
|
||||
open class KotlinScriptDefinition(open val template: KClass<out Any>) : UserDataHolderBase() {
|
||||
|
||||
open val name: String = "Kotlin Script"
|
||||
|
||||
// TODO: consider creating separate type (subtype? for kotlin scripts)
|
||||
open val fileType: LanguageFileType = KotlinFileType.INSTANCE
|
||||
|
||||
open val annotationsForSamWithReceivers: List<String>
|
||||
get() = emptyList()
|
||||
|
||||
open fun isScript(fileName: String): Boolean =
|
||||
fileName.endsWith(KotlinParserDefinition.STD_SCRIPT_EXT)
|
||||
|
||||
open fun getScriptName(script: KtScript): Name =
|
||||
NameUtils.getScriptNameForFile(script.containingKtFile.name)
|
||||
|
||||
open val fileExtension: String
|
||||
get() = "kts"
|
||||
|
||||
// Target platform for script, ex. "JVM", "JS", "NATIVE"
|
||||
open val platform: String
|
||||
get() = "JVM"
|
||||
|
||||
open val dependencyResolver: DependenciesResolver get() = DependenciesResolver.NoDependencies
|
||||
|
||||
open val acceptedAnnotations: List<KClass<out Annotation>> get() = emptyList()
|
||||
|
||||
@Deprecated("temporary workaround for missing functionality, will be replaced by the new API soon")
|
||||
open val additionalCompilerArguments: Iterable<String>? = null
|
||||
|
||||
open val scriptExpectedLocations: List<ScriptExpectedLocation> =
|
||||
listOf(ScriptExpectedLocation.SourcesOnly, ScriptExpectedLocation.TestsOnly)
|
||||
|
||||
open val implicitReceivers: List<KType> get() = emptyList()
|
||||
|
||||
open val providedProperties: List<Pair<String, KType>> get() = emptyList()
|
||||
|
||||
open val targetClassAnnotations: List<Annotation> get() = emptyList()
|
||||
|
||||
open val targetMethodAnnotations: List<Annotation> get() = emptyList()
|
||||
}
|
||||
|
||||
object StandardScriptDefinition : KotlinScriptDefinition(ScriptTemplateWithArgs::class)
|
||||
|
||||
-1
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.full.starProjectedType
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.definitions
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
interface ScriptDefinitionProvider {
|
||||
fun findScriptDefinition(fileName: String): KotlinScriptDefinition?
|
||||
fun isScript(fileName: String): Boolean
|
||||
fun getDefaultScriptDefinition(): KotlinScriptDefinition
|
||||
|
||||
fun getKnownFilenameExtensions(): Sequence<String>
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): ScriptDefinitionProvider? =
|
||||
ServiceManager.getService(project, ScriptDefinitionProvider::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-2
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.scripting.definitions
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.definitions
|
||||
|
||||
interface ScriptDefinitionsSource {
|
||||
|
||||
val definitions: Sequence<KotlinScriptDefinition>
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.definitions
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiFile
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
interface ScriptDependenciesProvider {
|
||||
fun getScriptDependencies(file: VirtualFile): ScriptDependencies?
|
||||
fun getScriptDependencies(file: PsiFile) = getScriptDependencies(file.virtualFile ?: file.originalFile.virtualFile)
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): ScriptDependenciesProvider? =
|
||||
ServiceManager.getService(project, ScriptDependenciesProvider::class.java)
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.definitions;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.psi.KtScript;
|
||||
|
||||
public class ScriptPriorities {
|
||||
|
||||
public static final Key<Integer> PRIORITY_KEY = Key.create(KtScript.class.getName() + ".priority");
|
||||
|
||||
public static int getScriptPriority(@NotNull KtScript script) {
|
||||
Integer priority = script.getUserData(PRIORITY_KEY);
|
||||
return priority == null ? 0 : priority;
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -7,15 +7,12 @@ package org.jetbrains.kotlin.scripting.definitions
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionsSource
|
||||
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URLClassLoader
|
||||
import java.util.jar.JarFile
|
||||
import kotlin.coroutines.experimental.buildSequence
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.KotlinType
|
||||
import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate
|
||||
@@ -46,7 +43,7 @@ fun discoverScriptTemplatesInClasspath(
|
||||
baseClassLoader: ClassLoader,
|
||||
scriptResolverEnv: Map<String, Any?>,
|
||||
messageCollector: MessageCollector
|
||||
): Sequence<KotlinScriptDefinition> = buildSequence {
|
||||
): Sequence<KotlinScriptDefinition> = sequence {
|
||||
// TODO: try to find a way to reduce classpath (and classloader) to minimal one needed to load script definition and its dependencies
|
||||
val loader = LazyClasspathWithClassLoader(baseClassLoader) { classpath }
|
||||
|
||||
@@ -136,7 +133,7 @@ fun loadScriptTemplatesFromClasspath(
|
||||
messageCollector: MessageCollector
|
||||
): Sequence<KotlinScriptDefinition> =
|
||||
if (scriptTemplates.isEmpty()) emptySequence()
|
||||
else buildSequence {
|
||||
else sequence {
|
||||
// trying the direct classloading from baseClassloader first, since this is the most performant variant
|
||||
val (initialLoadedDefinitions, initialNotFoundTemplates) = scriptTemplates.partitionMapNotNull {
|
||||
loadScriptDefinition(
|
||||
|
||||
-2
@@ -13,8 +13,6 @@ import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
|
||||
fun PsiFile.scriptDefinition(): KotlinScriptDefinition? {
|
||||
// Do not use psiFile.script, see comments in findScriptDefinition
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.dependencies
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.createSourceFilesFromSourceRoots
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import java.io.File
|
||||
|
||||
data class ScriptsCompilationDependencies(
|
||||
val classpath: List<File>,
|
||||
val sources: List<KtFile>,
|
||||
val sourceDependencies: List<SourceDependencies>
|
||||
) {
|
||||
data class SourceDependencies(
|
||||
val scriptFile: KtFile,
|
||||
val sourceDependencies: List<KtFile>
|
||||
)
|
||||
}
|
||||
|
||||
// recursively collect dependencies from initial and imported scripts
|
||||
fun collectScriptsCompilationDependencies(
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project,
|
||||
initialSources: Iterable<KtFile>
|
||||
): ScriptsCompilationDependencies {
|
||||
val collectedClassPath = ArrayList<File>()
|
||||
val collectedSources = ArrayList<KtFile>()
|
||||
val collectedSourceDependencies = ArrayList<ScriptsCompilationDependencies.SourceDependencies>()
|
||||
var remainingSources = initialSources
|
||||
val knownSourcePaths = initialSources.mapNotNullTo(HashSet()) { it.virtualFile?.path }
|
||||
val importsProvider = ScriptDependenciesProvider.getInstance(project)
|
||||
if (importsProvider != null) {
|
||||
while (true) {
|
||||
val newRemainingSources = ArrayList<KtFile>()
|
||||
for (source in remainingSources) {
|
||||
val dependencies = importsProvider.getScriptDependencies(source)
|
||||
if (dependencies != null) {
|
||||
collectedClassPath.addAll(dependencies.classpath)
|
||||
|
||||
val sourceDependenciesRoots = dependencies.scripts.map {
|
||||
KotlinSourceRoot(it.path, false)
|
||||
}
|
||||
val sourceDependencies =
|
||||
createSourceFilesFromSourceRoots(
|
||||
configuration, project, sourceDependenciesRoots,
|
||||
// TODO: consider receiving and using precise location from the resolver in the future
|
||||
source.virtualFile?.path?.let { CompilerMessageLocation.create(it) }
|
||||
)
|
||||
if (sourceDependencies.isNotEmpty()) {
|
||||
collectedSourceDependencies.add(
|
||||
ScriptsCompilationDependencies.SourceDependencies(
|
||||
source,
|
||||
sourceDependencies
|
||||
)
|
||||
)
|
||||
|
||||
val newSources = sourceDependencies.filterNot { knownSourcePaths.contains(it.virtualFile.path) }
|
||||
for (newSource in newSources) {
|
||||
collectedSources.add(newSource)
|
||||
newRemainingSources.add(newSource)
|
||||
knownSourcePaths.add(newSource.virtualFile.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newRemainingSources.isEmpty()) break
|
||||
else {
|
||||
remainingSources = newRemainingSources
|
||||
}
|
||||
}
|
||||
}
|
||||
return ScriptsCompilationDependencies(
|
||||
collectedClassPath.distinctBy { it.absolutePath },
|
||||
collectedSources,
|
||||
collectedSourceDependencies
|
||||
)
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.extensions
|
||||
|
||||
import com.intellij.core.JavaCoreProjectEnvironment
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.extensions.ReplFactoryExtension
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCompiler
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.repl.GenericReplCompiler
|
||||
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
|
||||
class JvmStandardReplFactoryExtension : ReplFactoryExtension {
|
||||
|
||||
override fun makeReplCompiler(
|
||||
templateClassName: String,
|
||||
templateClasspath: List<File>,
|
||||
baseClassLoader: ClassLoader?,
|
||||
configuration: CompilerConfiguration,
|
||||
projectEnvironment: JavaCoreProjectEnvironment
|
||||
): ReplCompiler = GenericReplCompiler(
|
||||
projectEnvironment.parentDisposable,
|
||||
makeScriptDefinition(templateClasspath, templateClassName, baseClassLoader),
|
||||
configuration,
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
)
|
||||
|
||||
private fun makeScriptDefinition(
|
||||
templateClasspath: List<File>, templateClassName: String, baseClassLoader: ClassLoader?
|
||||
): KotlinScriptDefinition = try {
|
||||
val classloader = URLClassLoader(templateClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassLoader)
|
||||
val cls = classloader.loadClass(templateClassName)
|
||||
KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, emptyMap())
|
||||
} catch (ex: ClassNotFoundException) {
|
||||
throw IllegalStateException("Cannot find script definition template class $templateClassName", ex)
|
||||
} catch (ex: Exception) {
|
||||
throw IllegalStateException("Error loading script definition template $templateClassName", ex)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtImportInfo
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
|
||||
class ScriptExtraImportsProviderExtension : ExtraImportsProviderExtension {
|
||||
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.extensions
|
||||
|
||||
import com.intellij.mock.MockProject
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.extensions.CollectAdditionalSourcesExtension
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.dependencies.collectScriptsCompilationDependencies
|
||||
|
||||
class ScriptingCollectAdditionalSourcesExtension(val project: MockProject) : CollectAdditionalSourcesExtension {
|
||||
override fun collectAdditionalSourcesAndUpdateConfiguration(
|
||||
knownSources: Collection<KtFile>,
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project
|
||||
): Collection<KtFile> {
|
||||
val (newSourcesClasspath, newSources, _) = collectScriptsCompilationDependencies(
|
||||
configuration,
|
||||
project,
|
||||
knownSources
|
||||
)
|
||||
configuration.addJvmClasspathRoots(newSourcesClasspath)
|
||||
return newSources
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.repl.messages.ConsoleDiagnosticMessageHolder
|
||||
import kotlin.concurrent.write
|
||||
|
||||
@@ -38,7 +39,7 @@ open class GenericReplChecker(
|
||||
|
||||
internal val environment = run {
|
||||
compilerConfiguration.apply {
|
||||
add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
||||
add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
||||
put<MessageCollector>(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
||||
put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
||||
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import java.io.File
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.write
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.replaceImportingScopes
|
||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptPriorities
|
||||
|
||||
class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
|
||||
private val topDownAnalysisContext: TopDownAnalysisContext
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.repl.configuration.ReplConfiguration
|
||||
import java.io.PrintWriter
|
||||
import java.net.URLClassLoader
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.resolve
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
|
||||
// wraps AsyncDependenciesResolver to provide implementation for synchronous DependenciesResolver::resolve
|
||||
class AsyncDependencyResolverWrapper(
|
||||
override val delegate: AsyncDependenciesResolver
|
||||
): AsyncDependenciesResolver, DependencyResolverWrapper<AsyncDependenciesResolver> {
|
||||
|
||||
override fun resolve(
|
||||
scriptContents: ScriptContents, environment: Environment
|
||||
): DependenciesResolver.ResolveResult
|
||||
= runBlocking { delegate.resolveAsync(scriptContents, environment) }
|
||||
|
||||
|
||||
suspend override fun resolveAsync(
|
||||
scriptContents: ScriptContents, environment: Environment
|
||||
): DependenciesResolver.ResolveResult
|
||||
= delegate.resolveAsync(scriptContents, environment)
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.jetbrains.kotlin.scripting.resolve
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.full.memberFunctions
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
import kotlin.script.dependencies.ScriptDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.location.ScriptExpectedLocation
|
||||
import kotlin.script.experimental.location.ScriptExpectedLocations
|
||||
import kotlin.script.templates.AcceptedAnnotations
|
||||
import kotlin.script.templates.DEFAULT_SCRIPT_FILE_PATTERN
|
||||
import kotlin.script.templates.ScriptTemplateDefinition
|
||||
|
||||
open class KotlinScriptDefinitionFromAnnotatedTemplate(
|
||||
template: KClass<out Any>,
|
||||
val environment: Map<String, Any?>? = null,
|
||||
val templateClasspath: List<File> = emptyList()
|
||||
) : KotlinScriptDefinition(template) {
|
||||
val scriptFilePattern by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
val pattern =
|
||||
takeUnlessError {
|
||||
val ann = template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateDefinition>()
|
||||
ann?.scriptFilePattern
|
||||
}
|
||||
?: takeUnlessError { template.annotations.firstIsInstanceOrNull<ScriptTemplateDefinition>()?.scriptFilePattern }
|
||||
?: DEFAULT_SCRIPT_FILE_PATTERN
|
||||
Regex(pattern)
|
||||
}
|
||||
|
||||
override val dependencyResolver: DependenciesResolver by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
resolverFromAnnotation(template) ?:
|
||||
DependenciesResolver.NoDependencies
|
||||
}
|
||||
|
||||
private fun resolverFromAnnotation(template: KClass<out Any>): DependenciesResolver? {
|
||||
val defAnn = takeUnlessError {
|
||||
template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateDefinition>()
|
||||
} ?: return null
|
||||
|
||||
val resolver = instantiateResolver(defAnn.resolver)
|
||||
return when (resolver) {
|
||||
is AsyncDependenciesResolver -> AsyncDependencyResolverWrapper(resolver)
|
||||
is DependenciesResolver -> resolver
|
||||
else -> resolver?.let(::ApiChangeDependencyResolverWrapper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Any> instantiateResolver(resolverClass: KClass<T>): T? {
|
||||
try {
|
||||
resolverClass.objectInstance?.let {
|
||||
return it
|
||||
}
|
||||
val constructorWithoutParameters = resolverClass.constructors.find { it.parameters.all { it.isOptional } }
|
||||
if (constructorWithoutParameters == null) {
|
||||
log.warn("[kts] ${resolverClass.qualifiedName} must have a constructor without required parameters")
|
||||
return null
|
||||
}
|
||||
return constructorWithoutParameters.callBy(emptyMap())
|
||||
}
|
||||
catch (ex: ClassCastException) {
|
||||
log.warn("[kts] Script def error ${ex.message}")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private val samWithReceiverAnnotations: List<String>? by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
takeUnlessError { template.annotations.firstIsInstanceOrNull<kotlin.script.extensions.SamWithReceiverAnnotations>()?.annotations?.toList() }
|
||||
}
|
||||
|
||||
override val acceptedAnnotations: List<KClass<out Annotation>> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
|
||||
fun sameSignature(left: KFunction<*>, right: KFunction<*>): Boolean =
|
||||
left.name == right.name &&
|
||||
left.parameters.size == right.parameters.size &&
|
||||
left.parameters.zip(right.parameters).all {
|
||||
it.first.kind == KParameter.Kind.INSTANCE ||
|
||||
it.first.type == it.second.type
|
||||
}
|
||||
|
||||
val resolveFunctions = getResolveFunctions()
|
||||
|
||||
dependencyResolver.unwrap()::class.memberFunctions
|
||||
.filter { function -> resolveFunctions.any { sameSignature(function, it) } }
|
||||
.flatMap { it.annotations }
|
||||
.filterIsInstance<AcceptedAnnotations>()
|
||||
.flatMap { it.supportedAnnotationClasses.toList() }
|
||||
.distinctBy { it.qualifiedName }
|
||||
}
|
||||
|
||||
private fun getResolveFunctions(): List<KFunction<*>> {
|
||||
// DependenciesResolver::resolve, ScriptDependenciesResolver::resolve, AsyncDependenciesResolver::resolveAsync
|
||||
return AsyncDependenciesResolver::class.memberFunctions.filter { it.name == "resolve" || it.name == "resolveAsync" }.also {
|
||||
assert(it.size == 3) {
|
||||
AsyncDependenciesResolver::class.memberFunctions
|
||||
.joinToString(prefix = "${AsyncDependenciesResolver::class.qualifiedName} api changed, fix this code") { it.name }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val scriptExpectedLocations: List<ScriptExpectedLocation> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
takeUnlessError {
|
||||
template.annotations.firstIsInstanceOrNull<ScriptExpectedLocations>()
|
||||
}?.value?.toList() ?: super.scriptExpectedLocations
|
||||
}
|
||||
|
||||
override val name = template.simpleName!!
|
||||
|
||||
override fun isScript(fileName: String): Boolean =
|
||||
scriptFilePattern.matches(fileName)
|
||||
|
||||
// TODO: implement other strategy - e.g. try to extract something from match with ScriptFilePattern
|
||||
override fun getScriptName(script: KtScript): Name = NameUtils.getScriptNameForFile(script.containingKtFile.name)
|
||||
|
||||
override fun toString(): String = "KotlinScriptDefinitionFromAnnotatedTemplate - ${template.simpleName}"
|
||||
|
||||
override val annotationsForSamWithReceivers: List<String>
|
||||
get() = samWithReceiverAnnotations ?: super.annotationsForSamWithReceivers
|
||||
|
||||
override val additionalCompilerArguments: Iterable<String>? by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
takeUnlessError {
|
||||
template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments>()?.let {
|
||||
val res = it.provider.primaryConstructor?.call(it.arguments.asIterable())
|
||||
res
|
||||
}
|
||||
}?.getAdditionalCompilerArguments(environment)
|
||||
}
|
||||
|
||||
private inline fun<T> takeUnlessError(reportError: Boolean = true, body: () -> T?): T? =
|
||||
try {
|
||||
body()
|
||||
}
|
||||
catch (ex: Throwable) {
|
||||
if (reportError) {
|
||||
log.error("Invalid script template: " + template.qualifiedName, ex)
|
||||
}
|
||||
else {
|
||||
log.warn("Invalid script template: " + template.qualifiedName, ex)
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal val log = Logger.getInstance(KotlinScriptDefinitionFromAnnotatedTemplate::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
interface DependencyResolverWrapper<T : ScriptDependenciesResolver> {
|
||||
val delegate: T
|
||||
}
|
||||
|
||||
fun ScriptDependenciesResolver.unwrap(): ScriptDependenciesResolver {
|
||||
return if (this is DependencyResolverWrapper<*>) delegate.unwrap() else this
|
||||
}
|
||||
+3
-3
@@ -33,9 +33,9 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeImpl
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
|
||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptPriorities
|
||||
import org.jetbrains.kotlin.scripting.definitions.scriptDefinitionByFileName
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.resolve
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult.Failure
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
import kotlin.script.experimental.dependencies.ScriptReport
|
||||
|
||||
class ScriptContentLoader(private val project: Project) {
|
||||
fun getScriptContents(scriptDefinition: KotlinScriptDefinition, file: VirtualFile)
|
||||
= BasicScriptContents(
|
||||
file,
|
||||
getAnnotations = { loadAnnotations(scriptDefinition, file) })
|
||||
|
||||
private fun loadAnnotations(scriptDefinition: KotlinScriptDefinition, file: VirtualFile): List<Annotation> {
|
||||
val classLoader = scriptDefinition.template.java.classLoader
|
||||
// TODO_R: report error on failure to load annotation class
|
||||
return ApplicationManager.getApplication().runReadAction<List<Annotation>> {
|
||||
getAnnotationEntries(file, project)
|
||||
.mapNotNull { psiAnn ->
|
||||
// TODO: consider advanced matching using semantic similar to actual resolving
|
||||
scriptDefinition.acceptedAnnotations.find { ann ->
|
||||
psiAnn.typeName.let { it == ann.simpleName || it == ann.qualifiedName }
|
||||
}?.let {
|
||||
constructAnnotation(
|
||||
psiAnn,
|
||||
classLoader.loadClass(it.qualifiedName).kotlin as KClass<out Annotation>,
|
||||
project
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnnotationEntries(file: VirtualFile, project: Project): Iterable<KtAnnotationEntry> {
|
||||
val psiFile: PsiFile = PsiManager.getInstance(project).findFile(file)
|
||||
?: throw IllegalArgumentException("Unable to load PSI from ${file.canonicalPath}")
|
||||
return (psiFile as? KtFile)?.annotationEntries
|
||||
?: throw IllegalArgumentException("Unable to extract kotlin annotations from ${file.name} (${file.fileType})")
|
||||
}
|
||||
|
||||
class BasicScriptContents(virtualFile: VirtualFile, getAnnotations: () -> Iterable<Annotation>) : ScriptContents {
|
||||
override val file: File = File(virtualFile.path)
|
||||
override val annotations: Iterable<Annotation> by lazy(LazyThreadSafetyMode.PUBLICATION) { getAnnotations() }
|
||||
override val text: CharSequence? by lazy(LazyThreadSafetyMode.PUBLICATION) { virtualFile.inputStream.reader(charset = virtualFile.charset).readText() }
|
||||
}
|
||||
|
||||
fun loadContentsAndResolveDependencies(
|
||||
scriptDef: KotlinScriptDefinition,
|
||||
file: VirtualFile
|
||||
): DependenciesResolver.ResolveResult {
|
||||
val scriptContents = getScriptContents(scriptDef, file)
|
||||
val environment = getEnvironment(scriptDef)
|
||||
val result = try {
|
||||
scriptDef.dependencyResolver.resolve(
|
||||
scriptContents,
|
||||
environment
|
||||
)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
e.asResolveFailure(scriptDef)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun getEnvironment(scriptDef: KotlinScriptDefinition) =
|
||||
(scriptDef as? KotlinScriptDefinitionFromAnnotatedTemplate)?.environment.orEmpty()
|
||||
}
|
||||
|
||||
fun ScriptDependencies.adjustByDefinition(
|
||||
scriptDef: KotlinScriptDefinition
|
||||
): ScriptDependencies {
|
||||
val additionalClasspath = (scriptDef as? KotlinScriptDefinitionFromAnnotatedTemplate)?.templateClasspath ?: return this
|
||||
if (additionalClasspath.isEmpty()) return this
|
||||
return copy(classpath = additionalClasspath + classpath)
|
||||
}
|
||||
|
||||
fun Throwable.asResolveFailure(scriptDef: KotlinScriptDefinition): Failure {
|
||||
val prefix = "${scriptDef.dependencyResolver::class.simpleName} threw exception ${this::class.simpleName}:\n "
|
||||
return Failure(ScriptReport(prefix + (message ?: "<no message>"), ScriptReport.Severity.FATAL))
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.resolve
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import kotlin.script.experimental.dependencies.ScriptReport
|
||||
|
||||
interface ScriptReportSink {
|
||||
fun attachReports(scriptFile: VirtualFile, reports: List<ScriptReport>)
|
||||
}
|
||||
-1
@@ -7,7 +7,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.scripting.resolve
|
||||
|
||||
import org.jetbrains.kotlin.script.DependencyResolverWrapper
|
||||
import java.io.File
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.dependencies.ScriptDependenciesResolver
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.scripting.resolve
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtUserType
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.tryCreateCallableMappingFromNamedArgs
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
internal val KtAnnotationEntry.typeName: String get() = (typeReference?.typeElement as? KtUserType)?.referencedName.orAnonymous()
|
||||
|
||||
internal fun String?.orAnonymous(kind: String = ""): String =
|
||||
this ?: "<anonymous" + (if (kind.isNotBlank()) " $kind" else "") + ">"
|
||||
|
||||
internal fun constructAnnotation(psi: KtAnnotationEntry, targetClass: KClass<out Annotation>, project: Project): Annotation {
|
||||
val module = ModuleDescriptorImpl(Name.special("<script-annotations-preprocessing>"), LockBasedStorageManager("scriptAnnotationsPreprocessing"), DefaultBuiltIns.Instance)
|
||||
val evaluator = ConstantExpressionEvaluator(module, LanguageVersionSettingsImpl.DEFAULT, project)
|
||||
val trace = BindingTraceContext()
|
||||
|
||||
val valueArguments = psi.valueArguments.map { arg ->
|
||||
val result = evaluator.evaluateToConstantValue(arg.getArgumentExpression()!!, trace, TypeUtils.NO_EXPECTED_TYPE)
|
||||
// TODO: consider inspecting `trace` to find diagnostics reported during the computation (such as division by zero, integer overflow, invalid annotation parameters etc.)
|
||||
val argName = arg.getArgumentName()?.asName?.toString()
|
||||
argName to result?.value
|
||||
}
|
||||
val mappedArguments: Map<KParameter, Any?> =
|
||||
tryCreateCallableMappingFromNamedArgs(targetClass.constructors.first(), valueArguments)
|
||||
?: return InvalidScriptResolverAnnotation(psi.typeName, valueArguments)
|
||||
|
||||
try {
|
||||
return targetClass.primaryConstructor!!.callBy(mappedArguments)
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
return InvalidScriptResolverAnnotation(psi.typeName, valueArguments, ex)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this class is used for error reporting. But in order to pass plugin verification, it should derive directly from java's Annotation
|
||||
// and implement annotationType method (see #KT-16621 for details).
|
||||
// TODO: instead of the workaround described above, consider using a sum-type for returning errors from constructAnnotation
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
class InvalidScriptResolverAnnotation(val name: String, val annParams: List<Pair<String?, Any?>>?, val error: Exception? = null) : Annotation, java.lang.annotation.Annotation {
|
||||
override fun annotationType(): Class<out Annotation> = InvalidScriptResolverAnnotation::class.java
|
||||
}
|
||||
Reference in New Issue
Block a user