JS: insert dummy initializers for property that initialized on init block or in secondary constructors. See KT-8211
This commit is contained in:
@@ -3611,6 +3611,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyInitializationOrder.kt")
|
||||||
|
public void testPropertyInitializationOrder() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/initialize/propertyInitializationOrder.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("rootPackageValInit.kt")
|
@TestMetadata("rootPackageValInit.kt")
|
||||||
public void testRootPackageValInit() throws Exception {
|
public void testRootPackageValInit() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/initialize/rootPackageValInit.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/initialize/rootPackageValInit.kt");
|
||||||
|
|||||||
+35
-3
@@ -16,16 +16,21 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.initializer;
|
package org.jetbrains.kotlin.js.translate.initializer;
|
||||||
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
|
import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
|
||||||
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
|
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils;
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsStatementAndMergeInBlockIfNeeded;
|
import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsStatementAndMergeInBlockIfNeeded;
|
||||||
import static org.jetbrains.kotlin.js.translate.initializer.InitializerUtils.generateInitializerForDelegate;
|
import static org.jetbrains.kotlin.js.translate.initializer.InitializerUtils.generateInitializerForDelegate;
|
||||||
@@ -49,10 +54,19 @@ public final class InitializerVisitor extends TranslatorVisitor<Void> {
|
|||||||
assert value != null;
|
assert value != null;
|
||||||
statement = generateInitializerForProperty(context, descriptor, value);
|
statement = generateInitializerForProperty(context, descriptor, value);
|
||||||
}
|
}
|
||||||
if (delegate != null) {
|
else if (delegate != null) {
|
||||||
assert value != null;
|
assert value != null;
|
||||||
statement = generateInitializerForDelegate(descriptor, value);
|
statement = generateInitializerForDelegate(descriptor, value);
|
||||||
}
|
}
|
||||||
|
else if (Boolean.TRUE.equals(context.bindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
|
||||||
|
JsExpression defaultValue = generateDefaultValue(descriptor, context);
|
||||||
|
statement = TranslationUtils.assignmentToBackingField(context, descriptor, defaultValue).makeStmt();
|
||||||
|
}
|
||||||
|
else if (JsDescriptorUtils.isSimpleFinalProperty(descriptor)) {
|
||||||
|
JsExpression defaultValue = generateDefaultValue(descriptor, context);
|
||||||
|
JsName propertyName = context.getNameForDescriptor(descriptor);
|
||||||
|
statement = JsAstUtils.assignment(new JsNameRef(propertyName, JsLiteral.THIS), defaultValue).makeStmt();
|
||||||
|
}
|
||||||
|
|
||||||
if (statement != null && !JsAstUtils.isEmptyStatement(statement)) {
|
if (statement != null && !JsAstUtils.isEmptyStatement(statement)) {
|
||||||
context.addStatementsToCurrentBlock(JsAstUtils.flattenStatement(statement));
|
context.addStatementsToCurrentBlock(JsAstUtils.flattenStatement(statement));
|
||||||
@@ -61,6 +75,24 @@ public final class InitializerVisitor extends TranslatorVisitor<Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static JsExpression generateDefaultValue(@NotNull PropertyDescriptor property, @NotNull TranslationContext context) {
|
||||||
|
if (property.isLateInit()) return Namer.getUndefinedExpression();
|
||||||
|
|
||||||
|
KotlinType type = property.getType();
|
||||||
|
if (KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isFloat(type) || KotlinBuiltIns.isDouble(type) ||
|
||||||
|
KotlinBuiltIns.isByte(type) || KotlinBuiltIns.isShort(type)
|
||||||
|
) {
|
||||||
|
return context.program().getNumberLiteral(0);
|
||||||
|
}
|
||||||
|
else if (KotlinBuiltIns.isBoolean(type)) {
|
||||||
|
return JsLiteral.FALSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return JsLiteral.NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitAnonymousInitializer(@NotNull KtAnonymousInitializer initializer, @NotNull TranslationContext context) {
|
public Void visitAnonymousInitializer(@NotNull KtAnonymousInitializer initializer, @NotNull TranslationContext context) {
|
||||||
KtExpression initializerBody = initializer.getBody();
|
KtExpression initializerBody = initializer.getBody();
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
open class A {
|
||||||
|
val a: Int
|
||||||
|
open val b: Int
|
||||||
|
val c = 99
|
||||||
|
val d: Int = 555
|
||||||
|
get() = field
|
||||||
|
|
||||||
|
val e: Int
|
||||||
|
get() = field
|
||||||
|
|
||||||
|
@get:JsName("getF")
|
||||||
|
val f: Int
|
||||||
|
|
||||||
|
@get:JsName("getG")
|
||||||
|
val g: Int = 777
|
||||||
|
|
||||||
|
lateinit var h: String
|
||||||
|
|
||||||
|
init {
|
||||||
|
foo()
|
||||||
|
a = 23
|
||||||
|
b = 42
|
||||||
|
e = 987
|
||||||
|
f = 888
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val aBody = js("A").toString()
|
||||||
|
val expectedRegex = build {
|
||||||
|
property("a")
|
||||||
|
field("b")
|
||||||
|
property("c")
|
||||||
|
field("d")
|
||||||
|
field("e")
|
||||||
|
field("f")
|
||||||
|
field("g")
|
||||||
|
property("h")
|
||||||
|
}
|
||||||
|
if (expectedRegex.find(aBody) == null) return "fail"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(f: RegexBuilder.() -> Unit): Regex {
|
||||||
|
val builder = RegexBuilder()
|
||||||
|
builder.f()
|
||||||
|
return Regex(builder.string + "foo()", RegexOption.MULTILINE)
|
||||||
|
}
|
||||||
|
|
||||||
|
class RegexBuilder {
|
||||||
|
var string = ""
|
||||||
|
|
||||||
|
fun property(name: String) {
|
||||||
|
string += "this.$name\\s+=$ANY_CHARS"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun field(name: String) {
|
||||||
|
string += "this.$name$FIELD_SUFFIX\\s+=$ANY_CHARS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ANY_CHARS = "(.|\n)+"
|
||||||
|
val FIELD_SUFFIX = "_[a-zA-Z0-9\\\$_]+"
|
||||||
Reference in New Issue
Block a user