Fix JS source maps for data class synthetic methods

This commit is contained in:
Alexey Andreev
2017-05-15 16:34:53 +03:00
parent 5bc6c07f9e
commit 6f0e4c4deb
4 changed files with 42 additions and 11 deletions
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.resolve.BindingContextUtils
* TODO: data class with zero components gets no toString/equals/hashCode methods. This is inconsistent and should be
* changed here with the platform backends adopted.
*/
abstract class DataClassMethodGenerator(private val declaration: KtClassOrObject, private val bindingContext: BindingContext) {
abstract class DataClassMethodGenerator(protected val declaration: KtClassOrObject, private val bindingContext: BindingContext) {
protected val classDescriptor: ClassDescriptor = BindingContextUtils.getNotNull(bindingContext, BindingContext.CLASS, declaration)
fun generate() {
@@ -78,6 +78,12 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest {
doTest(fileName);
}
@TestMetadata("dataClass.kt")
public void testDataClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/dataClass.kt");
doTest(fileName);
}
@TestMetadata("delegateMemberVal.kt")
public void testDelegateMemberVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/delegateMemberVal.kt");
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.translate.declaration;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator;
import org.jetbrains.kotlin.descriptors.*;
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtParameter;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import java.util.ArrayList;
import java.util.List;
@@ -51,7 +53,9 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
JsFunction functionObject = generateJsMethod(function);
JsExpression returnExpression = JsAstUtils.pureFqn(context.getNameForDescriptor(propertyDescriptor), new JsThisRef());
functionObject.getBody().getStatements().add(new JsReturn(returnExpression));
JsReturn returnStatement = new JsReturn(returnExpression);
returnStatement.setSource(KotlinSourceElementKt.getPsi(parameter.getSource()));
functionObject.getBody().getStatements().add(returnStatement);
}
@Override
@@ -87,7 +91,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
JsExpression defaultCondition = JsAstUtils.equality(new JsNameRef(paramName), Namer.getUndefinedExpression());
argumentValue = new JsConditional(defaultCondition, new JsNameRef(fieldName, new JsThisRef()), parameterValue);
}
constructorArguments.add(argumentValue);
constructorArguments.add(argumentValue.source(constructorParam));
}
ClassDescriptor classDescriptor = (ClassDescriptor) function.getContainingDeclaration();
@@ -100,7 +104,11 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
if (context.shouldBeDeferred(constructor)) {
context.deferConstructorCall(constructor, returnExpression.getArguments());
}
functionObj.getBody().getStatements().add(new JsReturn(returnExpression));
returnExpression.setSource(getDeclaration());
JsReturn returnStatement = new JsReturn(returnExpression);
returnStatement.setSource(getDeclaration());
functionObj.getBody().getStatements().add(returnStatement);
}
@Override
@@ -115,7 +123,8 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
JsName name = context.getNameForDescriptor(classProperties.get(i));
JsExpression literal = new JsStringLiteral((i == 0 ? (getClassDescriptor().getName() + "(") : ", ") + printName + "=");
JsExpression expr = new JsInvocation(context.namer().kotlin("toString"), new JsNameRef(name, new JsThisRef()));
JsExpression component = JsAstUtils.sum(literal, expr);
PsiElement source = KotlinSourceElementKt.getPsi(classProperties.get(i).getSource());
JsExpression component = JsAstUtils.sum(literal, expr).source(source);
if (result == null) {
result = component;
}
@@ -125,7 +134,10 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
}
assert result != null;
result = JsAstUtils.sum(result, new JsStringLiteral(")"));
functionObj.getBody().getStatements().add(new JsReturn(result));
JsReturn returnStatement = new JsReturn(result);
returnStatement.setSource(getDeclaration());
functionObj.getBody().getStatements().add(returnStatement);
}
@Override
@@ -136,7 +148,9 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
JsName varName = functionObj.getScope().declareName("result");
statements.add(new JsVars(new JsVars.JsVar(varName, new JsIntLiteral(0))));
JsVars resultVar = new JsVars(new JsVars.JsVar(varName, new JsIntLiteral(0)));
resultVar.setSource(getDeclaration());
statements.add(resultVar);
for (PropertyDescriptor prop : classProperties) {
// TODO: we should statically check that we can call hashCode method directly.
@@ -146,10 +160,12 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
JsExpression assignment = JsAstUtils.assignment(new JsNameRef(varName),
new JsBinaryOperation(JsBinaryOperator.BIT_OR, newHashValue,
new JsIntLiteral(0)));
statements.add(assignment.makeStmt());
statements.add(assignment.source(KotlinSourceElementKt.getPsi(prop.getSource())).makeStmt());
}
statements.add(new JsReturn(new JsNameRef(varName)));
JsReturn returnStatement = new JsReturn(new JsNameRef(varName));
returnStatement.setSource(getDeclaration());
statements.add(returnStatement);
}
@Override
@@ -171,9 +187,10 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
JsExpression fieldChain = null;
for (PropertyDescriptor prop : classProperties) {
JsName name = context.getNameForDescriptor(prop);
PsiElement source = KotlinSourceElementKt.getPsi(prop.getSource());
JsExpression next = new JsInvocation(context.namer().kotlin("equals"),
new JsNameRef(name, new JsThisRef()),
new JsNameRef(name, new JsNameRef(paramName)));
new JsNameRef(name, new JsNameRef(paramName))).source(source);
if (fieldChain == null) {
fieldChain = next;
}
@@ -184,7 +201,9 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
assert fieldChain != null;
JsExpression returnExpression = or(referenceEqual, and(isNotNull, and(otherIsObject, and(prototypeEqual, fieldChain))));
functionObj.getBody().getStatements().add(new JsReturn(returnExpression));
JsReturn returnStatement = new JsReturn(returnExpression);
returnStatement.setSource(getDeclaration());
functionObj.getBody().getStatements().add(returnStatement);
}
private JsFunction generateJsMethod(@NotNull FunctionDescriptor functionDescriptor) {
+6
View File
@@ -0,0 +1,6 @@
data class A(
val x: Int,
val y: String
)
// LINES: 2 3 * 2 * 3 * 1 2 3 * 1 2 3 * 1 2 3 1 * 1 2 3