From ddf92ef18733a5e72085720ac770e06d899008ea Mon Sep 17 00:00:00 2001 From: Denis Vnukov Date: Mon, 20 Aug 2018 16:00:28 -0700 Subject: [PATCH] Creating IrLineNumberTestGenerated, adding line numbers for few common expressions This PR enables LineNumberTestGenerated test on IR backend. The testing of hardcoded sequence of line numbers is replaced with mere checks for set-like checks for expected line numbers. --- .../codegen/inline/SMAPAndMethodNode.kt | 8 +- .../backend/jvm/codegen/ClassCodegen.kt | 14 +- .../backend/jvm/codegen/ExpressionCodegen.kt | 91 ++++++- .../jvm/codegen/IrSourceCompilerForInline.kt | 100 ++++++- .../backend/jvm/codegen/irCodegenUtils.kt | 23 +- .../codegen/boxInline/complexStack/asCheck.kt | 1 - .../tryFinally/nonLocalReturnToCatchBlock.kt | 1 - .../custom/functionCallWithDefault.kt | 2 +- .../inTheEndOfLambdaArgumentOfInlineCall.kt | 2 +- compiler/testData/lineNumber/if.kt | 1 + .../kotlin/codegen/AbstractLineNumberTest.kt | 194 +++++++------- .../codegen/ir/AbstractIrLineNumberTest.kt | 84 ++++++ .../codegen/ir/IrLineNumberTestGenerated.java | 244 ++++++++++++++++++ .../generators/tests/GenerateCompilerTests.kt | 9 +- 14 files changed, 644 insertions(+), 130 deletions(-) create mode 100644 compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrLineNumberTest.kt create mode 100644 compiler/tests/org/jetbrains/kotlin/codegen/ir/IrLineNumberTestGenerated.java diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt index d09a0d38945..c3cc2fc2146 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPAndMethodNode.kt @@ -23,12 +23,12 @@ import java.util.* //TODO comment class SMAPAndMethodNode(val node: MethodNode, val classSMAP: SMAP) { - val sortedRanges = createLineNumberSequence(node, classSMAP).map { it.mapper }.distinct().toList().sortedWith(RangeMapping.Comparator) + val sortedRanges = createLineNumberSequence(node, classSMAP).distinct().toList().sortedWith(RangeMapping.Comparator) fun copyWithNewNode(newMethodNode: MethodNode) = SMAPAndMethodNode(newMethodNode, classSMAP) } -private fun createLineNumberSequence(node: MethodNode, classSMAP: SMAP): Sequence { +private fun createLineNumberSequence(node: MethodNode, classSMAP: SMAP): Sequence { return InsnSequence(node.instructions.first, null).filterIsInstance().map { lineNumber -> val index = classSMAP.intervals.binarySearch(RangeMapping(lineNumber.line, lineNumber.line, 1), Comparator { value, key -> @@ -37,8 +37,6 @@ private fun createLineNumberSequence(node: MethodNode, classSMAP: SMAP): Sequenc if (index < 0) { error("Unmapped line number in inlined function ${node.name}:${lineNumber.line}") } - LabelAndMapping(lineNumber, classSMAP.intervals[index]) + classSMAP.intervals[index] } } - -class LabelAndMapping(val lineNumberNode: LineNumberNode, val mapper: RangeMapping) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 4b80164e982..45f7c361b12 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -39,7 +39,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import java.lang.RuntimeException -class ClassCodegen private constructor( +open class ClassCodegen protected constructor( internal val irClass: IrClass, val context: JvmBackendContext, private val parentClassCodegen: ClassCodegen? = null @@ -66,7 +66,9 @@ class ClassCodegen private constructor( val psiElement = irClass.descriptor.psiElement!! - val visitor: ClassBuilder = state.factory.newVisitor(OtherOrigin(psiElement, descriptor), type, psiElement.containingFile) + val visitor: ClassBuilder = createClassBuilder() + + open fun createClassBuilder() = state.factory.newVisitor(OtherOrigin(psiElement, descriptor), type, psiElement.containingFile) private var sourceMapper: DefaultSourceMapper? = null @@ -210,13 +212,7 @@ class ClassCodegen private constructor( fun getOrCreateSourceMapper(): DefaultSourceMapper { if (sourceMapper == null) { - sourceMapper = DefaultSourceMapper( - SourceInfo.createInfoForIr( - fileEntry.getSourceRangeInfo(irClass.startOffset, irClass.endOffset).endLineNumber + 1, - this.visitor.thisName, - this.psiElement.containingFile.name - ) - ) + sourceMapper = context.getSourceMapper(irClass) } return sourceMapper!! } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index e6bc2ffd4b8..ead6a3bc7d9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicFunction import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods import org.jetbrains.kotlin.backend.jvm.lower.CrIrType @@ -118,12 +119,9 @@ class ExpressionCodegen( fun generate() { mv.visitCode() val startLabel = markNewLabel() - irFunction.markLineNumber(true) val info = BlockInfo.create() val result = irFunction.body!!.accept(this, info) - - irFunction.markLineNumber(false) - + markFunctionLineNumber() val returnType = typeMapper.mapReturnType(irFunction.descriptor) if (irFunction.body is IrExpressionBody) { mv.areturn(returnType) @@ -141,6 +139,28 @@ class ExpressionCodegen( mv.visitEnd() } + private fun markFunctionLineNumber() { + if (irFunction.origin == JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER) { + return + } + if (irFunction is IrConstructor && irFunction.isPrimary) { + irFunction.markLineNumber(startOffset = true) + return + } + val lastElement = irFunction.body!!.getLastElement() + if (lastElement !is IrReturn) { + irFunction.markLineNumber(startOffset = false) + } + } + + private fun IrElement.getLastElement(): IrElement { + return when (this) { + is IrStatementContainer -> if (this.statements.isEmpty()) this else this.statements[this.statements.size - 1].getLastElement() + is IrExpressionBody -> this.expression.getLastElement() + else -> this + } + } + private fun writeParameterInLocalVariableTable(startLabel: Label) { if (!irFunction.isStatic) { mv.visitLocalVariable("this", classCodegen.type.descriptor, null, startLabel, markNewLabel(), 0) @@ -175,7 +195,9 @@ class ExpressionCodegen( override fun visitBlockBody(body: IrBlockBody, data: BlockInfo): StackValue { return body.statements.fold(none()) { _, exp -> - exp.accept(this, data) + exp.accept(this, data).also { + (exp as? IrExpression)?.markEndOfStatementIfNeeded() + } } } @@ -223,10 +245,12 @@ class ExpressionCodegen( } override fun visitMemberAccess(expression: IrMemberAccessExpression, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) return generateCall(expression, null, data) } override fun visitCall(expression: IrCall, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) if (expression.descriptor is ConstructorDescriptor) { return generateNewCall(expression, data) } @@ -367,8 +391,11 @@ class ExpressionCodegen( val varType = typeMapper.mapType(declaration.descriptor) val index = frame.enter(declaration.symbol, varType) + declaration.markLineNumber(startOffset = true) + declaration.initializer?.apply { StackValue.local(index, varType).store(gen(this, varType, data), mv) + this.markLineNumber(startOffset = true) } val info = VariableInfo( @@ -392,6 +419,7 @@ class ExpressionCodegen( } override fun visitGetValue(expression: IrGetValue, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) return generateLocal(expression.symbol, expression.asmType) } @@ -410,12 +438,14 @@ class ExpressionCodegen( } override fun visitGetField(expression: IrGetField, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) val value = generateFieldValue(expression, data) value.put(value.type, mv) return onStack(value.type) } override fun visitSetField(expression: IrSetField, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) val fieldValue = generateFieldValue(expression, data) fieldValue.store(expression.value.accept(this, data), mv) return none() @@ -450,12 +480,15 @@ class ExpressionCodegen( } override fun visitSetVariable(expression: IrSetVariable, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) + expression.value.markLineNumber(startOffset = true) val value = expression.value.accept(this, data) StackValue.local(findLocalIndex(expression.symbol), expression.descriptor.asmType).store(value, mv) return none() } override fun visitConst(expression: IrConst, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) val value = expression.value val type = expression.asmType StackValue.constant(value, type).put(type, mv) @@ -480,6 +513,7 @@ class ExpressionCodegen( } override fun visitVararg(expression: IrVararg, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) val outType = expression.type val type = expression.asmType assert(type.sort == Type.ARRAY) @@ -588,7 +622,7 @@ class ExpressionCodegen( val afterReturnLabel = Label() generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data) - expression.markLineNumber(false) + expression.markLineNumber(startOffset = true) mv.areturn(returnType) mv.mark(afterReturnLabel) mv.nop()/*TODO check RESTORE_STACK_IN_TRY_CATCH processor*/ @@ -596,8 +630,10 @@ class ExpressionCodegen( } - override fun visitWhen(expression: IrWhen, data: BlockInfo): StackValue = - genIfWithBranches(expression.branches[0], data, expression.type.toKotlinType(), expression.branches.drop(1)) + override fun visitWhen(expression: IrWhen, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) + return genIfWithBranches(expression.branches[0], data, expression.type.toKotlinType(), expression.branches.drop(1)) + } private fun genIfWithBranches(branch: IrBranch, data: BlockInfo, type: KotlinType, otherBranches: List): StackValue { @@ -636,6 +672,7 @@ class ExpressionCodegen( when (expression.operator) { IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { val result = expression.argument.accept(this, data) + expression.argument.markEndOfStatementIfNeeded() coerce(result.type, Type.VOID_TYPE, mv) return none() } @@ -686,7 +723,21 @@ class ExpressionCodegen( return expression.onStack } + private fun IrExpression.markEndOfStatementIfNeeded() { + when (this) { + is IrWhen -> if (this.branches.size > 1) { + this.markLineNumber(false) + } + is IrTry -> this.markLineNumber(false) + is IrContainerExpression -> when (this.origin) { + IrStatementOrigin.WHEN, IrStatementOrigin.IF -> + this.markLineNumber(false) + } + } + } + override fun visitStringConcatenation(expression: IrStringConcatenation, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) AsmUtil.genStringBuilderConstructor(mv) expression.arguments.forEach { val stackValue = gen(it, data) @@ -712,6 +763,7 @@ class ExpressionCodegen( // GOTO L0 // L1 //TODO: write elimination lower + condition.markLineNumber(startOffset = true) if (!(condition is IrConst<*> && condition.value == true)) { gen(condition, data) BranchedValue.condJump(StackValue.onStack(condition.asmType), endLabel, true, mv) @@ -733,6 +785,7 @@ class ExpressionCodegen( } override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): StackValue { + jump.markLineNumber(startOffset = true) generateBreakOrContinueExpression(jump, Label(), data) return none() } @@ -788,6 +841,7 @@ class ExpressionCodegen( mv.visitLabel(continueLabel) val condition = loop.condition + condition.markLineNumber(startOffset = true) gen(condition, data) BranchedValue.condJump(StackValue.onStack(condition.asmType), entry, false, mv) mv.mark(endLabel) @@ -796,6 +850,7 @@ class ExpressionCodegen( } override fun visitTry(aTry: IrTry, data: BlockInfo): StackValue { + aTry.markLineNumber(startOffset = true) val finallyExpression = aTry.finallyExpression val tryInfo = if (finallyExpression != null) TryInfo(aTry) else null if (tryInfo != null) { @@ -821,6 +876,7 @@ class ExpressionCodegen( mv.store(index, descriptorType) val catchBody = clause.result + catchBody.markLineNumber(true) gen(catchBody, catchBody.asmType, data) frame.leave(clause.catchParameter) @@ -919,6 +975,9 @@ class ExpressionCodegen( } if (tryCatchBlockEnd != null) { + if (tryInfo != null) { + tryInfo.tryBlock.finallyExpression!!.markLineNumber(startOffset = false) + } mv.goTo(tryCatchBlockEnd) } @@ -967,6 +1026,7 @@ class ExpressionCodegen( } override fun visitThrow(expression: IrThrow, data: BlockInfo): StackValue { + expression.markLineNumber(startOffset = true) gen(expression.value, JAVA_THROWABLE_TYPE, data) mv.athrow() return none() @@ -1124,8 +1184,7 @@ class ExpressionCodegen( get() = mv override val inlineNameGenerator: NameGenerator = NameGenerator("${classCodegen.type.internalName}\$todo") - override val lastLineNumber: Int - get() = -1 //TODO + override var lastLineNumber: Int = -1 override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) { //TODO @@ -1151,7 +1210,17 @@ class ExpressionCodegen( private fun markNewLabel() = Label().apply { mv.visitLabel(this) } private fun IrElement.markLineNumber(startOffset: Boolean) { - mv.visitLineNumber(fileEntry.getLineNumber(if (startOffset) this.startOffset else endOffset) + 1, markNewLabel()) + val offset = if (startOffset) this.startOffset else endOffset + if (offset < 0) { + return + } + val lineNumber = fileEntry.getLineNumber(offset) + 1 + assert(lineNumber > 0) + if (lastLineNumber == lineNumber) { + return + } + lastLineNumber = lineNumber + mv.visitLineNumber(lineNumber, markNewLabel()) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index 560d0ea1465..2e3380c5821 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -16,10 +16,12 @@ package org.jetbrains.kotlin.backend.jvm.codegen +import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.OwnerKind -import org.jetbrains.kotlin.codegen.SourceInfo import org.jetbrains.kotlin.codegen.inline.* +import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor @@ -31,9 +33,12 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature -import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.AnnotationVisitor +import org.jetbrains.org.objectweb.asm.ClassVisitor +import org.jetbrains.org.objectweb.asm.FieldVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.MethodNode @@ -109,7 +114,8 @@ class IrSourceCompilerForInline( //ExpressionCodegen() var node: MethodNode? = null var maxCalcAdapter: MethodVisitor? = null - val functionCodegen = object : FunctionCodegen(irFunction, codegen.classCodegen) { + val fakeClassCodegen = FakeClassCodegen(irFunction, codegen.classCodegen) + val functionCodegen = object : FunctionCodegen(irFunction, fakeClassCodegen) { override fun createMethod(flags: Int, signature: JvmMethodGenericSignature): MethodVisitor { node = MethodNode( API, @@ -121,11 +127,15 @@ class IrSourceCompilerForInline( return maxCalcAdapter!! } } + + assert(codegen.lastLineNumber >= 0) + lazySourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber) functionCodegen.generate() + lazySourceMapper.callSiteMarker = null maxCalcAdapter!!.visitMaxs(-1, -1) maxCalcAdapter!!.visitEnd() - return SMAPAndMethodNode(node!!, SMAP(/*TODO*/listOf(FileMapping.SKIP))) + return SMAPAndMethodNode(node!!, SMAP(fakeClassCodegen.getOrCreateSourceMapper().resultMappings)) } override fun generateAndInsertFinallyBlocks( @@ -160,4 +170,86 @@ class IrSourceCompilerForInline( override fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) { //TODO } + + private class FakeClassCodegen(irFunction: IrFunction, codegen: ClassCodegen) : + ClassCodegen(irFunction.parent as IrClass, codegen.context) { + + override fun createClassBuilder(): ClassBuilder { + return FakeBuilder + } + + companion object { + val FakeBuilder = object : ClassBuilder { + override fun newField( + origin: JvmDeclarationOrigin, + access: Int, + name: String, + desc: String, + signature: String?, + value: Any? + ): FieldVisitor { + TODO("not implemented") + } + + override fun newMethod( + origin: JvmDeclarationOrigin, + access: Int, + name: String, + desc: String, + signature: String?, + exceptions: Array? + ): MethodVisitor { + TODO("not implemented") + } + + override fun getSerializationBindings(): JvmSerializationBindings { + TODO("not implemented") + } + + override fun newAnnotation(desc: String, visible: Boolean): AnnotationVisitor { + TODO("not implemented") + } + + override fun done() { + TODO("not implemented") + } + + override fun getVisitor(): ClassVisitor { + TODO("not implemented") + } + + override fun defineClass( + origin: PsiElement?, + version: Int, + access: Int, + name: String, + signature: String?, + superName: String, + interfaces: Array + ) { + TODO("not implemented") + } + + override fun visitSource(name: String, debug: String?) { + TODO("not implemented") + } + + override fun visitOuterClass(owner: String, name: String?, desc: String?) { + TODO("not implemented") + } + + override fun visitInnerClass(name: String, outerName: String?, innerName: String?, access: Int) { + TODO("not implemented") + } + + override fun getThisName(): String { + TODO("not implemented") + } + + override fun addSMAP(mapping: FileMapping?) { + TODO("not implemented") + } + } + } + } } \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index 1f101b91e24..65e3236f23a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -6,12 +6,15 @@ package org.jetbrains.kotlin.backend.jvm.codegen import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.codegen.FrameMapBase +import org.jetbrains.kotlin.codegen.SourceInfo +import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrSymbol -import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.ir.util.isAnnotationClass +import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.org.objectweb.asm.Type @@ -41,3 +44,19 @@ internal val IrDeclaration.fileParent: IrFile internal val DeclarationDescriptorWithSource.psiElement: PsiElement? get() = (source as? PsiSourceElement)?.psi + +fun JvmBackendContext.getSourceMapper(declaration: IrClass): DefaultSourceMapper { + val sourceManager = this.psiSourceManager + val fileEntry = sourceManager.getFileEntry(declaration.fileParent) + // NOTE: apparently inliner requires the source range to cover the + // whole file the class is declared in rather than the class only. + // TODO: revise + val endLineNumber = fileEntry.getSourceRangeInfo(0, fileEntry.maxOffset).endLineNumber + return DefaultSourceMapper( + SourceInfo.createInfoForIr( + endLineNumber + 1, + this.state.typeMapper.mapType(declaration.descriptor).internalName, + declaration.descriptor.psiElement!!.containingFile.name + ) + ) +} diff --git a/compiler/testData/codegen/boxInline/complexStack/asCheck.kt b/compiler/testData/codegen/boxInline/complexStack/asCheck.kt index fb841e9a0d9..7612ca6abd5 100644 --- a/compiler/testData/codegen/boxInline/complexStack/asCheck.kt +++ b/compiler/testData/codegen/boxInline/complexStack/asCheck.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnToCatchBlock.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnToCatchBlock.kt index d289f00b39f..a62515523e3 100644 --- a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnToCatchBlock.kt +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnToCatchBlock.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // MODULE: lib // FILE: lib.kt diff --git a/compiler/testData/lineNumber/custom/functionCallWithDefault.kt b/compiler/testData/lineNumber/custom/functionCallWithDefault.kt index e7e155b002a..f1a99034a0c 100644 --- a/compiler/testData/lineNumber/custom/functionCallWithDefault.kt +++ b/compiler/testData/lineNumber/custom/functionCallWithDefault.kt @@ -8,5 +8,5 @@ fun foo(i: Int = 1) { inline fun bar(i: Int = 1) { } - +// IGNORE_BACKEND: JVM_IR // 2 3 13 14 4 7 6 10 9 15 \ No newline at end of file diff --git a/compiler/testData/lineNumber/custom/inTheEndOfLambdaArgumentOfInlineCall.kt b/compiler/testData/lineNumber/custom/inTheEndOfLambdaArgumentOfInlineCall.kt index 429c2b0484b..1aece9b9bc3 100644 --- a/compiler/testData/lineNumber/custom/inTheEndOfLambdaArgumentOfInlineCall.kt +++ b/compiler/testData/lineNumber/custom/inTheEndOfLambdaArgumentOfInlineCall.kt @@ -15,5 +15,5 @@ inline fun baz() { } fun nop() {} - +// IGNORE_BACKEND: JVM_IR // 2 20 21 3 4 25 26 5 27 6 9 10 11 14 15 17 \ No newline at end of file diff --git a/compiler/testData/lineNumber/if.kt b/compiler/testData/lineNumber/if.kt index ffa49a338fd..67105f6fb7f 100644 --- a/compiler/testData/lineNumber/if.kt +++ b/compiler/testData/lineNumber/if.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR fun foo() { if (test.lineNumber() > 0) { test.lineNumber() diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLineNumberTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLineNumberTest.kt index b46ffd3bfca..eef08db4788 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLineNumberTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLineNumberTest.kt @@ -20,11 +20,11 @@ import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase -import org.jetbrains.kotlin.utils.rethrow import org.jetbrains.org.objectweb.asm.* import java.io.File import java.util.* import java.util.regex.Pattern +import kotlin.collections.ArrayList abstract class AbstractLineNumberTest : CodegenTestCase() { @@ -41,10 +41,7 @@ abstract class AbstractLineNumberTest : CodegenTestCase() { try { if (isCustomTest) { - val actualLineNumbers = extractActualLineNumbersFromBytecode(classFileFactory, false) - val text = psiFile.text - val newFileText = text.substringBefore("// ") + getActualLineNumbersAsString(actualLineNumbers) - KotlinTestUtils.assertEqualsToFile(wholeFile, newFileText) + compareCustom(psiFile, wholeFile) } else { val expectedLineNumbers = extractSelectedLineNumbersFromSource(psiFile) val actualLineNumbers = extractActualLineNumbersFromBytecode(classFileFactory, true) @@ -57,8 +54,108 @@ abstract class AbstractLineNumberTest : CodegenTestCase() { } } + protected open fun compareCustom(psiFile: KtFile, wholeFile: File) { + val actualLineNumbers = extractActualLineNumbersFromBytecode(classFileFactory, false) + val text = psiFile.text + val newFileText = text.substring(0 until Regex("// \\d+").find(text)!!.range.first) + + getActualLineNumbersAsString(actualLineNumbers) + KotlinTestUtils.assertEqualsToFile(wholeFile, newFileText) + } + + protected fun extractActualLineNumbersFromBytecode(factory: ClassFileFactory, testFunInvoke: Boolean) = + factory.getClassFiles().flatMap { outputFile -> + val cr = ClassReader(outputFile.asByteArray()) + if (testFunInvoke) readTestFunLineNumbers(cr) else readAllLineNumbers(cr) + } + + protected open fun readTestFunLineNumbers(cr: ClassReader): List { + val labels = arrayListOf