diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/JsLineNumberTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/JsLineNumberTestGenerated.java index 4bb05ec45b0..18ee60fd347 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/JsLineNumberTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/JsLineNumberTestGenerated.java @@ -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"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt index f77ae0afb8c..4c8af069a4d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassModelGenerator.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( diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt index de15795455f..4760a0d00c8 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt @@ -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) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt index e84434a5640..f01aa4761cc 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt @@ -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()) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index f965c8f03f0..256291a9a5c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -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) diff --git a/js/js.translator/testData/lineNumbers/backingField.kt b/js/js.translator/testData/lineNumbers/backingField.kt new file mode 100644 index 00000000000..7b2dedd5cd6 --- /dev/null +++ b/js/js.translator/testData/lineNumbers/backingField.kt @@ -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 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/delegatedProperty.kt b/js/js.translator/testData/lineNumbers/delegatedProperty.kt new file mode 100644 index 00000000000..f940361ea13 --- /dev/null +++ b/js/js.translator/testData/lineNumbers/delegatedProperty.kt @@ -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 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/delegation.kt b/js/js.translator/testData/lineNumbers/delegation.kt new file mode 100644 index 00000000000..f197b7d8037 --- /dev/null +++ b/js/js.translator/testData/lineNumbers/delegation.kt @@ -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 \ No newline at end of file