diff --git a/idea-runner/build.gradle.kts b/idea-runner/build.gradle.kts index ea46a797bb4..96a7b9c1542 100644 --- a/idea-runner/build.gradle.kts +++ b/idea-runner/build.gradle.kts @@ -17,8 +17,9 @@ dependencies { val ideaPluginDir: File by rootProject.extra val ideaSandboxDir: File by rootProject.extra +val serialPluginDir: File by rootProject.extra -runIdeTask("runIde", ideaPluginDir, ideaSandboxDir) { +runIdeTask("runIde", ideaPluginDir, ideaSandboxDir, serialPluginDir) { // TODO: add serialization plugin to pluginDir dependsOn(":dist", ":ideaPlugin", ":kotlinx-serialization-compiler-plugin:dist") } diff --git a/libraries/tools/kotlin-maven-serialization/pom.xml b/libraries/tools/kotlin-maven-serialization/pom.xml index eb9e851fe89..ddcc00b6962 100755 --- a/libraries/tools/kotlin-maven-serialization/pom.xml +++ b/libraries/tools/kotlin-maven-serialization/pom.xml @@ -19,7 +19,7 @@ org.jetbrains.kotlinx kotlinx-maven-serialization-plugin jar - 0.3 + 0.5.0 Serialization plugin for Maven diff --git a/libraries/tools/kotlin-serialization/build.gradle b/libraries/tools/kotlin-serialization/build.gradle index 2f2627e07b9..d6afcd7da8b 100644 --- a/libraries/tools/kotlin-serialization/build.gradle +++ b/libraries/tools/kotlin-serialization/build.gradle @@ -8,7 +8,7 @@ configureJvmProject(project) configurePublishing(project) group = 'org.jetbrains.kotlinx' -version = '0.3' +version = '0.5.0' if (!project.hasProperty("deploy")) { version = "$version-SNAPSHOT" } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts index aebd4ea8942..1543ceb1cc4 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/build.gradle.kts @@ -1,11 +1,16 @@ description = "Kotlin Serialization Compiler Plugin" -apply { plugin("kotlin") } - +plugins { + kotlin("jvm") + id("jps-compatible") +} dependencies { - compileOnly(ideaSdkCoreDeps("intellij-core")) - compileOnly(ideaPluginDeps("maven", plugin = "maven")) +// val compileOnly by configurations +// val runtime by configurations + compileOnly(intellijCoreDep()) { includeJars("intellij-core") } + compileOnly(intellijDep()) + compileOnly(intellijPluginDep("maven")) compileOnly(project(":jps-plugin")) compileOnly(project(":compiler:plugin-api")) compileOnly(project(":compiler:frontend")) @@ -19,8 +24,6 @@ dependencies { runtime(projectRuntimeJar(":kotlin-compiler")) runtime(projectDist(":kotlin-stdlib")) -// val compileOnly by configurations -// val runtime by configurations } sourceSets { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml index d64f51754fd..71c492bf9f9 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml @@ -1,7 +1,7 @@ Kotlin-serialization org.jetbrains.kotlinx.serialization - 0.3 + 0.5.0 org.jetbrains.kotlin diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt index cfa0d638740..5364c03cbe7 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt @@ -28,7 +28,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.typeUtil.* +import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments +import org.jetbrains.kotlin.types.typeUtil.isBoolean +import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType +import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId @@ -36,29 +39,32 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySe import org.jetbrains.kotlinx.serialization.compiler.resolve.* open class SerialTypeInfo( - val property: SerializableProperty, - val elementMethodPrefix: String, - val serializer: ClassDescriptor? = null, - val unit: Boolean = false + val property: SerializableProperty, + val elementMethodPrefix: String, + val serializer: ClassDescriptor? = null, + val unit: Boolean = false ) fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { val T = property.type return when { T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null) - T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(property, - T.nameIfStandardType.toString().capitalize()) + T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo( + property, + T.nameIfStandardType.toString().capitalize() + ) KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String") KotlinBuiltIns.isUnit(T) -> SerialTypeInfo(property, "Unit", unit = true) KotlinBuiltIns.isPrimitiveArray(T) -> TODO("primitive arrays are not supported yet") KotlinBuiltIns.isNonPrimitiveArray(T.toClassDescriptor!!) -> { - val serializer = property.serializableWith?.toClassDescriptor ?: - property.module.findClassAcrossModuleDependencies(referenceArraySerializerId) + val serializer = property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies( + referenceArraySerializerId + ) SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer) } T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> { - val serializer = property.serializableWith?.toClassDescriptor ?: - property.module.findClassAcrossModuleDependencies(enumSerializerId) + val serializer = + property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(enumSerializerId) SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer) } else -> { @@ -72,9 +78,9 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescri return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module) else if (kType.isTypeParameter()) return null else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type - ?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer - ?: findEnumTypeSerializer(module, kType) - ?: module.findClassAcrossModuleDependencies(contextSerializerId) + ?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer + ?: findEnumTypeSerializer(module, kType) + ?: module.findClassAcrossModuleDependencies(contextSerializerId) } fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { @@ -110,8 +116,8 @@ fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDe fun KotlinType.requiresPolymorphism(): Boolean { return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true - || (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class - || this.containsTypeProjectionsInTopLevelArguments() // List<*> + || (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class + || this.containsTypeProjectionsInTopLevelArguments() // List<*> } fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor { @@ -119,20 +125,23 @@ fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor { } fun KtPureClassOrObject.bodyPropertiesDescriptorsMap(bindingContext: BindingContext): Map = declarations - .asSequence() - .filterIsInstance() - .associateBy { (bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? PropertyDescriptor)!! } + .asSequence() + .filterIsInstance() + // can filter here because it's impossible to create body property w/ backing field w/o explicit delegating or initializing + .filter { it.delegateExpressionOrInitializer != null } + .associateBy { (bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? PropertyDescriptor)!! } -fun KtPureClassOrObject.primaryPropertiesDescriptorsMap(bindingContext: BindingContext): Map = primaryConstructorParameters +fun KtPureClassOrObject.primaryPropertiesDescriptorsMap(bindingContext: BindingContext): Map = + primaryConstructorParameters .asSequence() .filter { it.hasValOrVar() } .associateBy { bindingContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!! } fun KtPureClassOrObject.anonymousInitializers() = declarations - .asSequence() - .filterIsInstance() - .mapNotNull { it.body } - .toList() + .asSequence() + .filterIsInstance() + .mapNotNull { it.body } + .toList() fun SerializableProperty.annotationVarsAndDesc(annotationClass: ClassDescriptor): Pair, List> { val args: List = (this.descriptor.annotations.findAnnotation(annotationClass.fqNameSafe) as? LazyAnnotationDescriptor)?.annotationEntry?.valueArguments.orEmpty() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt index 41d97e9f006..32d67258f13 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt @@ -16,10 +16,12 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.js +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters +import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator import org.jetbrains.kotlin.js.translate.utils.JsAstUtils internal class JsBlockBuilder { @@ -91,4 +93,12 @@ internal fun propNotSeenTest(seenVar: JsNameRef, index: Int): JsBinaryOperation JsIntLiteral(1 shl (index % 32)) ), JsIntLiteral(0) -) \ No newline at end of file +) + +internal fun TranslationContext.serializerObjectGetter(serializer: ClassDescriptor): JsExpression { + return ReferenceTranslator.translateAsValueReference(serializer, this) +} + +internal fun TranslationContext.translateQualifiedReference(clazz: ClassDescriptor): JsExpression { + return ReferenceTranslator.translateAsTypeReference(clazz, this) +} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt index aac2cd1337f..7e2d9adf1b4 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt @@ -17,7 +17,9 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.js import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.js.backend.ast.JsExpression import org.jetbrains.kotlin.js.backend.ast.JsInvocation import org.jetbrains.kotlin.js.backend.ast.JsNameRef import org.jetbrains.kotlin.js.backend.ast.JsReturn @@ -33,8 +35,8 @@ class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject, override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { val f = context.buildFunction(methodDescriptor) {jsFun, context -> val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!! - val stmt = if (serializableDescriptor.declaredTypeParameters.isEmpty()) { - context.getQualifiedReference(serializer) + val stmt: JsExpression = if (serializer.kind == ClassKind.OBJECT) { + context.serializerObjectGetter(serializer) } else { val args = jsFun.parameters.map { JsNameRef(it.name) } val ref = context.getInnerNameForDescriptor( diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt index eb10b5d2f40..89ad68d77d3 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableJsTranslator.kt @@ -35,25 +35,32 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryProper import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable -class SerializableJsTranslator(val declaration: KtPureClassOrObject, - val translator: DeclarationBodyVisitor, - val context: TranslationContext) : SerializableCodegen(declaration, context.bindingContext()) { +class SerializableJsTranslator( + val declaration: KtPureClassOrObject, + val translator: DeclarationBodyVisitor, + val context: TranslationContext +) : SerializableCodegen(declaration, context.bindingContext()) { - val initMap: Map = declaration.run { + private val initMap: Map = declaration.run { (bodyPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.delegateExpressionOrInitializer } + - primaryPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.defaultValue }) + primaryPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.defaultValue }) } override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) { val missingExceptionClassRef = serializableDescriptor.getClassFromSerializationPackage("MissingFieldException") - .let { context.getQualifiedReference(it) } + .let { context.translateQualifiedReference(it) } val f = context.buildFunction(constructorDescriptor) { jsFun, context -> val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef() val context = context.innerContextWithAliased(serializableDescriptor.thisAsReceiverParameter, thiz) - +JsVars(JsVars.JsVar(thiz.name, Namer.createObjectWithPrototypeFrom(context.getQualifiedReference(serializableDescriptor)))) + +JsVars( + JsVars.JsVar( + thiz.name, + Namer.createObjectWithPrototypeFrom(context.getInnerNameForDescriptor(serializableDescriptor).makeRef()) + ) + ) val seenVar = jsFun.parameters[0].name.makeRef() for ((index, prop) in properties.serializableProperties.withIndex()) { val paramRef = jsFun.parameters[index + 1].name.makeRef() @@ -64,8 +71,7 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject, val initializer = initMap.getValue(prop.descriptor) ?: throw IllegalArgumentException("optional without an initializer") val initExpr = Translation.translateAsExpression(initializer, context) TranslationUtils.assignmentToBackingField(context, prop.descriptor, initExpr).makeStmt() - } - else { + } else { JsThrow(JsNew(missingExceptionClassRef, listOf(JsStringLiteral(prop.name)))) } // (seen & 1 << i == 0) -- not seen @@ -75,14 +81,14 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject, //transient initializers and init blocks val serialDescs = properties.serializableProperties.map { it.descriptor } - (initMap - serialDescs).forEach { (desc, expr) -> - val e = requireNotNull(expr) {"transient without an initializer"} + (initMap - serialDescs).forEach { (desc, expr) -> + val e = requireNotNull(expr) { "transient without an initializer" } val initExpr = Translation.translateAsExpression(e, context) +TranslationUtils.assignmentToBackingField(context, desc, initExpr).makeStmt() } declaration.anonymousInitializers() - .forEach { Translation.translateAsExpression(it, context, this.block) } + .forEach { Translation.translateAsExpression(it, context, this.block) } +JsReturn(thiz) } @@ -96,7 +102,12 @@ class SerializableJsTranslator(val declaration: KtPureClassOrObject, } companion object { - fun translate(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) { + fun translate( + declaration: KtPureClassOrObject, + descriptor: ClassDescriptor, + translator: DeclarationBodyVisitor, + context: TranslationContext + ) { if (descriptor.isInternalSerializable) SerializableJsTranslator(declaration, translator, context).generate() } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt index af1f96288c1..807cdf2d787 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt @@ -80,7 +80,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, val argExprs = args.map { arg -> Translation.translateAsExpression(arg.getArgumentExpression()!!, context) } - val classRef = context.getQualifiedReference(annotationClass) + val classRef = context.translateQualifiedReference(annotationClass) val invok = JsInvocation(JsNameRef(context.getNameForDescriptor(pushFunc), serialClassDescRef), JsNew(classRef, argExprs)) translator.addInitializerStatement(invok.makeStmt()) } @@ -101,7 +101,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, val f = context.buildFunction(typedConstructorDescriptor) { jsFun, context -> val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef() - +JsVars(JsVars.JsVar(thiz.name, JsNew(getQualifiedClassReferenceName(serializerDescriptor)))) + +JsVars(JsVars.JsVar(thiz.name, JsNew(context.getInnerNameForDescriptor(serializerDescriptor).makeRef()))) jsFun.parameters.forEachIndexed { i, parameter -> val thisFRef = JsNameRef(context.scope().declareName("$typeArgPrefix$i"), thiz) +JsAstUtils.assignment(thisFRef, JsNameRef(parameter.name)).makeStmt() @@ -170,19 +170,15 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, +JsInvocation(JsNameRef(wEndFunc, localOutputRef), serialClassDescRef).makeStmt() } - private fun getQualifiedClassReferenceName(classDescriptor: ClassDescriptor): JsExpression { - return context.getQualifiedReference(classDescriptor) - } - private fun serializerInstance(serializerClass: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, genericIndex: Int? = null): JsExpression? { - val nullableSerClass = getQualifiedClassReferenceName(requireNotNull( + val nullableSerClass = context.translateQualifiedReference(requireNotNull( module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier("NullableSerializer"))))) if (serializerClass == null) { if (genericIndex == null) return null return JsNameRef(context.scope().declareName("$typeArgPrefix$genericIndex"), JsThisRef()) } if (serializerClass.kind == ClassKind.OBJECT) { - return getQualifiedClassReferenceName(serializerClass) + return context.serializerObjectGetter(serializerClass) } else { var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId) @@ -197,9 +193,9 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, val serializable = getSerializableClassDescriptorBySerializer(serializerClass) val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) { val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor) - JsInvocation(context.getInnerNameForDescriptor(desc).makeRef(), args) + JsInvocation(context.getInnerReference(desc), args) } else { - JsNew(getQualifiedClassReferenceName(serializerClass), args) + JsNew(context.translateQualifiedReference(serializerClass), args) } return ref } @@ -207,7 +203,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, private fun createGetKClassExpression(classDescriptor: ClassDescriptor): JsExpression = JsInvocation(context.namer().kotlin("getKClass"), - getQualifiedClassReferenceName(classDescriptor)) + context.translateQualifiedReference(classDescriptor)) override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context -> @@ -312,9 +308,15 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, } // char unboxing crutch if (KotlinBuiltIns.isCharOrNullableChar(property.type)) { + // can't use KotlinCompilerVersion.VERSION because javac inlines final string literal :( + val coerceTo = if (KotlinVersion.CURRENT.run { major == 1 && minor == 2 && patch in (0..10) }) { + context.currentModule.builtIns.charType + } else { + TranslationUtils.getReturnTypeForCoercion(property.descriptor) + } +JsAstUtils.assignment( localProps[i], - TranslationUtils.coerce(context, localProps[i], context.currentModule.builtIns.charType) + TranslationUtils.coerce(context, localProps[i], coerceTo) ).makeStmt() } @@ -335,7 +337,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, // default: throw default { val excClassRef = serializableDescriptor.getClassFromSerializationPackage("UnknownFieldException") - .let { context.getQualifiedReference(it) } + .let { context.translateQualifiedReference(it) } +JsThrow(JsNew(excClassRef, listOf(indexVar))) } } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt index feba3a0ecbf..35bfa72c4c4 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -182,7 +183,15 @@ class SerializableCodegenImpl( { "Non-serializable parent of serializable $serializableDescriptor must have no arg constructor" }) // call - invokespecial(superType, "", "()V", false) + // Sealed classes have private so they cannot be inherited from Java src + // public is synthetic and contains additional parameter + val desc = if (DescriptorUtils.isSealedClass(superClass)) { + aconst(null) + "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V" + } else { + "()V" + } + invokespecial(superType, "", desc, false) return 0 to propStartVar } else { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt index 37074b6654c..5b3a45aeaa7 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationCodegenExtension.kt @@ -30,4 +30,7 @@ class SerializationCodegenExtension : ExpressionCodegenExtension { SerializerCodegenImpl.generateSerializerExtensions(codegen) SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen) } + + override val shouldGenerateClassSyntheticPartsInLightClassesMode: Boolean + get() = false } \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt index c207a753d75..36de6d4a78f 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension import org.jetbrains.kotlin.resolve.lazy.LazyClassContext import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider @@ -42,30 +43,49 @@ class SerializationResolveExtension : SyntheticResolveExtension { else -> emptyList() } - override fun generateSyntheticClasses(thisDescriptor: ClassDescriptor, name: Name, ctx: LazyClassContext, declarationProvider: ClassMemberDeclarationProvider, result: MutableSet) { + override fun generateSyntheticClasses( + thisDescriptor: ClassDescriptor, + name: Name, + ctx: LazyClassContext, + declarationProvider: ClassMemberDeclarationProvider, + result: MutableSet + ) { if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && name == KSerializerDescriptorResolver.IMPL_NAME) result.add(KSerializerDescriptorResolver.addSerialInfoImplClass(thisDescriptor, declarationProvider, ctx)) else if (thisDescriptor.isInternalSerializable && name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME && - result.none { it.name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME }) + result.none { it.name == KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME } + ) result.add(KSerializerDescriptorResolver.addSerializerImplClass(thisDescriptor, declarationProvider, ctx)) return } override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? = - if (thisDescriptor.isInternalSerializable) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT - else null + if (thisDescriptor.isInternalSerializable) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT + else null override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList) { KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes) KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes) } - override fun generateSyntheticMethods(thisDescriptor: ClassDescriptor, name: Name, fromSupertypes: List, result: MutableCollection) { + override fun generateSyntheticMethods( + thisDescriptor: ClassDescriptor, + name: Name, + bindingContext: BindingContext, + fromSupertypes: List, + result: MutableCollection + ) { KSerializerDescriptorResolver.generateSerializerMethods(thisDescriptor, fromSupertypes, name, result) KSerializerDescriptorResolver.generateCompanionObjectMethods(thisDescriptor, fromSupertypes, name, result) } - override fun generateSyntheticProperties(thisDescriptor: ClassDescriptor, name: Name, fromSupertypes: ArrayList, result: MutableSet) { + override fun generateSyntheticProperties( + thisDescriptor: ClassDescriptor, + name: Name, + bindingContext: BindingContext, + fromSupertypes: ArrayList, + result: MutableSet + ) { KSerializerDescriptorResolver.generateDescriptorsForAnnotationImpl(thisDescriptor, name, fromSupertypes, result) KSerializerDescriptorResolver.generateSerializerProperties(thisDescriptor, fromSupertypes, name, result) } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt index f04ecdf879f..47a505850f2 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt @@ -28,7 +28,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.lazy.LazyClassContext import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor -import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.KotlinTypeFactory +import org.jetbrains.kotlin.types.TypeProjectionImpl +import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.typeUtil.createProjection import org.jetbrains.kotlin.types.typeUtil.makeNullable import java.util.* @@ -74,7 +77,7 @@ object KSerializerDescriptorResolver { val interfaceDecl = declarationProvider.correspondingClassOrObject!! val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor) - return SyntheticClassOrObjectDescriptor(ctx, + val descriptor = SyntheticClassOrObjectDescriptor(ctx, interfaceDecl, interfaceDesc, IMPL_NAME, @@ -85,18 +88,35 @@ object KSerializerDescriptorResolver { Visibilities.PRIVATE, ClassKind.CLASS, false) + descriptor.initialize() + return descriptor } - fun addSerializerImplClass(thisDescriptor: ClassDescriptor, declarationProvider: ClassMemberDeclarationProvider, ctx: LazyClassContext): ClassDescriptor { + fun addSerializerImplClass( + thisDescriptor: ClassDescriptor, + declarationProvider: ClassMemberDeclarationProvider, + ctx: LazyClassContext + ): ClassDescriptor { val thisDeclaration = declarationProvider.correspondingClassOrObject!! val scope = ctx.declarationScopeProvider.getResolutionScopeForDeclaration(declarationProvider.ownerInfo!!.scopeAnchor) val serializerKind = if (thisDescriptor.declaredTypeParameters.isNotEmpty()) ClassKind.CLASS else ClassKind.OBJECT - return SyntheticClassOrObjectDescriptor(ctx, - thisDeclaration, - thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source, - scope, - Modality.FINAL, Visibilities.PUBLIC, Visibilities.PRIVATE, - serializerKind, false) + val serializerDescriptor = SyntheticClassOrObjectDescriptor( + ctx, + thisDeclaration, + thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source, + scope, + Modality.FINAL, Visibilities.PUBLIC, Visibilities.PRIVATE, + serializerKind, false + ) + val typeParameters: List = + thisDescriptor.declaredTypeParameters.mapIndexed { index, param -> + TypeParameterDescriptorImpl.createWithDefaultBound( + serializerDescriptor, Annotations.EMPTY, false, Variance.INVARIANT, + param.name, index + ) + } + serializerDescriptor.initialize(typeParameters) + return serializerDescriptor } fun generateSerializerProperties(thisDescriptor: ClassDescriptor, @@ -110,10 +130,12 @@ object KSerializerDescriptorResolver { } - fun generateCompanionObjectMethods(thisDescriptor: ClassDescriptor, - fromSupertypes: List, - name: Name, - result: MutableCollection) { + fun generateCompanionObjectMethods( + thisDescriptor: ClassDescriptor, + fromSupertypes: List, + name: Name, + result: MutableCollection + ) { val classDescriptor = getSerializableClassDescriptorByCompanion(thisDescriptor) ?: return if (name == SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == classDescriptor.declaredTypeParameters.size }) { @@ -248,24 +270,32 @@ object KSerializerDescriptorResolver { return functionDescriptor } - fun createTypedSerializerConstructorDescriptor(classDescriptor: ClassDescriptor, serializableDescriptor: ClassDescriptor): ConstructorDescriptor { + fun createTypedSerializerConstructorDescriptor( + classDescriptor: ClassDescriptor, + serializableDescriptor: ClassDescriptor + ): ConstructorDescriptor { val constrDesc = ClassConstructorDescriptorImpl.createSynthesized( - classDescriptor, - Annotations.EMPTY, - false, - classDescriptor.source + classDescriptor, + Annotations.EMPTY, + false, + classDescriptor.source ) val serializerClass = classDescriptor.getClassFromSerializationPackage("KSerializer") val targs = mutableListOf() - val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, _ -> - val targ = TypeParameterDescriptorImpl.createWithDefaultBound(constrDesc, Annotations.EMPTY, false, Variance.INVARIANT, - Name.identifier("T$index"), index) + val args = serializableDescriptor.declaredTypeParameters.mapIndexed { index, param -> + val targ = TypeParameterDescriptorImpl.createWithDefaultBound( + constrDesc, Annotations.EMPTY, false, Variance.INVARIANT, + param.name, index + ) - val pType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType))) + val pType = + KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType))) targs.add(targ) - ValueParameterDescriptorImpl(constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType, - false, false, false, null, constrDesc.source) + ValueParameterDescriptorImpl( + constrDesc, null, index, Annotations.EMPTY, Name.identifier("$typeArgPrefix$index"), pType, + false, false, false, null, constrDesc.source + ) } constrDesc.initialize(args, Visibilities.PUBLIC, targs) @@ -274,7 +304,13 @@ object KSerializerDescriptorResolver { } fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor { - val f = SimpleFunctionDescriptorImpl.create(thisClass, Annotations.EMPTY, SERIALIZER_PROVIDER_NAME, CallableMemberDescriptor.Kind.SYNTHESIZED, thisClass.source) + val f = SimpleFunctionDescriptorImpl.create( + thisClass, + Annotations.EMPTY, + SERIALIZER_PROVIDER_NAME, + CallableMemberDescriptor.Kind.SYNTHESIZED, + thisClass.source + ) val serializerClass = thisClass.getClassFromSerializationPackage("KSerializer") val args = mutableListOf() @@ -282,31 +318,38 @@ object KSerializerDescriptorResolver { var i = 0 serializableClass.declaredTypeParameters.forEach { it -> - val targ = TypeParameterDescriptorImpl.createWithDefaultBound(f, Annotations.EMPTY, false, Variance.INVARIANT, - Name.identifier("T$i"), i) + val targ = TypeParameterDescriptorImpl.createWithDefaultBound( + f, Annotations.EMPTY, false, Variance.INVARIANT, + Name.identifier("T$i"), i + ) - val pType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType))) + val pType = + KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(targ.defaultType))) - args.add(ValueParameterDescriptorImpl( + args.add( + ValueParameterDescriptorImpl( f, null, i, Annotations.EMPTY, - Name.identifier("$typeArgPrefix${i}"), + Name.identifier("$typeArgPrefix$i"), pType, false, false, false, null, f.source - )) + ) + ) typeArgs.add(targ) i++ } - val newSerializableType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializableClass, typeArgs.map { TypeProjectionImpl(it.defaultType) }) - val serialReturnType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(newSerializableType))) + val newSerializableType = + KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializableClass, typeArgs.map { TypeProjectionImpl(it.defaultType) }) + val serialReturnType = + KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerClass, listOf(TypeProjectionImpl(newSerializableType))) f.initialize(null, thisClass.thisAsReceiverParameter, typeArgs, args, serialReturnType, Modality.FINAL, Visibilities.PUBLIC) return f diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt index 723c7546dc1..487b7b3e477 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt @@ -19,51 +19,52 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny -import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) { private val primaryConstructorParameters: List = - serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList() + serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList() private val primaryConstructorProperties: Map = - primaryConstructorParameters.asSequence() - .map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.hasDefaultValue() } - .mapNotNull { (a, b) -> if (a == null) null else a to b } - .toMap() + primaryConstructorParameters.asSequence() + .map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() } + .mapNotNull { (a, b) -> if (a == null) null else a to b } + .toMap() val isExternallySerializable: Boolean = - primaryConstructorParameters.size == primaryConstructorProperties.size + primaryConstructorParameters.size == primaryConstructorProperties.size val serializableProperties: List = - serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) - .asSequence() - .filterIsInstance() - .filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION } - .filter(this::isPropSerializable) - .map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) } - .partition { primaryConstructorProperties.contains(it.descriptor) } - .run { - val supers = serializableClass.getSuperClassNotAny() - if (supers == null || !supers.isInternalSerializable) - first + second - else - SerializableProperties(supers, bindingContext).serializableProperties + first + second - } + serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES) + .asSequence() + .filterIsInstance() + .filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION } + .filter(this::isPropSerializable) + .map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) } + .partition { primaryConstructorProperties.contains(it.descriptor) } + .run { + val supers = serializableClass.getSuperClassNotAny() + if (supers == null || !supers.isInternalSerializable) + first + second + else + SerializableProperties(supers, bindingContext).serializableProperties + first + second + } private fun isPropSerializable(it: PropertyDescriptor) = - if (serializableClass.isInternalSerializable) !it.annotations.serialTransient - else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(it)) + if (serializableClass.isInternalSerializable) !it.annotations.serialTransient + else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains( + it + )) val serializableConstructorProperties: List = - serializableProperties.asSequence() - .filter { primaryConstructorProperties.contains(it.descriptor) } - .toList() + serializableProperties.asSequence() + .filter { primaryConstructorProperties.contains(it.descriptor) } + .toList() val serializableStandaloneProperties: List = - serializableProperties.minus(serializableConstructorProperties) + serializableProperties.minus(serializableConstructorProperties) val size = serializableProperties.size val indices = serializableProperties.indices diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/jps/KotlinSerializationJpsPlugin.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/jps/KotlinSerializationJpsPlugin.kt index 06152e5e418..fe569bcdeb9 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/jps/KotlinSerializationJpsPlugin.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/jps/KotlinSerializationJpsPlugin.kt @@ -34,12 +34,13 @@ class KotlinSerializationJpsPlugin : KotlinJpsCompilerArgumentsProvider { override fun getClasspath(moduleBuildTarget: ModuleBuildTarget, context: CompileContext): List { val inJar = File(PathUtil.getJarPathForClass(this::class.java)).isFile return listOf( - if (inJar) { - File(PathUtil.getJarPathForClass(this::class.java)).absolutePath - } else { - // We're in tests now - val kotlinProjectDirectory = File(PathUtil.getJarPathForClass(javaClass)).parentFile.parentFile.parentFile - File(kotlinProjectDirectory, "dist/artifacts/Serialization/lib/$JAR_FILE_NAME").absolutePath - }) + if (inJar) { + File(PathUtil.getJarPathForClass(this::class.java)).absolutePath + } else { + // We're in tests now + val kotlinProjectDirectory = File(PathUtil.getJarPathForClass(javaClass)).parentFile.parentFile.parentFile + File(kotlinProjectDirectory, "dist/artifacts/Serialization/lib/$JAR_FILE_NAME").absolutePath + } + ) } } diff --git a/ultimate/ultimate-runner/build.gradle.kts b/ultimate/ultimate-runner/build.gradle.kts index 7eb921f8f83..bf6c48ffea4 100644 --- a/ultimate/ultimate-runner/build.gradle.kts +++ b/ultimate/ultimate-runner/build.gradle.kts @@ -17,9 +17,10 @@ val intellijUltimateEnabled : Boolean by rootProject.extra val ideaUltimatePluginDir: File by rootProject.extra val ideaUltimateSandboxDir: File by rootProject.extra +val serialPluginDir: File by rootProject.extra if (intellijUltimateEnabled) { - runIdeTask("runUltimate", ideaUltimatePluginDir, ideaUltimateSandboxDir) { + runIdeTask("runUltimate", ideaUltimatePluginDir, ideaUltimateSandboxDir, serialPluginDir) { dependsOn(":dist", ":ideaPlugin", ":ultimate:ideaUltimatePlugin") } }