diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt index 2c9bfc3aa53..08473397774 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt @@ -81,7 +81,7 @@ internal class ExpressionDecomposer private constructor( for (jsVar in vars) { if (jsVar in containsExtractable && prevVars.isNotEmpty()) { - addStatement(JsVars(prevVars, x.isMultiline)) + addStatement(JsVars(prevVars, x.isMultiline).apply { source = prevVars.first().source }) prevVars = SmartList() } @@ -89,8 +89,11 @@ internal class ExpressionDecomposer private constructor( prevVars.add(jsVar) } - vars.clear() - vars.addAll(prevVars) + if (vars.size != prevVars.size) { + vars.clear() + vars.addAll(prevVars) + x.source = prevVars.first().source + } return false } @@ -168,7 +171,7 @@ internal class ExpressionDecomposer private constructor( additionalStatements.toStatement() } - addStatement(JsIf(test, arg2Eval)) + addStatement(JsIf(test, arg2Eval).also { it.source = source }) ctx.replaceMe(tmp.nameRef) } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionInlineMutator.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionInlineMutator.kt index e2f6d734a2a..58f44600b81 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionInlineMutator.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionInlineMutator.kt @@ -50,7 +50,7 @@ private constructor( val parameters = getParameters() removeDefaultInitializers(arguments, parameters, body) - aliasArgumentsIfNeeded(namingContext, arguments, parameters) + aliasArgumentsIfNeeded(namingContext, arguments, parameters, call.source) renameLocalNames(namingContext, invokedFunction) processReturns() @@ -89,7 +89,7 @@ private constructor( val namingContext = inliningContext.newNamingContext() val arguments = call.arguments val parameters = outer.parameters - aliasArgumentsIfNeeded(namingContext, arguments, parameters) + aliasArgumentsIfNeeded(namingContext, arguments, parameters, call.source) namingContext.applyRenameTo(inner) } @@ -100,7 +100,7 @@ private constructor( if (thisReplacement == null || thisReplacement is JsThisRef) return val thisName = JsScope.declareTemporaryName(getThisAlias()) - namingContext.newVar(thisName, thisReplacement) + namingContext.newVar(thisName, thisReplacement, source = call.source) thisReplacement = thisName.makeRef() replaceThisReference(block, thisReplacement) @@ -121,7 +121,7 @@ private constructor( val resultName = JsScope.declareTemporaryName(getResultLabel()) this.resultName = resultName - namingContext.newVar(resultName, null) + namingContext.newVar(resultName, source = call.source) return resultName.makeRef() } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/NamingContext.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/NamingContext.kt index 785067ac732..0ec08ef96db 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/NamingContext.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/NamingContext.kt @@ -45,9 +45,10 @@ class NamingContext(private val statementContext: JsContext) { renamings.put(name, replacement) } - fun newVar(name: JsName, value: JsExpression? = null) { + fun newVar(name: JsName, value: JsExpression? = null, source: Any?) { val vars = JsAstUtils.newVar(name, value) vars.synthetic = true + vars.source = source declarations.add(vars) } } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/namingUtils.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/namingUtils.kt index 90eaf8ee02a..96b8060ced2 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/namingUtils.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/namingUtils.kt @@ -25,7 +25,8 @@ import org.jetbrains.kotlin.js.inline.util.rewriters.LabelNameRefreshingVisitor fun aliasArgumentsIfNeeded( context: NamingContext, arguments: List, - parameters: List + parameters: List, + source: Any? ) { require(arguments.size <= parameters.size) { "arguments.size (${arguments.size}) should be less or equal to parameters.size (${parameters.size})" } @@ -34,9 +35,10 @@ fun aliasArgumentsIfNeeded( val replacement = JsScope.declareTemporaryName(paramName.ident).apply { staticRef = arg - context.newVar(this, arg.deepCopy()) + context.newVar(this, arg.deepCopy(), source = source) }.makeRef() + replacement.source = arg.source context.replaceName(paramName, replacement) } @@ -45,7 +47,7 @@ fun aliasArgumentsIfNeeded( val paramName = defaultParam.name val freshName = JsScope.declareTemporaryName(paramName.ident) freshName.copyMetadataFrom(paramName) - context.newVar(freshName) + context.newVar(freshName, source = source) context.replaceName(paramName, freshName.makeRef()) } 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 2093bb6c102..6e5affbfc7c 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 @@ -120,12 +120,30 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest { doTest(fileName); } + @TestMetadata("destructuring.kt") + public void testDestructuring() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/destructuring.kt"); + doTest(fileName); + } + + @TestMetadata("destructuringInline.kt") + public void testDestructuringInline() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/destructuringInline.kt"); + doTest(fileName); + } + @TestMetadata("doWhileWithComplexCondition.kt") public void testDoWhileWithComplexCondition() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/doWhileWithComplexCondition.kt"); doTest(fileName); } + @TestMetadata("elvis.kt") + public void testElvis() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/elvis.kt"); + doTest(fileName); + } + @TestMetadata("enumCompanionObject.kt") public void testEnumCompanionObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/enumCompanionObject.kt"); @@ -156,6 +174,12 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest { doTest(fileName); } + @TestMetadata("inlineArguments.kt") + public void testInlineArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/inlineArguments.kt"); + doTest(fileName); + } + @TestMetadata("inlineLocalVarsRef.kt") public void testInlineLocalVarsRef() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/inlineLocalVarsRef.kt"); @@ -186,6 +210,12 @@ public class JsLineNumberTestGenerated extends AbstractJsLineNumberTest { doTest(fileName); } + @TestMetadata("isOperator.kt") + public void testIsOperator() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/isOperator.kt"); + doTest(fileName); + } + @TestMetadata("lambdaWithClosure.kt") public void testLambdaWithClosure() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/lineNumbers/lambdaWithClosure.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/CatchTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/CatchTranslator.kt index 1d4c3bacbf0..13bac20bd03 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/CatchTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/CatchTranslator.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.js.translate.expression +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.general.AbstractTranslator @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.types.isDynamic class CatchTranslator( val catches: List, + val psi: PsiElement, context: TranslationContext ) : AbstractTranslator(context) { @@ -86,7 +88,7 @@ class CatchTranslator( catches: Iterator ): JsStatement { if (!catches.hasNext()) { - return JsThrow(initialCatchParameterRef) + return JsThrow(initialCatchParameterRef).apply { source = psi } } var nextContext = context diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java index d5eeab3fe07..72fcc981aa7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java @@ -92,8 +92,12 @@ public class DestructuringDeclarationTranslator extends AbstractTranslator { entryInitializer = JsAstUtils.wrapValue(alias, entryInitializer); } - jsVars.add(new JsVars.JsVar(name, entryInitializer)); + JsVars.JsVar jsVar = new JsVars.JsVar(name, entryInitializer); + jsVar.setSource(entry); + jsVars.add(jsVar); } - return new JsVars(jsVars, true); + JsVars result = new JsVars(jsVars, true); + result.setSource(multiDeclaration); + return result; } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index 19a4758bcf6..95f632dea73 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -391,7 +391,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitIsExpression(@NotNull KtIsExpression expression, @NotNull TranslationContext context) { - return Translation.patternTranslator(context).translateIsExpression(expression); + return Translation.patternTranslator(context).translateIsExpression(expression).source(expression); } @Override diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LoopTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LoopTranslator.kt index e3f31b02871..fb774d83cef 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LoopTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LoopTranslator.kt @@ -115,12 +115,13 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont val currentVarInit = if (destructuringParameter == null) { - newVar(parameterName, itemValue) + newVar(parameterName, itemValue).apply { source = expression.loopRange } } else { val innerBlockContext = context.innerBlock(block) if (itemValue != null) { - innerBlockContext.addStatementToCurrentBlock(JsAstUtils.newVar(parameterName, itemValue)) + val parameterStatement = JsAstUtils.newVar(parameterName, itemValue).apply { source = expression.loopRange } + innerBlockContext.addStatementToCurrentBlock(parameterStatement) } DestructuringDeclarationTranslator.translate( destructuringParameter, JsAstUtils.pureFqn(parameterName, null), innerBlockContext) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/TryTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/TryTranslator.kt index 1aecfe933fd..cdb6622adb9 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/TryTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/TryTranslator.kt @@ -32,7 +32,7 @@ class TryTranslator( fun translate(): JsTry { val tryBlock = translateAsBlock(expression.tryBlock) - val catchTranslator = CatchTranslator(expression.catchClauses, context()) + val catchTranslator = CatchTranslator(expression.catchClauses, expression, context()) val catchBlock = catchTranslator.translate() val finallyExpression = expression.finallyBlock?.finalExpression diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java index 52a92019982..cecae5837b7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java @@ -154,6 +154,7 @@ public final class BinaryOperationTranslator extends AbstractTranslator { JsExpression testExpression = TranslationUtils.isNullCheck(leftExpression); ifStatement = JsAstUtils.newJsIf(testExpression, rightBlock); } + ifStatement.setSource(expression); context().addStatementToCurrentBlock(ifStatement); return result; } diff --git a/js/js.translator/testData/lineNumbers/catch.kt b/js/js.translator/testData/lineNumbers/catch.kt index a5f67c809a8..839ed2eba0a 100644 --- a/js/js.translator/testData/lineNumbers/catch.kt +++ b/js/js.translator/testData/lineNumbers/catch.kt @@ -19,4 +19,4 @@ fun bar() { } } -// LINES: 11 3 3 5 5 6 6 8 8 9 9 * 20 15 15 18 18 \ No newline at end of file +// LINES: 11 3 3 5 5 6 6 8 8 9 9 2 2 * 20 15 15 18 18 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/charBoxing.kt b/js/js.translator/testData/lineNumbers/charBoxing.kt index 4939a1aa5b3..1469ab9b2ae 100644 --- a/js/js.translator/testData/lineNumbers/charBoxing.kt +++ b/js/js.translator/testData/lineNumbers/charBoxing.kt @@ -17,4 +17,4 @@ fun bar(a: String, b: Char, x: Int) { a.foo(b) } -// LINES: 6 4 4 5 5 11 9 9 10 10 18 14 14 14 14 14 15 17 9 9 14 10 17 10 14 14 * 1 * 1 \ No newline at end of file +// LINES: 6 4 4 5 5 11 9 9 10 10 18 14 14 14 14 14 15 17 17 9 9 14 10 17 10 14 14 * 1 * 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/destructuring.kt b/js/js.translator/testData/lineNumbers/destructuring.kt new file mode 100644 index 00000000000..a29bb97b188 --- /dev/null +++ b/js/js.translator/testData/lineNumbers/destructuring.kt @@ -0,0 +1,30 @@ +var log = "" + +fun foo() { + for ( + ( + q, + w + ) + in listOf(Pair("1", "2")) + ) { + log += q + log += w + } + + bar { + ( + q, + w + ) -> + log += q + log += w + } +} + +fun bar(f: (Pair) -> Unit) { + f(Pair("w", "e")) +} + + +// LINES: 22 16 16 17 18 20 20 21 21 23 9 9 9 9 4 9 9 9 5 5 6 7 11 11 12 12 15 15 27 26 26 * 1 * 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/destructuringInline.kt b/js/js.translator/testData/lineNumbers/destructuringInline.kt new file mode 100644 index 00000000000..e64423be376 --- /dev/null +++ b/js/js.translator/testData/lineNumbers/destructuringInline.kt @@ -0,0 +1,35 @@ +var log = "" + +fun foo() { + for ( + ( + q, + w + ) + in listOf(P("1", "2")) + ) { + log += q + log += w + } + + bar { + ( + q, + w + ) -> + log += q + log += w + } +} + +fun bar(f: (P) -> Unit) { + f(P("w", "e")) +} + +class P(val a: String, val b: String) + +inline operator fun P.component1() = a + +inline operator fun P.component2() = b + +// LINES: 22 17 17 31 18 18 33 20 20 21 21 23 9 9 9 9 4 9 9 9 6 6 31 7 7 33 11 11 12 12 15 15 27 26 26 29 29 29 * 31 31 31 33 33 33 * 1 * 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/elvis.kt b/js/js.translator/testData/lineNumbers/elvis.kt new file mode 100644 index 00000000000..c9de55ab3b1 --- /dev/null +++ b/js/js.translator/testData/lineNumbers/elvis.kt @@ -0,0 +1,12 @@ +var log = "" + +fun box(x: String?) { + log += + x + ?: + try { foo() } finally { log += "finally" } +} + +fun foo() = "bar" + +// LINES: 8 7 7 4 4 4 5 5 7 7 7 7 * 5 4 5 10 10 10 * 1 * 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/for.kt b/js/js.translator/testData/lineNumbers/for.kt index f8bca1a724c..9342979b2f3 100644 --- a/js/js.translator/testData/lineNumbers/for.kt +++ b/js/js.translator/testData/lineNumbers/for.kt @@ -17,4 +17,4 @@ fun box() { } } -// LINES: 18 2 2 10 15 2 2 2 2 2 3 3 6 6 6 6 7 7 10 10 10 10 10 11 11 14 14 15 15 15 15 15 15 15 15 15 15 15 15 16 16 \ No newline at end of file +// LINES: 18 2 2 10 15 2 2 2 2 2 2 3 3 6 6 6 6 7 7 10 10 10 10 10 10 11 11 14 14 15 15 15 15 15 15 15 15 15 15 15 15 16 16 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/inlineArguments.kt b/js/js.translator/testData/lineNumbers/inlineArguments.kt new file mode 100644 index 00000000000..8e01ac5c37f --- /dev/null +++ b/js/js.translator/testData/lineNumbers/inlineArguments.kt @@ -0,0 +1,14 @@ +var log = "" + +fun box() { + foo(bar()) +} + +inline fun foo(x: Int) { + log += x + log += x +} + +fun bar() = 23 + +// LINES: 5 4 4 8 8 9 9 10 8 8 9 9 12 12 12 * 1 * 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/inlineReturn.kt b/js/js.translator/testData/lineNumbers/inlineReturn.kt index e2c94ffb7c6..e97a0a24111 100644 --- a/js/js.translator/testData/lineNumbers/inlineReturn.kt +++ b/js/js.translator/testData/lineNumbers/inlineReturn.kt @@ -21,4 +21,4 @@ fun bar(x: Int) { println("%") } -// LINES: 17 2 2 3 3 4 7 7 9 9 10 10 11 14 14 16 16 22 20 * 2 2 3 3 4 3 7 7 9 9 10 10 11 10 14 14 16 16 * 20 21 21 \ No newline at end of file +// LINES: 17 2 2 3 3 4 7 7 9 9 10 10 11 14 14 16 16 22 20 20 20 20 2 2 3 3 4 3 7 7 9 9 10 10 11 10 14 14 16 16 * 20 21 21 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/isOperator.kt b/js/js.translator/testData/lineNumbers/isOperator.kt new file mode 100644 index 00000000000..e072670e52e --- /dev/null +++ b/js/js.translator/testData/lineNumbers/isOperator.kt @@ -0,0 +1,14 @@ +var log = "" + +fun box(a: Any) { + if (a is String && foo()) { + log += "OK" + } +} + +inline fun foo(): Boolean { + log += "foo" + return true +} + +// LINES: 7 4 4 4 10 10 4 11 4 5 5 12 10 10 11 11 * 1 * 1 \ No newline at end of file