/* * Copyright 2010-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.kotlin.codegen import junit.framework.TestCase import org.jetbrains.asm4.ClassReader import org.jetbrains.asm4.ClassVisitor import org.jetbrains.asm4.MethodVisitor import org.jetbrains.asm4.Opcodes import org.jetbrains.kotlin.test.ConfigurationKind import java.util.* class MethodOrderTest: CodegenTestCase() { fun testDelegatedMethod() { doTest( """ interface Trait { fun f0() fun f4() fun f3() fun f2() fun f1() fun f5() } val delegate: Trait = throw Error() val obj = object : Trait by delegate { override fun f3() { } } """, "\$obj$1", listOf("f3()V", "()V", "f0()V", "f1()V", "f2()V", "f4()V", "f5()V") ) } fun testLambdaClosureOrdering() { doTest( """ class Klass { fun Any.f(a: String, b: Int, c: Double, d: Any, e: Long) { { a + b + c + d + e + this@f + this@Klass }() } } """, "\$f$1", listOf("invoke()Ljava/lang/Object;", "invoke()Ljava/lang/String;", "(LKlass;Ljava/lang/Object;Ljava/lang/String;IDLjava/lang/Object;J)V") ) } fun testAnonymousObjectClosureOrdering() { doTest( """ class Klass { fun Any.f(a: String, b: Int, c: Double, d: Any, e: Long) { object : Runnable { override fun run() { a + b + c + d + e + this@f + this@Klass } }.run() } } """, "\$f$1", listOf("run()V", "(LKlass;Ljava/lang/Object;Ljava/lang/String;IDLjava/lang/Object;J)V") ) } fun testMemberAccessor() { doTest( """ class Outer(private val a: Int, private var b: String) { private fun c() { } inner class Inner() { init { b = b + a c() } } } """, "Outer", listOf( "c()V", "(ILjava/lang/String;)V", "access\$getB\$p(LOuter;)Ljava/lang/String;", "access\$setB\$p(LOuter;Ljava/lang/String;)V", "access\$getA\$p(LOuter;)I", "access\$c(LOuter;)V" ) ) } private fun doTest(sourceText: String, classSuffix: String, expectedOrder: List) { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY) myFiles = CodegenTestFiles.create("file.kt", sourceText, myEnvironment!!.project) val classFileForObject = generateClassesInFile().asList().first { it.relativePath.endsWith("$classSuffix.class") } val classReader = ClassReader(classFileForObject.asByteArray()) val methodNames = ArrayList() classReader.accept(object : ClassVisitor(Opcodes.ASM4) { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { methodNames.add(name + desc) return null } }, ClassReader.SKIP_CODE and ClassReader.SKIP_DEBUG and ClassReader.SKIP_FRAMES) TestCase.assertEquals(expectedOrder, methodNames) } }