| /* | |
| * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license | |
| * that can be found in the LICENSE file. | |
| */ | |
| package codegen.kclass.kclass0 | |
| import kotlin.test.* | |
| import kotlin.coroutines.* | |
| import kotlin.reflect.KClass | |
| fun box(): String { | |
| main(emptyArray<String>()) | |
| return "OK" | |
| } | |
| fun main(args: Array<String>) { | |
| checkBasics() | |
| checkLocalClasses(args) | |
| checkAnonymousObjects(args) | |
| checkAnonymousObjectsAssignedToProperty(args) | |
| checkFunctionReferences() | |
| checkInterfaces() | |
| checkEtc() | |
| } | |
| private fun checkBasics() { | |
| checkClass( | |
| clazz = Any::class, | |
| expectedQualifiedName = "kotlin.Any", | |
| expectedSimpleName = "Any", | |
| expectedToStringName = "class kotlin.Any", | |
| expectedInstance = Any(), | |
| expectedNotInstance = null | |
| ) | |
| checkClass( | |
| clazz = Int::class, | |
| expectedQualifiedName = "kotlin.Int", | |
| expectedSimpleName = "Int", | |
| expectedToStringName = "class kotlin.Int", | |
| expectedInstance = 42, | |
| expectedNotInstance = "17" | |
| ) | |
| checkClass( | |
| clazz = String::class, | |
| expectedQualifiedName = "kotlin.String", | |
| expectedSimpleName = "String", | |
| expectedToStringName = "class kotlin.String", | |
| expectedInstance = "17", | |
| expectedNotInstance = 42 | |
| ) | |
| checkClass( | |
| clazz = TopLevel::class, | |
| expectedQualifiedName = "codegen.kclass.kclass0.TopLevel", | |
| expectedSimpleName = "TopLevel", | |
| expectedToStringName = "class codegen.kclass.kclass0.TopLevel", | |
| expectedInstance = TopLevel(), | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = TopLevel.Nested::class, | |
| expectedQualifiedName = "codegen.kclass.kclass0.TopLevel.Nested", | |
| expectedSimpleName = "Nested", | |
| expectedToStringName = "class codegen.kclass.kclass0.TopLevel.Nested", | |
| expectedInstance = TopLevel.Nested(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| private fun checkLocalClasses(args: Array<String>) { | |
| // Local class. | |
| class Local0 { | |
| val captured = args | |
| inner class Inner | |
| } | |
| checkClass( | |
| clazz = Local0::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Local0", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$Local0", | |
| expectedInstance = Local0(), | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = Local0.Inner::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$Local0\$Inner", | |
| expectedInstance = Local0().Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| // Local class inside of lambda. | |
| ;{ | |
| class Local { | |
| val captured = args | |
| inner class Inner | |
| } | |
| checkClass( | |
| clazz = Local::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Local", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$1\$invoke\$Local", | |
| expectedInstance = Local(), | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = Local.Inner::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$1\$invoke\$Local\$Inner", | |
| expectedInstance = Local().Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| }.invoke() | |
| // Local class inside of non-inlined lambda. | |
| runNonInlining { | |
| class Local { | |
| val captured = args | |
| inner class Inner | |
| } | |
| checkClass( | |
| clazz = Local::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Local", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$2\$invoke\$Local", | |
| expectedInstance = Local(), | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = Local.Inner::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$2\$invoke\$Local\$Inner", | |
| expectedInstance = Local().Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| // Local class inside of inlined lambda. | |
| run { | |
| class Local { | |
| val captured = args | |
| inner class Inner | |
| } | |
| checkClass( | |
| clazz = Local::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Local", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$Local", | |
| expectedInstance = Local(), | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = Local.Inner::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$Local\$Inner", | |
| expectedInstance = Local().Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| // Local class inside of suspend lambda. | |
| suspend { | |
| class Local { | |
| val captured = args | |
| inner class Inner | |
| } | |
| checkClass( | |
| clazz = Local::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Local", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$3\$invoke\$Local", | |
| expectedInstance = Local(), | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = Local.Inner::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$3\$invoke\$Local\$Inner", | |
| expectedInstance = Local().Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| }.runCoroutine() | |
| // Local class inside of suspend function. | |
| suspend fun suspendFunWithLocalClass() { | |
| class Local { | |
| val captured = args | |
| inner class Inner | |
| } | |
| checkClass( | |
| clazz = Local::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Local", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$suspendFunWithLocalClass\$Local", | |
| expectedInstance = Local(), | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = Local.Inner::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkLocalClasses\$suspendFunWithLocalClass\$Local\$Inner", | |
| expectedInstance = Local().Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| ::suspendFunWithLocalClass.runCoroutine() | |
| } | |
| private fun checkAnonymousObjects(args: Array<String>) { | |
| // Anonymous object. | |
| with(object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| }) { | |
| checkClass( | |
| clazz = this::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$1", | |
| expectedInstance = this, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = this.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$1\$Inner", | |
| expectedInstance = this.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| // Anonymous object inside of lambda. | |
| ;{ | |
| // $2 goes for this lambda itself. | |
| with(object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| }) { | |
| checkClass( | |
| clazz = this::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$2\$invoke\$1", | |
| expectedInstance = this, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = this.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$2\$invoke\$1\$Inner", | |
| expectedInstance = this.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| }.invoke() | |
| // Anonymous object inside of non-inlined lambda. | |
| runNonInlining { | |
| with(object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| }) { | |
| checkClass( | |
| clazz = this::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$3\$invoke\$1", | |
| expectedInstance = this, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = this.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$3\$invoke\$1\$Inner", | |
| expectedInstance = this.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| } | |
| // Anonymous object inside of inlined lambda. | |
| run { | |
| with(object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| }) { | |
| checkClass( | |
| clazz = this::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$4", | |
| expectedInstance = this, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = this.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$4\$Inner", | |
| expectedInstance = this.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| } | |
| // Anonymous object inside of suspend lambda. | |
| suspend { | |
| with(object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| }) { | |
| checkClass( | |
| clazz = this::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$5\$invoke\$2", | |
| expectedInstance = this, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = this.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$5\$invoke\$2\$Inner", | |
| expectedInstance = this.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| }.runCoroutine() | |
| // Anonymous object inside of suspend function. | |
| suspend fun suspendFunWithAnonymousObject() { | |
| // $1 goes for lambda created in `::suspendFunWithAnonymousObject.runCoroutine()` call. | |
| with(object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| }) { | |
| checkClass( | |
| clazz = this::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$suspendFunWithAnonymousObject\$2", | |
| expectedInstance = this, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = this.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjects\$suspendFunWithAnonymousObject\$2\$Inner", | |
| expectedInstance = this.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| } | |
| ::suspendFunWithAnonymousObject.runCoroutine() | |
| } | |
| private fun checkAnonymousObjectsAssignedToProperty(args: Array<String>) { | |
| // Anonymous object. | |
| val obj = object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| } | |
| checkClass( | |
| clazz = obj::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$obj\$1", | |
| expectedInstance = obj, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = obj.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$obj\$1\$Inner", | |
| expectedInstance = obj.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| // Anonymous object inside of lambda. | |
| ;{ | |
| val obj = object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| } | |
| checkClass( | |
| clazz = obj::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$1\$invoke\$obj\$1", | |
| expectedInstance = obj, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = obj.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$1\$invoke\$obj\$1\$Inner", | |
| expectedInstance = obj.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| }.invoke() | |
| // Anonymous object inside of non-inlined lambda. | |
| runNonInlining { | |
| val obj = object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| } | |
| checkClass( | |
| clazz = obj::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$2\$invoke\$obj\$1", | |
| expectedInstance = obj, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = obj.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$2\$invoke\$obj\$1\$Inner", | |
| expectedInstance = obj.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| // Anonymous object inside of inlined lambda. | |
| run { | |
| val obj = object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| } | |
| checkClass( | |
| clazz = obj::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$3", | |
| expectedInstance = obj, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = obj.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$3\$Inner", | |
| expectedInstance = obj.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| // Anonymous object inside of suspend lambda. | |
| suspend { | |
| val obj = object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| } | |
| checkClass( | |
| clazz = obj::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$4\$invoke\$obj\$1", | |
| expectedInstance = obj, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = obj.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$4\$invoke\$obj\$1\$Inner", | |
| expectedInstance = obj.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| }.runCoroutine() | |
| // Anonymous object inside of suspend function. | |
| suspend fun suspendFunWithAnonymousObject() { | |
| // $1 goes for lambda created in `::suspendFunWithAnonymousObject.runCoroutine()` call. | |
| val obj = object : Any() { | |
| val captured = args | |
| inner class Inner | |
| val innerKClass = Inner::class | |
| } | |
| checkClass( | |
| clazz = obj::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$suspendFunWithAnonymousObject\$obj\$1", | |
| expectedInstance = obj, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = obj.innerKClass, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = "Inner", | |
| expectedToStringName = "class codegen.kclass.kclass0.checkAnonymousObjectsAssignedToProperty\$suspendFunWithAnonymousObject\$obj\$1\$Inner", | |
| expectedInstance = obj.Inner(), | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| ::suspendFunWithAnonymousObject.runCoroutine() | |
| } | |
| private fun checkFunctionReferences() { | |
| // TODO add tests for lambdas and anonymous functions, see KT-47194 | |
| fun foo() = Unit | |
| val ref = ::foo | |
| checkClass( | |
| clazz = ref::class, | |
| expectedQualifiedName = null, | |
| expectedSimpleName = null, | |
| expectedToStringName = "class codegen.kclass.kclass0.checkFunctionReferences\$ref\$\$FUNCTION_REFERENCE_FOR\$foo\$3", | |
| expectedInstance = ref, | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| private fun checkInterfaces() { | |
| checkClass( | |
| clazz = Comparable::class, | |
| expectedQualifiedName = "kotlin.Comparable", | |
| expectedSimpleName = "Comparable", | |
| expectedToStringName = "class kotlin.Comparable", | |
| expectedInstance = 42, | |
| expectedNotInstance = Any() | |
| ) | |
| checkClass( | |
| clazz = Interface::class, | |
| expectedQualifiedName = "codegen.kclass.kclass0.Interface", | |
| expectedSimpleName = "Interface", | |
| expectedToStringName = "class codegen.kclass.kclass0.Interface", | |
| expectedInstance = object : Interface {}, | |
| expectedNotInstance = Any() | |
| ) | |
| } | |
| private fun checkEtc() { | |
| checkInstanceClass(Any(), Any::class) | |
| checkInstanceClass(42, Int::class) | |
| assertEquals(42::class, Int::class) | |
| class Local | |
| checkReifiedClass<Int>(Int::class) | |
| checkReifiedClass<Int?>(Int::class) | |
| checkReifiedClass2<Int>(Int::class) | |
| checkReifiedClass2<Int?>(Int::class) | |
| checkReifiedClass<Any>(Any::class) | |
| checkReifiedClass2<Any>(Any::class) | |
| checkReifiedClass2<Any?>(Any::class) | |
| checkReifiedClass<Local>(Local::class) | |
| checkReifiedClass2<Local>(Local::class) | |
| checkReifiedClass<TopLevel>(TopLevel::class) | |
| checkReifiedClass2<TopLevel>(TopLevel::class) | |
| } | |
| class TopLevel { | |
| class Nested | |
| } | |
| interface Interface | |
| private fun checkClass( | |
| clazz: KClass<*>, | |
| expectedQualifiedName: String?, expectedSimpleName: String?, expectedToStringName: String, | |
| expectedInstance: Any, expectedNotInstance: Any? | |
| ) { | |
| assertEquals(expectedQualifiedName, clazz.qualifiedName) | |
| assertEquals(expectedSimpleName, clazz.simpleName) | |
| assertEquals(expectedToStringName, clazz.toString()) | |
| assertTrue(clazz.isInstance(expectedInstance)) | |
| if (expectedNotInstance != null) assertTrue(!clazz.isInstance(expectedNotInstance)) | |
| } | |
| private fun checkInstanceClass(instance: Any, clazz: KClass<*>) { | |
| assertEquals(clazz, instance::class) | |
| } | |
| private inline fun <reified T> checkReifiedClass(expectedClass: KClass<*>) { | |
| assertEquals(expectedClass, T::class) | |
| } | |
| private inline fun <reified T> checkReifiedClass2(expectedClass: KClass<*>) { | |
| checkReifiedClass<T>(expectedClass) | |
| checkReifiedClass<T?>(expectedClass) | |
| } | |
| // Like `run` but without inlining. | |
| private fun runNonInlining(block: () -> Unit) = block() | |
| private fun <T> (suspend () -> T).runCoroutine() = startCoroutine(Continuation(EmptyCoroutineContext) { it.getOrThrow() }) |