JS: fix absence of temporary variable in secondary constructors. See KT-16377

This commit is contained in:
Alexey Andreev
2017-02-15 17:58:12 +03:00
committed by Alexey Andreev
parent 3b222f13f3
commit 86d1c7b7ec
4 changed files with 56 additions and 2 deletions
@@ -2149,6 +2149,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("secondaryConstructorTemporaryVars.kt")
public void testSecondaryConstructorTemporaryVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/expression/evaluationOrder/secondaryConstructorTemporaryVars.kt");
doTest(fileName);
}
@TestMetadata("whenAsMinusArgument.kt")
public void testWhenAsMinusArgument() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/expression/evaluationOrder/whenAsMinusArgument.kt");
@@ -16,9 +16,11 @@
package org.jetbrains.kotlin.js.test.utils;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.js.backend.ast.*;
import org.jetbrains.kotlin.js.inline.util.CollectUtilsKt;
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata;
import java.util.*;
@@ -261,6 +263,28 @@ public class DirectiveTestUtils {
}
};
private static final DirectiveHandler HAS_NO_CAPTURED_VARS = new DirectiveHandler("HAS_NO_CAPTURED_VARS") {
@Override
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
String functionName = arguments.getNamedArgument("function");
Set<String> except = new HashSet<String>();
String exceptString = arguments.findNamedArgument("except");
if (exceptString != null) {
for (String exceptId : StringUtil.split(exceptString, ";")) {
except.add(exceptId.trim());
}
}
JsFunction function = AstSearchUtil.getFunction(ast, functionName);
Set<JsName> freeVars = CollectUtilsKt.collectFreeVariables(function);
for (JsName freeVar : freeVars) {
assertTrue("Function " + functionName + " captures free variable " + freeVar.getIdent(),
except.contains(freeVar.getIdent()));
}
}
};
private static final List<DirectiveHandler> DIRECTIVE_HANDLERS = Arrays.asList(
FUNCTION_CONTAINS_NO_CALLS,
FUNCTION_NOT_CALLED,
@@ -278,7 +302,8 @@ public class DirectiveTestUtils {
COUNT_NULLS,
NOT_REFERENCED,
HAS_INLINE_METADATA,
HAS_NO_INLINE_METADATA
HAS_NO_INLINE_METADATA,
HAS_NO_CAPTURED_VARS
);
public static void processDirectives(@NotNull JsNode ast, @NotNull String sourceCode) throws Exception {
@@ -217,13 +217,14 @@ class ClassTranslator private constructor(
val constructorInitializer = context.getFunctionObject(constructorDescriptor)
constructorInitializer.name = context.getInnerNameForDescriptor(constructorDescriptor)
context.addDeclarationStatement(constructorInitializer.makeStmt())
context = context.contextWithScope(constructorInitializer)
context.translateAndAliasParameters(constructorDescriptor, constructorInitializer.parameters)
.translateFunction(constructor, constructorInitializer)
// Translate super/this call
val superCallGenerators = mutableListOf<(MutableList<JsStatement>) -> Unit>()
val referenceToClass = context.getInnerReference(classDescriptor)
context = context.contextWithScope(constructorInitializer)
superCallGenerators += { it += FunctionBodyTranslator.setDefaultValueForArguments(constructorDescriptor, context) }
@@ -0,0 +1,22 @@
// HAS_NO_CAPTURED_VARS: function=A_init except=Kotlin;A
class A() {
var y: String? = null
var z: Any? = null
constructor(x: Any) : this() {
y = if (x == "foo") "!!!" else { z = x; ">>>" }
}
}
fun box(): String {
val a = A("foo")
if (a.y != "!!!") return "fail1: ${a.y}"
if (a.z != null) return "fail2: ${a.z}"
val b = A(23)
if (b.y != ">>>") return "fail3: ${b.y}"
if (b.z != 23) return "fail4: ${b.z}"
return "OK"
}