diff --git a/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptDefinitionFromAnnotatedTemplate.kt b/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptDefinitionFromAnnotatedTemplate.kt index cc98bd0c4fd..cad96f02bc5 100644 --- a/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptDefinitionFromAnnotatedTemplate.kt +++ b/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptDefinitionFromAnnotatedTemplate.kt @@ -28,21 +28,22 @@ 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.templates.AcceptedAnnotations +import kotlin.script.templates.* open class KotlinScriptDefinitionFromAnnotatedTemplate( template: KClass, val environment: Map? = null, val templateClasspath: List = emptyList() ) : KotlinScriptDefinition(template) { - val scriptFilePattern by lazy { val pattern = takeUnlessError { - template.annotations.firstIsInstanceOrNull()?.scriptFilePattern + val ann = template.annotations.firstIsInstanceOrNull() + ann?.scriptFilePattern } ?: takeUnlessError { template.annotations.firstIsInstanceOrNull()?.scriptFilePattern } ?: DEFAULT_SCRIPT_FILE_PATTERN @@ -144,6 +145,15 @@ open class KotlinScriptDefinitionFromAnnotatedTemplate( override val annotationsForSamWithReceivers: List get() = samWithReceiverAnnotations ?: super.annotationsForSamWithReceivers + override val additionalCompilerArguments: Iterable? by lazy { + takeUnlessError { + template.annotations.firstIsInstanceOrNull()?.let { + val res = it.provider.primaryConstructor?.call(it.arguments.asIterable()) + res + } + }?.getAdditionalCompilerArguments(environment) + } + private inline fun takeUnlessError(reportError: Boolean = true, body: () -> T?): T? = try { body() diff --git a/compiler/frontend.script/src/org/jetbrains/kotlin/script/ScriptContentLoader.kt b/compiler/frontend.script/src/org/jetbrains/kotlin/script/ScriptContentLoader.kt index b0fac37cfeb..3aa844d02da 100644 --- a/compiler/frontend.script/src/org/jetbrains/kotlin/script/ScriptContentLoader.kt +++ b/compiler/frontend.script/src/org/jetbrains/kotlin/script/ScriptContentLoader.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.script +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile @@ -38,13 +39,15 @@ class ScriptContentLoader(private val project: Project) { private fun loadAnnotations(scriptDefinition: KotlinScriptDefinition, file: VirtualFile): List { val classLoader = scriptDefinition.template.java.classLoader // TODO_R: report error on failure to load annotation class - return getAnnotationEntries(file, project) + return ApplicationManager.getApplication().runReadAction> { + 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) } } + } } private fun getAnnotationEntries(file: VirtualFile, project: Project): Iterable { diff --git a/compiler/psi/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt b/compiler/psi/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt index d62e5674c35..b3f07e25359 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.script 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 @@ -26,7 +27,7 @@ import kotlin.reflect.KClass import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.templates.standard.ScriptTemplateWithArgs -open class KotlinScriptDefinition(val template: KClass) { +open class KotlinScriptDefinition(val template: KClass) : UserDataHolderBase() { open val name: String = "Kotlin Script" @@ -45,6 +46,9 @@ open class KotlinScriptDefinition(val template: KClass) { open val dependencyResolver: DependenciesResolver get() = DependenciesResolver.NoDependencies open val acceptedAnnotations: List> get() = emptyList() + + @Deprecated("temporary workaround for missing functionality, will be replaced by the new API soon") + open val additionalCompilerArguments: Iterable? = null } object StandardScriptDefinition : KotlinScriptDefinition(ScriptTemplateWithArgs::class) diff --git a/core/script.runtime/src/kotlin/script/templates/annotations_deprecated.kt b/core/script.runtime/src/kotlin/script/templates/annotations_deprecated.kt new file mode 100644 index 00000000000..21da68fbd47 --- /dev/null +++ b/core/script.runtime/src/kotlin/script/templates/annotations_deprecated.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2018 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. + */ + +/* + * Copyright 2000-2018 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 kotlin.script.templates + +import kotlin.reflect.KClass +import kotlin.script.dependencies.Environment + +@Deprecated("temporary workaround for missing functionality, will be replaced by the new API soon") +// Note: all subclasses should provide the same constructor +open class ScriptTemplateAdditionalCompilerArgumentsProvider(val arguments: Iterable = emptyList()) { + open fun getAdditionalCompilerArguments(@Suppress("UNUSED_PARAMETER") environment: Environment?): Iterable = arguments +} + +// Should be deprecated as well, but since we don't have replacement as of yet, leaving it as is +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class ScriptTemplateAdditionalCompilerArguments( + val arguments: Array = [], + val provider: KClass = ScriptTemplateAdditionalCompilerArgumentsProvider::class +) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt index 40decc7cf73..dc7aa51fe4e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt @@ -18,10 +18,16 @@ package org.jetbrains.kotlin.idea.compiler import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ProjectRootModificationTracker +import com.intellij.openapi.util.Key +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.cli.common.arguments.Jsr305Parser import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.config.AnalysisFlag import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider @@ -29,15 +35,18 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.TargetPlatformVersion import org.jetbrains.kotlin.idea.caches.project.LibraryInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo +import org.jetbrains.kotlin.idea.caches.project.ScriptModuleInfo import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.targetPlatform +import org.jetbrains.kotlin.script.KotlinScriptDefinition object IDELanguageSettingsProvider : LanguageSettingsProvider { override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings = when (moduleInfo) { is ModuleSourceInfo -> moduleInfo.module.languageVersionSettings is LibraryInfo -> project.getLanguageVersionSettings(extraAnalysisFlags = getExtraAnalysisFlags(project)) + is ScriptModuleInfo -> getVersionLanguageSettingsForScripts(project, moduleInfo.scriptDefinition) else -> project.getLanguageVersionSettings() } @@ -60,3 +69,33 @@ object IDELanguageSettingsProvider : LanguageSettingsProvider { return (moduleInfo as? ModuleSourceInfo)?.module?.targetPlatform?.version ?: TargetPlatformVersion.NoVersion } } + +private val LANGUAGE_VERSION_SETTINGS = Key.create>("LANGUAGE_VERSION_SETTINGS") + +private fun getVersionLanguageSettingsForScripts(project: Project, scriptDefinition: KotlinScriptDefinition): LanguageVersionSettings { + val args = scriptDefinition.additionalCompilerArguments + return if (args == null || args.none()) { + project.getLanguageVersionSettings() + } else { + val settings = scriptDefinition.getUserData(LANGUAGE_VERSION_SETTINGS) ?: createCachedValue(project) { + val compilerArguments = K2JVMCompilerArguments() + parseCommandLineArguments(args.toList(), compilerArguments) + // TODO: reporting + compilerArguments.configureLanguageVersionSettings(MessageCollector.NONE) + }.also { scriptDefinition.putUserData(LANGUAGE_VERSION_SETTINGS, it) } + settings.value + } +} + +private fun createCachedValue(project: Project, body: () -> LanguageVersionSettings): CachedValue { + return CachedValuesManager + .getManager(project) + .createCachedValue( + { + CachedValueProvider.Result( + body(), + ProjectRootModificationTracker.getInstance(project) + ) + }, false + ) +}