diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/scriptAnnotationsPreprocessing.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/scriptAnnotationsPreprocessing.kt index eacfc57367c..3a242e90445 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/scriptAnnotationsPreprocessing.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/scriptAnnotationsPreprocessing.kt @@ -11,17 +11,28 @@ 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.psi.* +import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTraceContext +import org.jetbrains.kotlin.resolve.CollectionLiteralResolver +import org.jetbrains.kotlin.resolve.CollectionLiteralResolver.Companion.ARRAY_OF_FUNCTION +import org.jetbrains.kotlin.resolve.CollectionLiteralResolver.Companion.PRIMITIVE_TYPE_TO_ARRAY +import org.jetbrains.kotlin.resolve.constants.ArrayValue +import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.types.KotlinType 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 +private val ARRAY_OF_METHODS = setOf(ARRAY_OF_FUNCTION) + PRIMITIVE_TYPE_TO_ARRAY.values.toSet() + Name.identifier("emptyArray") + +// basic text comparison of function name, todo: better handling? +private val KtCallExpression.isArrayCall: Boolean get() = Name.identifier(calleeExpression!!.text) in ARRAY_OF_METHODS + internal val KtAnnotationEntry.typeName: String get() = (typeReference?.typeElement as? KtUserType)?.referencedName.orAnonymous() internal fun String?.orAnonymous(kind: String = ""): String = @@ -39,7 +50,23 @@ internal fun constructAnnotation(psi: KtAnnotationEntry, targetClass: KClass - val result = evaluator.evaluateToConstantValue(arg.getArgumentExpression()!!, trace, TypeUtils.NO_EXPECTED_TYPE) + val expression = arg.getArgumentExpression()!! + + val result = when { + expression is KtCollectionLiteralExpression -> + evaluator.evaluateToConstantArrayValue(expression.getInnerExpressions(), trace, TypeUtils.NO_EXPECTED_TYPE) + + expression is KtCallExpression && expression.isArrayCall -> { + evaluator.evaluateToConstantArrayValue( + expression.valueArguments.mapNotNull { it.getArgumentExpression() }, + trace, + TypeUtils.NO_EXPECTED_TYPE + ) + } + + else -> 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 @@ -56,6 +83,15 @@ internal fun constructAnnotation(psi: KtAnnotationEntry, targetClass: KClass, + trace: BindingTrace, + expectedElementType: KotlinType +): ArrayValue { + val constants = elementExpressions.mapNotNull { evaluateExpression(it, trace, expectedElementType)?.toConstantValue(expectedElementType) } + return ConstantValueFactory.createArrayValue(constants, TypeUtils.NO_EXPECTED_TYPE) +} + // 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 diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt index f5b55816b8e..605e9257dc2 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt @@ -49,32 +49,19 @@ class ScriptingCompilerConfigurationComponentRegistrar : ComponentRegistrar { } withClassloadingProblemsReporting(messageCollector) { CompilerConfigurationExtension.registerExtension(project, ScriptingCompilerConfigurationExtension(project, hostConfiguration)) - CollectAdditionalSourcesExtension.registerExtension(project, - ScriptingCollectAdditionalSourcesExtension( - project - ) - ) + CollectAdditionalSourcesExtension.registerExtension(project, ScriptingCollectAdditionalSourcesExtension(project)) ScriptEvaluationExtension.registerExtensionIfRequired(project, JvmCliScriptEvaluationExtension()) ScriptEvaluationExtension.registerExtensionIfRequired(project, JsScriptEvaluationExtension()) ShellExtension.registerExtensionIfRequired(project, JvmCliReplShellExtension()) - ReplFactoryExtension.registerExtensionIfRequired(project, - JvmStandardReplFactoryExtension() - ) + ReplFactoryExtension.registerExtensionIfRequired(project, JvmStandardReplFactoryExtension()) - val scriptDefinitionProvider = CliScriptDefinitionProvider() - project.registerService(ScriptDefinitionProvider::class.java, scriptDefinitionProvider) - project.registerService( - ScriptDependenciesProvider::class.java, - CliScriptDependenciesProvider(project) - ) + project.registerService(ScriptDefinitionProvider::class.java, CliScriptDefinitionProvider()) + project.registerService(ScriptDependenciesProvider::class.java, CliScriptDependenciesProvider(project)) SyntheticResolveExtension.registerExtension(project, ScriptingResolveExtension()) ExtraImportsProviderExtension.registerExtension(project, ScriptExtraImportsProviderExtension()) if (messageCollector != null) { - project.registerService( - ScriptReportSink::class.java, - CliScriptReportSink(messageCollector) - ) + project.registerService(ScriptReportSink::class.java, CliScriptReportSink(messageCollector)) } } }