[K/JS] chore: stop unnecessary defineProperties generating.

This commit is contained in:
Artem Kobzar
2022-09-09 11:14:26 +00:00
committed by Space
parent 9176ba5b2d
commit da367a467d
11 changed files with 284 additions and 15 deletions
@@ -115,7 +115,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
return expression.receiver!!.accept(this, context).withSource(expression, context)
}
val fieldName = context.getNameForField(field)
return JsNameRef(fieldName, expression.receiver?.accept(this, context)).withSource(expression, context)
return jsElementAccess(fieldName, expression.receiver?.accept(this, context)).withSource(expression, context)
}
override fun visitGetValue(expression: IrGetValue, context: JsGenerationContext): JsExpression {
@@ -101,7 +101,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
override fun visitSetField(expression: IrSetField, context: JsGenerationContext): JsStatement {
val fieldName = context.getNameForField(expression.symbol.owner)
val expressionTransformer = IrElementToJsExpressionTransformer()
val dest = JsNameRef(fieldName, expression.receiver?.accept(expressionTransformer, context))
val dest = jsElementAccess(fieldName, expression.receiver?.accept(expressionTransformer, context))
return expression.value.maybeOptimizeIntoSwitch(context) { jsAssignment(dest, it).withSource(expression, context).makeStmt() }
}
@@ -111,7 +111,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null)
continue
if (!property.visibility.isPublicAPI)
if (!property.visibility.isPublicAPI || property.isSimpleProperty)
continue
if (
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.isSimpleProperty
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.utils.DFS
@@ -117,7 +118,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
declaration is IrFunction && declaration.dispatchReceiverParameter != null -> {
val property = (declaration as? IrSimpleFunction)?.correspondingPropertySymbol?.owner
if (property?.isExported(context) == true || property?.isEffectivelyExternal() == true) {
context.minimizedNameGenerator.reserveName(property.name.asString())
context.minimizedNameGenerator.reserveName(property.getJsNameOrKotlinName().identifier)
}
if (declaration.hasStableJsName(context)) {
val signature = jsFunctionSignature(declaration, context)
@@ -126,7 +127,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
}
declaration is IrProperty -> {
if (declaration.isExported(context)) {
context.minimizedNameGenerator.reserveName(declaration.name.asString())
context.minimizedNameGenerator.reserveName(declaration.getJsNameOrKotlinName().identifier)
}
}
}
@@ -138,12 +139,22 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
it.declarations.forEach {
when {
it is IrField -> {
val safeName = if (minimizedMemberNames) {
context.minimizedNameGenerator.generateNextName()
} else it.safeName()
val suffix = nameCnt.getOrDefault(safeName, 0) + 1
nameCnt[safeName] = suffix
result[it] = safeName + "_$suffix"
val correspondingProperty = it.correspondingPropertySymbol?.owner
val hasStableName = correspondingProperty != null &&
correspondingProperty.visibility.isPublicAPI &&
(correspondingProperty.isExported(context) || correspondingProperty.getJsName() != null) &&
correspondingProperty.isSimpleProperty
val safeName = when {
hasStableName -> (correspondingProperty ?: it).getJsNameOrKotlinName().identifier
minimizedMemberNames -> context.minimizedNameGenerator.generateNextName()
else -> it.safeName()
}
val resultName = if (!hasStableName) {
val suffix = nameCnt.getOrDefault(safeName, 0) + 1
nameCnt[safeName] = suffix
safeName + "_$suffix"
} else safeName
result[it] = resultName
}
it is IrFunction && it.dispatchReceiverParameter != null -> {
nameCnt[jsFunctionSignature(it, context)] = 1 // avoid clashes with member functions
@@ -52,10 +52,13 @@ fun <T : JsNode> IrWhen.toJsNode(
}
fun jsElementAccess(name: String, receiver: JsExpression?): JsExpression =
if (receiver == null || name.isValidES5Identifier()) {
JsNameRef(JsName(name, false), receiver)
jsElementAccess(JsName(name, false), receiver)
fun jsElementAccess(name: JsName, receiver: JsExpression?): JsExpression =
if (receiver == null || name.ident.isValidES5Identifier()) {
JsNameRef(name, receiver)
} else {
JsArrayAccess(receiver, JsStringLiteral(name))
JsArrayAccess(receiver, JsStringLiteral(name.ident))
}
fun jsAssignment(left: JsExpression, right: JsExpression) = JsBinaryOperation(JsBinaryOperator.ASG, left, right)
@@ -192,6 +192,16 @@ fun IrValueParameter.createStubDefaultValue(): IrExpressionBody =
IrErrorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, "Stub expression for default value of $name")
)
val IrProperty.isSimpleProperty: Boolean
get() {
val getterFun = getter
val setterFun = setter
return !isFakeOverride &&
modality === Modality.FINAL &&
(getterFun == null || getterFun.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) &&
(setterFun == null || setterFun.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR)
}
val IrClass.functions: Sequence<IrSimpleFunction>
get() = declarations.asSequence().filterIsInstance<IrSimpleFunction>()
@@ -2112,6 +2112,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/export/exportAllFile.kt");
}
@Test
@TestMetadata("exportClassPropertiesInDifferentCombinations.kt")
public void testExportClassPropertiesInDifferentCombinations() throws Exception {
runTest("js/js.translator/testData/box/export/exportClassPropertiesInDifferentCombinations.kt");
}
@Test
@TestMetadata("exportClassWithInternal.kt")
public void testExportClassWithInternal() throws Exception {
@@ -2584,6 +2584,12 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
runTest("js/js.translator/testData/box/export/exportAllFile.kt");
}
@Test
@TestMetadata("exportClassPropertiesInDifferentCombinations.kt")
public void testExportClassPropertiesInDifferentCombinations() throws Exception {
runTest("js/js.translator/testData/box/export/exportClassPropertiesInDifferentCombinations.kt");
}
@Test
@TestMetadata("exportClassWithInternal.kt")
public void testExportClassWithInternal() throws Exception {
@@ -2584,6 +2584,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/export/exportAllFile.kt");
}
@Test
@TestMetadata("exportClassPropertiesInDifferentCombinations.kt")
public void testExportClassPropertiesInDifferentCombinations() throws Exception {
runTest("js/js.translator/testData/box/export/exportClassPropertiesInDifferentCombinations.kt");
}
@Test
@TestMetadata("exportClassWithInternal.kt")
public void testExportClassWithInternal() throws Exception {
@@ -7,7 +7,7 @@
// FILE: lib.kt
@JsExport
fun `@do something like-this`(): Int = 42
fun `@do something like-this`(`test value`: Int = 42): Int = `test value`
// FILE: test.js
function box() {
@@ -0,0 +1,227 @@
// EXPECTED_REACHABLE_NODES: 1252
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: export_class_properties
// FILE: lib.kt
@JsExport
interface IOwner {
val interfaceValOpen: String
val interfaceGetterOnly: String
get() = "Interface with Getter"
var interfaceVarOpen: String
}
@JsExport
open class Owner {
open val classOpenReadonly: String = "Class Readonly Open"
open var classOpenVar: String = "Class Var Open"
val classFinalReadonly: String = "Class Readonly Final"
var classFinalVar: String = "Class Default"
val classGetterOnly: String
get() = "Class with Final Getter"
open val classOpenGetterOnly: String
get() = "Class with Open Getter"
var classSetterOnly: String = "Class setter only"
set(value) { classOpenVar = "Class Changed by class setter only $value" }
open var classOpenSetterOnly: String = "Class open setter only"
set(value) { classOpenVar = "Class Changed by class open setter only $value" }
var classGetterAndSetter: String = "Class Getter and Setter"
get() = field + " by class getter"
set(value) { field = value }
open var classOpenGetterAndSetter: String = "Class Open Getter and Setter"
get() = field + " by class open getter"
set(value) { field = value }
}
open class HiddenChild : Owner(), IOwner {
override val interfaceValOpen: String = "Hidden Child Open Val"
override var interfaceVarOpen: String = "Hidden Child Open Var"
val hiddenDefaultVal: String = "Hidden Default Val"
val hiddenDefaultGetter: String get() = "Hidden Default Getter"
var hiddenDefaultVar: String = "Hidden Default Var"
}
open class AnotherOneHiddenChild: HiddenChild() {
override val interfaceGetterOnly: String
get() = "Another One Hidden Child with Getter"
}
@JsExport
class ExportedChild: AnotherOneHiddenChild() {
override val classOpenReadonly: String = "Exported Child Readonly Open"
override var classOpenVar: String = "Exported Child Var Open"
override val classOpenGetterOnly: String
get() = "Exported Child with Open Getter"
override var classOpenSetterOnly: String = super.classOpenSetterOnly
set(value) { classOpenVar = "Exported Child Changed by class open setter only $value" }
override var classOpenGetterAndSetter: String = super.classOpenGetterAndSetter
get() = field + " by exported child open getter"
set(value) { field = value }
}
@JsExport
fun generateHiddenChild() = HiddenChild()
@JsExport
fun generateAnotherHiddenChild() = AnotherOneHiddenChild()
// FILE: test.js
function assertEquals(actualValue, expectedValue) {
if (actualValue !== expectedValue) {
throw new Error("Expected value is '" + expectedValue + "', but got '" + actualValue + "'")
}
}
function testOwner(pkg) {
var owner = new pkg.Owner();
assertEquals(owner.classOpenReadonly, "Class Readonly Open")
assertEquals(owner.classOpenVar, "Class Var Open")
assertEquals(owner.classFinalReadonly, "Class Readonly Final")
assertEquals(owner.classFinalVar, "Class Default")
assertEquals(owner.classGetterOnly, "Class with Final Getter")
assertEquals(owner.classOpenGetterOnly, "Class with Open Getter")
assertEquals(owner.classGetterAndSetter, "Class Getter and Setter by class getter")
assertEquals(owner.classOpenGetterAndSetter, "Class Open Getter and Setter by class open getter")
assertEquals(owner.classSetterOnly, "Class setter only")
owner.classSetterOnly = "test1"
assertEquals(owner.classOpenVar, "Class Changed by class setter only test1")
assertEquals(owner.classOpenSetterOnly, "Class open setter only")
owner.classOpenSetterOnly = "test2"
assertEquals(owner.classOpenVar, "Class Changed by class open setter only test2")
}
function testHiddenChild(pkg) {
var owner = pkg.generateHiddenChild()
assertEquals(owner.hiddenDefaultVal, undefined)
assertEquals(owner.hiddenDefaultGetter, undefined)
assertEquals(owner.hiddenDefaultVar, undefined)
assertEquals(owner.interfaceValOpen, "Hidden Child Open Val")
assertEquals(owner.interfaceVarOpen, "Hidden Child Open Var")
assertEquals(owner.interfaceGetterOnly, "Interface with Getter")
assertEquals(owner.classOpenReadonly, "Class Readonly Open")
assertEquals(owner.classOpenVar, "Class Var Open")
assertEquals(owner.classFinalReadonly, "Class Readonly Final")
assertEquals(owner.classFinalVar, "Class Default")
assertEquals(owner.classGetterOnly, "Class with Final Getter")
assertEquals(owner.classOpenGetterOnly, "Class with Open Getter")
assertEquals(owner.classGetterAndSetter, "Class Getter and Setter by class getter")
assertEquals(owner.classOpenGetterAndSetter, "Class Open Getter and Setter by class open getter")
assertEquals(owner.classSetterOnly, "Class setter only")
owner.classSetterOnly = "test1"
assertEquals(owner.classOpenVar, "Class Changed by class setter only test1")
assertEquals(owner.classOpenSetterOnly, "Class open setter only")
owner.classOpenSetterOnly = "test2"
assertEquals(owner.classOpenVar, "Class Changed by class open setter only test2")
}
function testAnotherHiddenChild(pkg) {
var owner = pkg.generateAnotherHiddenChild()
assertEquals(owner.hiddenDefaultVal, undefined)
assertEquals(owner.hiddenDefaultGetter, undefined)
assertEquals(owner.hiddenDefaultVar, undefined)
assertEquals(owner.interfaceValOpen, "Hidden Child Open Val")
assertEquals(owner.interfaceVarOpen, "Hidden Child Open Var")
assertEquals(owner.interfaceGetterOnly, "Another One Hidden Child with Getter")
assertEquals(owner.classOpenReadonly, "Class Readonly Open")
assertEquals(owner.classOpenVar, "Class Var Open")
assertEquals(owner.classFinalReadonly, "Class Readonly Final")
assertEquals(owner.classFinalVar, "Class Default")
assertEquals(owner.classGetterOnly, "Class with Final Getter")
assertEquals(owner.classOpenGetterOnly, "Class with Open Getter")
assertEquals(owner.classGetterAndSetter, "Class Getter and Setter by class getter")
assertEquals(owner.classOpenGetterAndSetter, "Class Open Getter and Setter by class open getter")
owner.classSetterOnly = "test1"
assertEquals(owner.classOpenVar, "Class Changed by class setter only test1")
owner.classOpenSetterOnly = "test2"
assertEquals(owner.classOpenVar, "Class Changed by class open setter only test2")
}
function testExportedChild(pkg) {
var owner = pkg.generateAnotherHiddenChild()
assertEquals(owner.hiddenDefaultVal, undefined)
assertEquals(owner.hiddenDefaultGetter, undefined)
assertEquals(owner.hiddenDefaultVar, undefined)
assertEquals(owner.interfaceValOpen, "Hidden Child Open Val")
assertEquals(owner.interfaceVarOpen, "Hidden Child Open Var")
assertEquals(owner.interfaceGetterOnly, "Another One Hidden Child with Getter")
assertEquals(owner.classOpenReadonly, "Exported Child Readonly Open")
assertEquals(owner.classOpenVar, "Exported Child Var Open")
assertEquals(owner.classFinalReadonly, "Class Readonly Final")
assertEquals(owner.classFinalVar, "Class Default")
assertEquals(owner.classGetterOnly, "Class with Final Getter")
assertEquals(owner.classOpenGetterOnly, "Exported Child with Open Getter")
assertEquals(owner.classGetterAndSetter, "Class Getter and Setter by class getter")
assertEquals(owner.classOpenGetterAndSetter, "Class Open Getter and Setter by exported child open getter")
assertEquals(owner.classSetterOnly, "Class setter only")
owner.classSetterOnly = "test1"
assertEquals(owner.classOpenVar, "Class Changed by class setter only test1")
assertEquals(owner.classOpenSetterOnly, "Class open setter only")
owner.classOpenSetterOnly = "test2"
assertEquals(owner.classOpenVar, "Exported Child Changed by class open setter only test2")
}
function box() {
var pkg = this["export_class_properties"]
testOwner(pkg)
testHiddenChild(pkg)
testAnotherHiddenChild(pkg)
return "OK"
}