Fix generation of source maps for synthetic code in enums in JS BE

This commit is contained in:
Alexey Andreev
2017-05-04 16:46:49 +03:00
parent fb3a864892
commit 3a7df13440
6 changed files with 44 additions and 18 deletions
@@ -71,4 +71,10 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/syntheticCodeInConstructors.kt");
doTest(fileName);
}
@TestMetadata("syntheticCodeInEnums.kt")
public void testSyntheticCodeInEnums() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/syntheticCodeInEnums.kt");
doTest(fileName);
}
}
@@ -473,7 +473,7 @@ class ClassTranslator private constructor(
}
private fun generateEnumStandardMethods(entries: List<ClassDescriptor>) {
EnumTranslator(context(), descriptor, entries).generateStandardMethods()
EnumTranslator(context(), descriptor, entries, classDeclaration).generateStandardMethods()
}
private fun mayBeAddThrowableProperties(context: TranslationContext) {
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,8 @@ class DeclarationBodyVisitor(
if (classOrObject is KtObjectDeclaration) {
if (classOrObject.isCompanion() && containingClass.kind != ClassKind.ENUM_CLASS) {
val descriptor = BindingUtils.getDescriptorForElement(context.bindingContext(), classOrObject) as ClassDescriptor
addInitializerStatement(JsInvocation(context.getNameForObjectInstance(descriptor).makeRef()).makeStmt())
addInitializerStatement(JsInvocation(context.getNameForObjectInstance(descriptor).makeRef())
.source(classOrObject).makeStmt())
}
}
}
@@ -62,7 +63,7 @@ class DeclarationBodyVisitor(
if (enumEntry.getBody() != null || supertypes.size > 1) {
ClassTranslator.translate(enumEntry, context, enumInitializer.name, enumEntryOrdinal)
enumInitializer.body.statements += JsNew(context.getInnerReference(descriptor)).makeStmt()
enumInitializer.body.statements += JsNew(context.getInnerReference(descriptor)).source(enumEntry).makeStmt()
}
else {
val enumName = context.getInnerNameForDescriptor(descriptor)
@@ -77,8 +78,8 @@ class DeclarationBodyVisitor(
enumInstanceFunction.name = context.getNameForObjectInstance(descriptor)
context.addDeclarationStatement(enumInstanceFunction.makeStmt())
enumInstanceFunction.body.statements += JsInvocation(pureFqn(enumInitializer.name, null)).makeStmt()
enumInstanceFunction.body.statements += JsReturn(enumInstanceName.makeRef())
enumInstanceFunction.body.statements += JsInvocation(pureFqn(enumInitializer.name, null)).source(enumEntry).makeStmt()
enumInstanceFunction.body.statements += JsReturn(enumInstanceName.makeRef().source(enumEntry))
}
context.export(descriptor)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.translate.declaration
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
@@ -29,7 +30,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
class EnumTranslator(
context: TranslationContext,
val descriptor: ClassDescriptor,
val entries: List<ClassDescriptor>
val entries: List<ClassDescriptor>,
private val psi: PsiElement
) : AbstractTranslator(context) {
fun generateStandardMethods() {
generateValuesFunction()
@@ -39,7 +41,9 @@ class EnumTranslator(
private fun generateValuesFunction() {
val function = createFunction(DescriptorUtils.getFunctionByName(descriptor.staticScope, DescriptorUtils.ENUM_VALUES))
val values = entries.map { JsInvocation(JsAstUtils.pureFqn(context().getNameForObjectInstance(it), null)) }
val values = entries.map {
JsInvocation(JsAstUtils.pureFqn(context().getNameForObjectInstance(it), null)).source(psi)
}
function.body.statements += JsReturn(JsArrayLiteral(values))
}
@@ -52,18 +56,19 @@ class EnumTranslator(
val clauses = entries.map { entry ->
JsCase().apply {
caseExpression = context().program().getStringLiteral(entry.name.asString())
statements += JsReturn(JsInvocation(JsAstUtils.pureFqn(context().getNameForObjectInstance(entry), null)))
statements += JsReturn(JsInvocation(JsAstUtils.pureFqn(context().getNameForObjectInstance(entry), null)).source(psi))
source = psi
}
}
val message = JsBinaryOperation(JsBinaryOperator.ADD,
context().program().getStringLiteral("No enum constant ${descriptor.fqNameSafe}."),
nameParam.makeRef())
val throwStatement = JsExpressionStatement(JsInvocation(Namer.throwIllegalStateExceptionFunRef(), message))
val throwStatement = JsExpressionStatement(JsInvocation(Namer.throwIllegalStateExceptionFunRef(), message).source(psi))
if (clauses.isNotEmpty()) {
val defaultCase = JsDefault().apply { statements += throwStatement }
function.body.statements += JsSwitch(nameParam.makeRef(), clauses + defaultCase)
function.body.statements += JsSwitch(nameParam.makeRef().source(psi), clauses + defaultCase)
}
else {
function.body.statements += throwStatement
@@ -49,7 +49,6 @@ import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import java.util.ArrayList;
@@ -113,7 +112,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
// Initialize enum 'name' and 'ordinal' before translating property initializers.
if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) {
addEnumClassParameters(initFunction);
addEnumClassParameters(initFunction, classDeclaration);
}
}
@@ -123,13 +122,17 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
new InitializerVisitor().traverseContainer(classDeclaration, context().innerBlock(initFunction.getBody()));
}
private static void addEnumClassParameters(JsFunction constructorFunction) {
private static void addEnumClassParameters(JsFunction constructorFunction, PsiElement psiElement) {
JsName nameParamName = constructorFunction.getScope().declareFreshName("name");
JsName ordinalParamName = constructorFunction.getScope().declareFreshName("ordinal");
constructorFunction.getParameters().addAll(0, Arrays.asList(new JsParameter(nameParamName), new JsParameter(ordinalParamName)));
constructorFunction.getBody().getStatements().add(JsAstUtils.assignmentToThisField(Namer.ENUM_NAME_FIELD, nameParamName.makeRef()));
constructorFunction.getBody().getStatements().add(JsAstUtils.assignmentToThisField(Namer.ENUM_ORDINAL_FIELD, ordinalParamName.makeRef()));
JsStatement nameAssignment = JsAstUtils.assignmentToThisField(Namer.ENUM_NAME_FIELD, nameParamName.makeRef().source(psiElement));
constructorFunction.getBody().getStatements().add(nameAssignment);
JsStatement ordinalAssignment = JsAstUtils.assignmentToThisField(
Namer.ENUM_ORDINAL_FIELD, ordinalParamName.makeRef().source(psiElement));
constructorFunction.getBody().getStatements().add(ordinalAssignment);
}
private void addOuterClassReference(ClassDescriptor classDescriptor) {
@@ -170,7 +173,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
invocation.getArguments().addAll(0, additionalArgs);
}
return call;
return call.source(enumEntry);
}
private void mayBeAddCallToSuperMethod(JsFunction initializer) {
@@ -0,0 +1,11 @@
enum class E {
X,
Y,
Z {
init {
println("Z")
}
}
}
// LINES: 1 1 1 1 2 3 4 * 2 2 * 3 3 4 4 6 * 1 * 1 1 1 1 1 1