Fix JS source maps for delegates and backing fields

This commit is contained in:
Alexey Andreev
2017-05-12 19:49:35 +03:00
parent 13795b47fb
commit 1014666937
8 changed files with 103 additions and 14 deletions
@@ -42,6 +42,12 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest {
doTest(fileName);
}
@TestMetadata("backingField.kt")
public void testBackingField() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/backingField.kt");
doTest(fileName);
}
@TestMetadata("catch.kt")
public void testCatch() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/catch.kt");
@@ -78,6 +84,18 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest {
doTest(fileName);
}
@TestMetadata("delegatedProperty.kt")
public void testDelegatedProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/delegatedProperty.kt");
doTest(fileName);
}
@TestMetadata("delegation.kt")
public void testDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/delegation.kt");
doTest(fileName);
}
@TestMetadata("doWhileWithComplexCondition.kt")
public void testDoWhileWithComplexCondition() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/doWhileWithComplexCondition.kt");
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDe
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.utils.identity
class ClassModelGenerator(val context: StaticContext) {
@@ -192,7 +193,8 @@ class ClassModelGenerator(val context: StaticContext) {
val sourceName = context.getNameForDescriptor(key).ident
val targetName = context.getNameForDescriptor(value).ident
if (sourceName != targetName) {
val statement = generateDelegateCall(descriptor, key, value, JsThisRef(), translationContext, false)
val statement = generateDelegateCall(descriptor, key, value, JsThisRef(), translationContext, false,
descriptor.source.getPsi())
model.postDeclarationBlock.statements += statement
}
}
@@ -229,7 +231,7 @@ class ClassModelGenerator(val context: StaticContext) {
val translationContext = TranslationContext.rootContext(context)
model.postDeclarationBlock.statements += generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsThisRef(),
translationContext, false)
translationContext, false, descriptor.source.getPsi())
}
private fun copyMethod(
@@ -77,27 +77,29 @@ class DelegationTranslator(
val delegateInitExpr = Translation.translateAsExpression(expression, context)
statements += context.dynamicContext().jsBlock().statements
val lhs = JsAstUtils.pureFqn(field.name, JsThisRef())
statements += JsAstUtils.assignment(lhs, delegateInitExpr).makeStmt()
statements += JsAstUtils.assignment(lhs, delegateInitExpr)
.apply { source = specifier }
.makeStmt()
}
}
}
fun generateDelegated() {
for (specifier in delegationBySpecifiers) {
generateDelegates(getSuperClass(specifier), fields[specifier]!!)
generateDelegates(specifier, getSuperClass(specifier), fields[specifier]!!)
}
}
private fun getSuperClass(specifier: KtSuperTypeListEntry): ClassDescriptor =
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
private fun generateDelegates(toClass: ClassDescriptor, field: Field) {
private fun generateDelegates(specifier: KtSuperTypeListEntry, toClass: ClassDescriptor, field: Field) {
for ((descriptor, overriddenDescriptor) in DelegationResolver.getDelegates(classDescriptor, toClass)) {
when (descriptor) {
is PropertyDescriptor ->
generateDelegateCallForPropertyMember(descriptor, field.name)
generateDelegateCallForPropertyMember(specifier, descriptor, field.name)
is FunctionDescriptor ->
generateDelegateCallForFunctionMember(descriptor, overriddenDescriptor as FunctionDescriptor, field.name)
generateDelegateCallForFunctionMember(specifier, descriptor, overriddenDescriptor as FunctionDescriptor, field.name)
else ->
throw IllegalArgumentException("Expected property or function $descriptor")
}
@@ -105,6 +107,7 @@ class DelegationTranslator(
}
private fun generateDelegateCallForPropertyMember(
specifier: KtSuperTypeListEntry,
descriptor: PropertyDescriptor,
delegateName: JsName
) {
@@ -122,6 +125,8 @@ class DelegationTranslator(
JsNameRef(propertyName, delegateRef)
}
returnExpression.source(specifier)
val jsFunction = simpleReturnFunction(context().getScopeForDescriptor(getterDescriptor.containingDeclaration), returnExpression)
if (DescriptorUtils.isExtension(descriptor)) {
val receiverName = jsFunction.scope.declareName(Namer.getReceiverParameterName())
@@ -154,7 +159,7 @@ class DelegationTranslator(
}
jsFunction.parameters.add(defaultParameter)
jsFunction.body = JsBlock(setExpression.makeStmt())
jsFunction.body = JsBlock(setExpression.apply { source = specifier }.makeStmt())
return jsFunction
}
@@ -191,12 +196,13 @@ class DelegationTranslator(
private fun generateDelegateCallForFunctionMember(
specifier: KtSuperTypeListEntry,
descriptor: FunctionDescriptor,
overriddenDescriptor: FunctionDescriptor,
delegateName: JsName
) {
val delegateRef = JsNameRef(delegateName, JsThisRef())
val statement = generateDelegateCall(classDescriptor, descriptor, overriddenDescriptor, delegateRef, context(), true)
val statement = generateDelegateCall(classDescriptor, descriptor, overriddenDescriptor, delegateRef, context(), true, specifier)
context().addDeclarationStatement(statement)
}
}
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.source.getPsi
/**
* Translates single property /w accessors.
@@ -92,7 +93,7 @@ class DefaultPropertyTranslator(
assert(!descriptor.isExtension) { "Unexpected extension property $descriptor}" }
assert(descriptor is PropertyDescriptor) { "Property descriptor expected: $descriptor" }
val result = backingFieldReference(context(), descriptor as PropertyDescriptor)
function.body.statements += JsReturn(result)
function.body.statements += JsReturn(result).apply { source = descriptor.source.getPsi() }
}
private fun generateDelegatedGetterFunction(
@@ -105,7 +106,9 @@ class DefaultPropertyTranslator(
.newDeclarationIfNecessary(getterDescriptor, function)
.contextWithPropertyMetadataCreationIntrinsified(delegatedCall, descriptor, host)
val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference)
val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference).apply {
source = getterDescriptor.source.getPsi()
}
val returnResult = JsReturn(delegatedJsCall)
function.addStatement(returnResult)
@@ -123,14 +126,16 @@ class DefaultPropertyTranslator(
val delegateContext = withAliased
.newDeclarationIfNecessary(setterDescriptor, function)
.contextWithPropertyMetadataCreationIntrinsified(delegatedCall, descriptor, host)
val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference)
val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference).apply {
source = setterDescriptor.source.getPsi()
}
function.addStatement(delegatedJsCall.makeStmt())
}
else {
assert(!descriptor.isExtension) { "Unexpected extension property $descriptor}" }
assert(descriptor is PropertyDescriptor) { "Property descriptor expected: $descriptor" }
val assignment = assignmentToBackingField(withAliased, descriptor as PropertyDescriptor, valueParameter.makeRef())
function.addStatement(assignment.makeStmt())
function.addStatement(assignment.apply { source = descriptor.source.getPsi() }.makeStmt())
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.translate.utils
import com.intellij.psi.PsiElement
import com.intellij.util.SmartList
import org.jetbrains.kotlin.backend.common.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
@@ -45,7 +46,8 @@ fun generateDelegateCall(
toDescriptor: FunctionDescriptor,
thisObject: JsExpression,
context: TranslationContext,
detectDefaultParameters: Boolean
detectDefaultParameters: Boolean,
source: PsiElement?
): JsStatement {
fun FunctionDescriptor.getNameForFunctionWithPossibleDefaultParam() =
if (detectDefaultParameters && hasOrInheritsParametersWithDefaultValue()) {
@@ -82,6 +84,8 @@ fun generateDelegateCall(
JsInvocation(overriddenMemberFunctionRef, args)
}
invocation.source = source
val functionObject = simpleReturnFunction(context.scope(), invocation)
functionObject.parameters.addAll(parameters)
+15
View File
@@ -0,0 +1,15 @@
open class A {
open var x = 23
var y: String = "42"
get() = field +
"!"
set(value) {
print(
field)
field =
value.removeSuffix("!")
}
}
// LINES: 2 4 2 2 * 5 6 8 9 10 11
@@ -0,0 +1,18 @@
import kotlin.reflect.*
open class A {
var x: String by
B()
}
class B {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "OK"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println(value)
}
}
// LINES: 4 5 4 4 2 * 10 * 14
+21
View File
@@ -0,0 +1,21 @@
class A :
I
by o
interface I {
fun foo(): String
var bar: Int
}
val o = object : I {
override fun foo(): String = "foo"
override var bar: Int
get() = 23
set(value) {
println(value)
}
}
// LINES: 2 3 2 2 * 2 * 12 * 15 17