diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 058a428dd3d..d8356948777 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1717,6 +1717,21 @@ public class ExpressionCodegen extends JetVisitor implem v.visitLineNumber(lineNumber, label); } + //we should generate additional linenumber info after inline call only if it used as argument + public void markLineNumberAfterInlineIfNeeded() { + if (!shouldMarkLineNumbers) { + //if it used as general argument + if (myLastLineNumber > -1) { + Label label = new Label(); + v.visitLabel(label); + v.visitLineNumber(myLastLineNumber, label); + } + } else { + //if it used as argument of infix call (in this case lineNumber for simple inlineCall also would be reset) + myLastLineNumber = -1; + } + } + private void doFinallyOnReturn() { if(!blockStackElements.isEmpty()) { BlockStackElement stackElement = blockStackElements.peek(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 182312f1f96..ccde808d88c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -154,6 +154,8 @@ public class InlineCodegen extends CallGenerator { codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages()); state.getFactory().removeInlinedClasses(result.getClassesToRemove()); + + codegen.markLineNumberAfterInlineIfNeeded(); } @NotNull diff --git a/compiler/testData/codegen/boxInline/smap/smap.2.kt b/compiler/testData/codegen/boxInline/smap/smap.2.kt index 42f03f73739..b973d593786 100644 --- a/compiler/testData/codegen/boxInline/smap/smap.2.kt +++ b/compiler/testData/codegen/boxInline/smap/smap.2.kt @@ -8,8 +8,8 @@ inline fun initTag2(init: () -> Unit) { val p = 1; init() } - -inline fun head(init: () -> Unit) = initTag2(init) +//{val p = initTag2(init); return p} to remove difference in linenumber processing through MethodNode and MethodVisitor should be: = initTag2(init) +inline fun head(init: () -> Unit) {val p = initTag2(init); return p} inline fun html(init: () -> Unit) { diff --git a/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/chainCalls.kt b/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/chainCalls.kt new file mode 100644 index 00000000000..99316127d2d --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/chainCalls.kt @@ -0,0 +1,82 @@ +fun testProperLineNumber(): String { + var exceptionCount = 0; + try { + test(). + test(). + fail() + + } + catch(e: AssertionError) { + val entry = (e as java.lang.Throwable).getStackTrace()!!.get(1) + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("chainCalls.kt:6" != actual) { + return "fail 1: ${actual}" + } + exceptionCount++ + } + + try { + call(). + test(). + fail() + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("chainCalls.kt:21" != actual) { + return "fail 2: ${actual}" + } + exceptionCount++ + } + + try { + test(). + fail() + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("chainCalls.kt:34" != actual) { + return "fail 3: ${actual}" + } + exceptionCount++ + } + + try { + test().fail() + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("chainCalls.kt:46" != actual) { + return "fail 4: ${actual}" + } + exceptionCount++ + } + + return if (exceptionCount == 4) "OK" else "fail" +} + +fun box(): String { + return testProperLineNumber() +} + +public fun checkEquals(p1: String, p2: String) { + throw AssertionError("fail") +} + +inline fun test(): String { + return "123" +} + +inline fun String.test(): String { + return "123" +} + +fun String.fail(): String { + throw AssertionError("fail") +} + +fun call(): String { + return "xxx" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/infixCalls.kt b/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/infixCalls.kt new file mode 100644 index 00000000000..6029a2f43c7 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/infixCalls.kt @@ -0,0 +1,62 @@ +fun testProperLineNumber(): String { + var exceptionCount = 0; + try { + test() fail + call() + } + catch(e: AssertionError) { + val entry = (e as java.lang.Throwable).getStackTrace()!!.get(1) + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("infixCalls.kt:4" != actual) { + return "fail 1: ${actual}" + } + exceptionCount++ + } + + try { + call() fail + test() + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("infixCalls.kt:17" != actual) { + return "fail 1: ${actual}" + } + exceptionCount++ + } + + try { + call() fail test() + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("infixCalls.kt:30" != actual) { + return "fail 1: ${actual}" + } + exceptionCount++ + } + + return if (exceptionCount == 3) "OK" else "fail" +} + +fun box(): String { + return testProperLineNumber() +} + +public fun checkEquals(p1: String, p2: String) { + throw AssertionError("fail") +} + +inline fun test(): String { + return "123" +} + +fun String.fail(p: String): String { + throw AssertionError("fail") +} + +fun call(): String { + return "xxx" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/simpleCallWithParams.kt b/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/simpleCallWithParams.kt new file mode 100644 index 00000000000..21b4dda4e38 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/fullJdk/smap/simpleCallWithParams.kt @@ -0,0 +1,106 @@ +fun testProperLineNumberAfterInline(): String { + var exceptionCount = 0; + try { + checkEquals(test(), + "12") + } + catch(e: AssertionError) { + val entry = (e as java.lang.Throwable).getStackTrace()!!.get(1) + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("simpleCallWithParams.kt:4" != actual) { + return "fail 1: ${actual}" + } + exceptionCount++ + } + + try { + checkEquals("12", + test()) + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("simpleCallWithParams.kt:17" != actual) { + return "fail 2: ${actual}" + } + exceptionCount++ + } + + return if (exceptionCount == 2) "OK" else "fail" +} + +fun testProperLineForOtherParameters(): String { + var exceptionCount = 0; + try { + checkEquals(test(), + fail()) + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("simpleCallWithParams.kt:35" != actual) { + return "fail 3: ${actual}" + } + exceptionCount++ + + } + + try { + checkEquals(fail(), + test()) + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("simpleCallWithParams.kt:49" != actual) { + return "fail 4: ${actual}" + } + exceptionCount++ + } + + try { + checkEquals(fail(), test()) + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("simpleCallWithParams.kt:62" != actual) { + return "fail 5: ${actual}" + } + exceptionCount++ + } + + try { + checkEquals(fail(), test()) + } + catch(e: AssertionError) { + val entry = e.getStackTrace()!![1] + val actual = "${entry.getFileName()}:${entry.getLineNumber()}" + if ("simpleCallWithParams.kt:74" != actual) { + return "fail 6: ${actual}" + } + exceptionCount++ + } + + return if (exceptionCount == 4) "OK" else "fail" +} + + +fun box(): String { + val res = testProperLineNumberAfterInline() + if (res != "OK") return "$res" + + return testProperLineForOtherParameters() +} + +public fun checkEquals(p1: String, p2: String) { + throw AssertionError("fail") +} + +inline fun test(): String { + return "123" +} + +fun fail(): String { + throw AssertionError("fail") +} \ No newline at end of file diff --git a/compiler/testData/lineNumber/custom/smapInlineAsArgument.kt b/compiler/testData/lineNumber/custom/smapInlineAsArgument.kt new file mode 100644 index 00000000000..e7f7ac9c043 --- /dev/null +++ b/compiler/testData/lineNumber/custom/smapInlineAsArgument.kt @@ -0,0 +1,21 @@ +fun box(){ + checkEquals(test(), + fail()) + + checkEquals(fail(), + test()) +} + +public fun checkEquals(p1: String, p2: String) { + throw AssertionError("fail") +} + +inline fun test() : String { + return "123" +} + +fun fail() : String { + throw AssertionError("fail") +} + +// 2 14 2 5 14 5 7 10 14 18 \ No newline at end of file diff --git a/compiler/testData/lineNumber/custom/smapInlineAsInfixArgument.kt b/compiler/testData/lineNumber/custom/smapInlineAsInfixArgument.kt new file mode 100644 index 00000000000..0d815f84177 --- /dev/null +++ b/compiler/testData/lineNumber/custom/smapInlineAsInfixArgument.kt @@ -0,0 +1,19 @@ +fun String.execute(p: String) = this + p + +fun box(){ + test() execute + fail() + + fail() execute + test() +} + +inline fun test() : String { + return "123" +} + +fun fail() : String { + throw AssertionError("fail") +} + +// 1 4 12 4 7 12 7 9 12 16 \ No newline at end of file diff --git a/compiler/testData/lineNumber/custom/smapInlineAsInlineArgument.kt b/compiler/testData/lineNumber/custom/smapInlineAsInlineArgument.kt new file mode 100644 index 00000000000..2fa321bf0d4 --- /dev/null +++ b/compiler/testData/lineNumber/custom/smapInlineAsInlineArgument.kt @@ -0,0 +1,21 @@ +fun box(){ + test(test("1", "2"), + fail()) + + test(fail(), + test("1", "2")) +} + +public fun checkEquals(p1: String, p2: String) { + throw AssertionError("fail") +} + +inline fun test(p: String, s: String) : String { + return "123" +} + +fun fail() : String { + throw AssertionError("fail") +} + +//2 14 2 14 5 14 5 14 7 10 14 18 \ No newline at end of file diff --git a/compiler/testData/lineNumber/custom/smapInlineInIntrinsicArgument.kt b/compiler/testData/lineNumber/custom/smapInlineInIntrinsicArgument.kt new file mode 100644 index 00000000000..a032a5a9b7a --- /dev/null +++ b/compiler/testData/lineNumber/custom/smapInlineInIntrinsicArgument.kt @@ -0,0 +1,17 @@ +fun box(){ + test() + + fail() + + fail() + + test() +} + +inline fun test() : String { + return "123" +} + +fun fail() : String { + throw AssertionError("fail") +} + +// 2 10 3 5 6 10 7 10 14 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java index a8971b0233c..046aec3298b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LineNumberTestGenerated.java @@ -219,6 +219,30 @@ public class LineNumberTestGenerated extends AbstractLineNumberTest { doTestCustom(fileName); } + @TestMetadata("smapInlineAsArgument.kt") + public void testSmapInlineAsArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/custom/smapInlineAsArgument.kt"); + doTestCustom(fileName); + } + + @TestMetadata("smapInlineAsInfixArgument.kt") + public void testSmapInlineAsInfixArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/custom/smapInlineAsInfixArgument.kt"); + doTestCustom(fileName); + } + + @TestMetadata("smapInlineAsInlineArgument.kt") + public void testSmapInlineAsInlineArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/custom/smapInlineAsInlineArgument.kt"); + doTestCustom(fileName); + } + + @TestMetadata("smapInlineInIntrinsicArgument.kt") + public void testSmapInlineInIntrinsicArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/custom/smapInlineInIntrinsicArgument.kt"); + doTestCustom(fileName); + } + @TestMetadata("tryCatchExpression.kt") public void testTryCatchExpression() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/custom/tryCatchExpression.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index cba6d8798d4..f1e5a011fcd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -1404,6 +1404,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode @InnerTestClasses({ FullJdk.Native.class, FullJdk.Regressions.class, + FullJdk.Smap.class, FullJdk.Synchronized.class, }) @RunWith(JUnit3RunnerWithInners.class) @@ -1586,6 +1587,33 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/fullJdk/smap") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Smap extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInSmap() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/fullJdk/smap"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("chainCalls.kt") + public void testChainCalls() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/fullJdk/smap/chainCalls.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("infixCalls.kt") + public void testInfixCalls() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/fullJdk/smap/infixCalls.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("simpleCallWithParams.kt") + public void testSimpleCallWithParams() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/fullJdk/smap/simpleCallWithParams.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/fullJdk/synchronized") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)