Move everything under kotlin-native folder

I was forced to manually do update the following files, because otherwise
they would be ignored according .gitignore settings. Probably they
should be deleted from repo.

Interop/.idea/compiler.xml
Interop/.idea/gradle.xml
Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_3.xml
Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_3.xml
Interop/.idea/modules.xml
Interop/.idea/modules/Indexer/Indexer.iml
Interop/.idea/modules/Runtime/Runtime.iml
Interop/.idea/modules/StubGenerator/StubGenerator.iml
backend.native/backend.native.iml
backend.native/bc.frontend/bc.frontend.iml
backend.native/cli.bc/cli.bc.iml
backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt
backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt
backend.native/tests/link/lib/foo.kt
backend.native/tests/link/lib/foo2.kt
backend.native/tests/teamcity-test.property
This commit is contained in:
Stanislav Erokhin
2020-10-27 21:00:28 +03:00
parent 91e4162dad
commit f624800b84
2830 changed files with 0 additions and 0 deletions
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- AUTO-GENERATED FILE. DO NOT MODIFY. -->
<!-- This file was automatically generated by the LocoLaser tool. -->
<!-- It should not be modified by hand. -->
<plist version="1.0">
<dict>
<key>screen_main_plural_string</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@value@</string>
<key>value</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>other</key>
<string>Plural: %d apples</string>
<key>one</key>
<string>Plural: one apple</string>
<key>zero</key>
<string>Plural: no apples</string>
</dict>
</dict>
</dict>
</plist>
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2019 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.
*/
import platform.Foundation.*
import platform.objc.*
import kotlin.test.*
import kotlinx.cinterop.*
import platform.posix.*
import kotlin.system.exitProcess
fun exc_handler(x: Any?) : Unit {
println("Uncaught exception handler")
println(x.toString())
exitProcess(0)
}
fun main() {
// This does not work anymore, as NSException propagated as ForeignException
// so we got `Uncaught Kotlin exception` instead. Use normal try/catch.
objc_setUncaughtExceptionHandler(staticCFunction(::exc_handler))
try {
println(NSJSONSerialization())
} catch (e: Exception) { // ForeignException expected
println(e)
}
}
@@ -0,0 +1,3 @@
language = Objective-C
headerFilter = **/objc_wrap.h
linkerOpts = -lobjcexception
@@ -0,0 +1,47 @@
/*
* Test different behavior depending on foreignExceptionMode option
*/
import kotlin.test.*
import objcExceptionMode.*
import kotlinx.cinterop.*
import platform.objc.*
import kotlin.system.exitProcess
@Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER")
@Test fun testKT35056() {
val name = "Some native exception"
val reason = "Illegal value"
var finallyBlockTest = "FAILED"
var catchBlockTest = "FAILED"
try {
raiseExc(name, reason)
assertNotEquals("FAILED", catchBlockTest) // shall not get here anyway
} catch (e: ForeignException) {
val ret = logExc(e.nativeException) // return NSException name
assertEquals(name, ret)
assertEquals("$name:: $reason", e.message)
println("OK: ForeignException")
catchBlockTest = "PASSED"
} finally {
finallyBlockTest = "PASSED"
}
assertEquals("PASSED", catchBlockTest)
assertEquals("PASSED", finallyBlockTest)
}
@Suppress("UNUSED_PARAMETER")
fun abnormal_handler(x: Any?) : Unit {
println("OK: Ends with uncaught exception handler")
exitProcess(0)
}
fun main() {
// Depending on the `foreignxceptionMode` option (def file or cinterop cli) this test should ends
// normally with `ForeignException` handled or abnormally with `abnormal_handler`.
// Test shall validate output (golden value) from `abnormal_handler`.
objc_setUncaughtExceptionHandler(staticCFunction(::abnormal_handler))
testKT35056()
}
@@ -0,0 +1,4 @@
language = Objective-C
headerFilter = **/objc_wrap.h
linkerOpts = -lobjcexception
foreignExceptionMode = objc-wrap
@@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
void raiseExc(id name, id reason);
id logExc(id exception);
@interface Foo : NSObject
- (void)instanceMethodThrow:(id)name reason:(id)reason;
+ (void)classMethodThrow:(id)name reason:(id)reason;
@end
@@ -0,0 +1,53 @@
/*
* Test different types of callable with foreignExceptionMode=objc-wrap
*/
import kotlin.test.*
//import objcTests.*
import objc_wrap.*
import kotlinx.cinterop.*
fun testInner(name: String, reason: String) {
var finallyBlockTest = "FAILED"
var catchBlockTest = "NOT EXPECTED"
try {
raiseExc(name, reason)
} catch (e: RuntimeException) {
catchBlockTest = "This shouldn't happen"
} finally {
finallyBlockTest = "PASSED"
}
assertEquals("NOT EXPECTED", catchBlockTest)
assertEquals("PASSED", finallyBlockTest)
}
typealias CallMe = (String, String) -> Unit
@Test fun testExceptionWrap(raise: CallMe) {
val name = "Some native exception"
val reason = "Illegal value"
var finallyBlockTest = "FAILED"
var catchBlockTest = "FAILED"
try {
raise(name, reason)
} catch (e: ForeignException) {
val ret = logExc(e.nativeException) // return NSException name
assertEquals(name, ret)
assertEquals("$name:: $reason", e.message)
catchBlockTest = "PASSED"
} finally {
finallyBlockTest = "PASSED"
}
assertEquals("PASSED", catchBlockTest)
assertEquals("PASSED", finallyBlockTest)
}
class Bar() : Foo()
fun main() {
testExceptionWrap(::raiseExc) // simple
testExceptionWrap(::testInner) // nested try block
testExceptionWrap(Foo::classMethodThrow) // class method
testExceptionWrap(Foo()::instanceMethodThrow) // instance method
testExceptionWrap(Bar()::instanceMethodThrow) // fake override
}
@@ -0,0 +1,21 @@
#include "objc_wrap.h"
#import <Foundation/Foundation.h>
void raiseExc(id name, id reason) {
[NSException raise:name format:@"%@", reason];
}
id logExc(id exc) {
assert([exc isKindOfClass:[NSException class]]);
return ((NSException*)exc).name;
}
@implementation Foo : NSObject
- (void) instanceMethodThrow:(id)name reason:(id)reason {
raiseExc(name, reason);
}
+ (void) classMethodThrow:(id)name reason:(id)reason {
raiseExc(name, reason);
}
@end
@@ -0,0 +1,30 @@
import kotlin.native.concurrent.*
import kotlin.test.*
import platform.Foundation.*
import platform.darwin.NSObject
fun Worker.runInWorker(block: () -> Unit) {
this.execute(TransferMode.SAFE, { block.freeze() }) {
it()
}.result
}
private class NSObjectImpl : NSObject() {
var x = 111
}
// Also see counterpart in interop/objc/tests/sharing.kt
fun main() = withWorker {
val obj = NSObjectImpl()
val array: NSArray = NSMutableArray().apply {
addObject(obj)
}
assertFalse(obj.isFrozen)
println("Before")
runInWorker {
array.objectAtIndex(0)
}
println("After")
}
@@ -0,0 +1,28 @@
import kotlin.native.concurrent.*
import kotlinx.cinterop.autoreleasepool
import objclib.*
fun main() {
autoreleasepool {
run()
}
}
private class NSObjectImpl : NSObject() {
var x = 111
}
fun run() = withWorker {
val obj = NSObjectImpl()
setObject(obj)
println("Before")
val isAlive = try {
execute(TransferMode.SAFE, {}) {
isObjectAliveShouldCrash()
}.result
} catch (e: Throwable) {
false
}
println("After $isAlive")
}
@@ -0,0 +1,2 @@
language = Objective-C
headerFilter = **/objclib.h
@@ -0,0 +1,13 @@
#import <objc/NSObject.h>
static NSObject* __weak globalObject = nil;
void setObject(NSObject* obj) {
globalObject = obj;
}
// Make sure this function persists, because the test expects to find this function in the stack trace.
__attribute__((noinline))
bool isObjectAliveShouldCrash() {
return globalObject != nil;
}
@@ -0,0 +1 @@
#define ANSWER 42
@@ -0,0 +1,6 @@
import module_library.*
fun main() {
println("OK")
println(ANSWER)
}
@@ -0,0 +1,2 @@
language = Objective-C
modules = module_library
@@ -0,0 +1,6 @@
module module_library {
umbrella header "module_library_umbrella.h"
export *
module * { export * }
}
@@ -0,0 +1 @@
#import <foo.h>
@@ -0,0 +1,58 @@
import messaging.*
import kotlinx.cinterop.*
import kotlin.test.*
fun main(args: Array<String>) {
autoreleasepool {
primitives()
aggregates()
}
}
private fun primitives() {
assertEquals(3.14f, PrimitiveTestSubject.floatFn())
assertEquals(3.14, PrimitiveTestSubject.doubleFn())
assertEquals(42, PrimitiveTestSubject.intFn())
assertEquals(vectorOf(2f, 4f, 5f, 8f), PrimitiveTestSubject.simdFn())
}
private fun aggregates() {
AggregateTestSubject.singleFloatFn().useContents {
assertEquals(3.14f, f)
}
AggregateTestSubject.simplePackedFn().useContents {
assertEquals('0'.toByte(), f1)
assertEquals(111, f2)
}
AggregateTestSubject.evenSmallerPackedFn().useContents {
assertEquals('x'.toByte(), x)
assertEquals(169, y)
assertEquals('z'.toByte(), z)
}
AggregateTestSubject.homogeneousBigFn().useContents {
assertEquals(1.0f, f1)
assertEquals(2.0f, f2)
assertEquals(3.0f, f3)
assertEquals(4.0f, f4)
assertEquals(5.0f, f5)
assertEquals(6.0f, f6)
assertEquals(7.0f, f7)
assertEquals(8.0f, f8)
}
AggregateTestSubject.homogeneousSmallFn().useContents {
assertEquals(1.0f, f1)
assertEquals(2.0f, f2)
assertEquals(3.0f, f3)
assertEquals(4.0f, f4)
}
AggregateTestSubject.simd_quatfFn().useContents {
assertEquals(vectorOf(1f, 4f, 9f, 25f), vector)
}
AggregateTestSubject.geterogeneousSmallFn().useContents {
assertEquals(1, s1)
assertEquals(vectorOf(1f, 4f, 9f, 25f), v2)
assertEquals(3f, f3)
assertEquals(4, i4)
}
}
@@ -0,0 +1,3 @@
language = Objective-C
headerFilter = **/messaging.h
linkerOpts = -lobjcmessaging
@@ -0,0 +1,68 @@
#import <objc/NSObject.h>
#include <simd/simd.h>
@interface PrimitiveTestSubject : NSObject
+ (int)intFn;
+ (float)floatFn;
+ (double)doubleFn;
+ (simd_float4)simdFn;
@end;
typedef struct {
float f;
} SingleFloat;
typedef struct __attribute__((packed)) {
char f1;
short f2;
char f3;
char f4;
} SimplePacked;
typedef struct __attribute__((packed)) {
char x;
short y;
char z;
} EvenSmallerPacked;
typedef struct {
float f1;
float f2;
float f3;
float f4;
} HomogeneousSmall;
typedef struct {
float f1;
float f2;
float f3;
float f4;
float f5;
float f6;
float f7;
float f8;
} HomogeneousBig;
// TODO: Add more cases later: SIMD, bitfields.
typedef struct {
short s1;
simd_float4 v2;
float f3;
int i4;
} GeterogeneousSmall;
@interface AggregateTestSubject : NSObject
+ (SingleFloat)singleFloatFn;
+ (SimplePacked)simplePackedFn;
+ (EvenSmallerPacked)evenSmallerPackedFn;
+ (HomogeneousSmall)homogeneousSmallFn;
+ (HomogeneousBig)homogeneousBigFn;
+ (simd_quatf)simd_quatfFn;
+ (GeterogeneousSmall)geterogeneousSmallFn;
@end;
@@ -0,0 +1,81 @@
#import "messaging.h"
@implementation PrimitiveTestSubject
+ (int)intFn {
return 42;
}
+ (float)floatFn {
return 3.14f;
}
+ (double)doubleFn {
return 3.14;
}
+ (simd_float4)simdFn {
simd_float4 v;
v.x = 2;
v.y = 4;
v.z = 5;
v.w = 8;
return v;
}
@end;
@implementation AggregateTestSubject
+ (SingleFloat)singleFloatFn {
SingleFloat s;
s.f = 3.14f;
return s;
}
+ (SimplePacked)simplePackedFn {
SimplePacked s;
s.f1 = '0';
s.f2 = 111;
return s;
}
+ (EvenSmallerPacked)evenSmallerPackedFn {
EvenSmallerPacked s;
s.x = 'x';
s.y = 169;
s.z = 'z';
return s;
}
+ (HomogeneousSmall)homogeneousSmallFn {
HomogeneousSmall s;
s.f1 = 1.0f;
s.f2 = 2.0f;
s.f3 = 3.0f;
s.f4 = 4.0f;
return s;
}
+ (HomogeneousBig)homogeneousBigFn {
HomogeneousBig s;
s.f1 = 1.0f;
s.f2 = 2.0f;
s.f3 = 3.0f;
s.f4 = 4.0f;
s.f5 = 5.0f;
s.f6 = 6.0f;
s.f7 = 7.0f;
s.f8 = 8.0f;
return s;
}
+ (GeterogeneousSmall)geterogeneousSmallFn {
return (GeterogeneousSmall){1, {1, 4, 9, 25}, 3, 4};
}
+ (simd_quatf)simd_quatfFn {
return (simd_quatf){ {1, 4, 9, 25} };
}
@end;
@@ -0,0 +1,5 @@
language = Objective-C
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h Foundation/NSBundle.h
headerFilter = **/smoke.h Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h \
objc/objc.h Foundation/NSBundle.h
linkerOpts = -lobjcsmoke
@@ -0,0 +1,6 @@
language = Objective-C
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h Foundation/NSBundle.h
headerFilter = **/interop/objc/tests/**.h \
Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h \
objc/objc.h Foundation/NSBundle.h
linkerOpts = -lobjctests
@@ -0,0 +1,117 @@
#import <objc/NSObject.h>
#import <CoreFoundation/CoreFoundation.h>
@class Foo;
@protocol Printer;
@protocol Printer;
@protocol Empty
@end;
@protocol Forward;
@class Forward;
void useForward1(Forward * p) {}
void useForward2(id<Forward> p) {}
typedef NSString NSStringTypedef;
@interface Foo : NSObject <Empty>
@property NSStringTypedef* name;
-(void)helloWithPrinter:(id <Printer>)printer;
@end;
@interface Foo (FooExtensions)
-(void)hello;
@end;
@protocol Printer
@required
-(void)print:(const char*)string;
@end;
@protocol MutablePair
@required
@property (readonly) int first;
@property (readonly) int second;
-(void)update:(int)index add:(int)delta;
-(void)update:(int)index sub:(int)delta;
@end;
void replacePairElements(id <MutablePair> pair, int first, int second);
int invoke1(int arg, int (^block)(int)) {
return block(arg);
}
void invoke2(void (^block)(void)) {
block();
}
int (^getSupplier(int x))(void);
Class (^ _Nonnull getClassGetter(NSObject* obj))(void);
extern NSString* globalString;
extern NSObject* globalObject;
int formatStringLength(NSString* format, ...);
#define STRING_MACRO @"String macro"
#define CFSTRING_MACRO CFSTR("CFString macro")
typedef NS_ENUM(int32_t, ForwardDeclaredEnum);
typedef NS_ENUM(int32_t, ForwardDeclaredEnum) {
ZERO, ONE, TWO,
};
@protocol ObjectFactory
@required
-(id)create;
@end;
id createObjectWithFactory(id<ObjectFactory> factory) {
return [factory create];
}
@protocol CustomRetainMethods
@required
-(id)returnRetained:(id)obj __attribute__((ns_returns_retained));
-(void)consume:(id) __attribute__((ns_consumed)) obj;
-(void)consumeSelf __attribute__((ns_consumes_self));
-(void (^)(void))returnRetainedBlock:(void (^)(void))block __attribute__((ns_returns_retained));
@end;
extern BOOL unexpectedDeallocation;
@interface MustNotBeDeallocated : NSObject
@end;
@interface CustomRetainMethodsImpl : MustNotBeDeallocated <CustomRetainMethods>
@end;
static MustNotBeDeallocated* retainedObj;
static void (^retainedBlock)(void);
void useCustomRetainMethods(id<CustomRetainMethods> p) {
MustNotBeDeallocated* obj = [MustNotBeDeallocated new];
retainedObj = obj; // Retain to detect possible over-release.
[p returnRetained:obj];
[p consume:p];
[p consumeSelf];
MustNotBeDeallocated* capturedObj = [MustNotBeDeallocated new];
retainedBlock = ^{ [capturedObj description]; }; // Retain to detect possible over-release.
[p returnRetainedBlock:retainedBlock]();
}
id getPrinterProtocolRaw() {
return @protocol(Printer);
}
Protocol* getPrinterProtocol() {
return @protocol(Printer);
}
@@ -0,0 +1,239 @@
/*
* 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.
*/
import kotlinx.cinterop.*
import objcSmoke.*
import kotlin.native.concurrent.*
import kotlin.native.ref.*
import kotlin.test.*
fun main(args: Array<String>) {
autoreleasepool {
run()
}
}
fun run() {
// TODO: migrate remaining tests to interop/objc/tests/
testTypeOps()
testCustomRetain()
testExportObjCClass()
testLocalizedStrings()
assertEquals(2, ForwardDeclaredEnum.TWO.value)
println(
getSupplier(
invoke1(42) { it * 2 }
)!!()
)
val foo = Foo()
val classGetter = getClassGetter(foo)
invoke2 { println(classGetter()) }
foo.hello()
foo.name = "everybody"
foo.helloWithPrinter(object : NSObject(), PrinterProtocol {
override fun print(string: CPointer<ByteVar>?) {
println("Kotlin says: " + string?.toKString())
}
})
Bar().hello()
val pair = MutablePairImpl(42, 17)
replacePairElements(pair, 1, 2)
pair.swap()
println("${pair.first}, ${pair.second}")
val defaultPair = MutablePairImpl()
assertEquals(defaultPair.first(), 123)
assertEquals(defaultPair.second(), 321)
// equals and hashCode (virtually):
val map = mapOf(foo to pair, pair to foo)
// equals (directly):
if (!foo.equals(pair)) {
// toString (directly):
println(map[pair].toString() + map[foo].toString() == foo.description() + pair.description())
}
// hashCode (directly):
// hash() returns value of NSUInteger type.
val hash = when (Platform.osFamily) {
// `typedef unsigned int NSInteger` on watchOS.
OsFamily.WATCHOS -> foo.hash().toInt()
// `typedef unsigned long NSUInteger` on iOS, macOS, tvOS.
else -> foo.hash().let { it.toInt() xor (it shr 32).toInt() }
}
if (foo.hashCode() == hash) {
// toString (virtually):
if (Platform.memoryModel == MemoryModel.STRICT)
println(map.keys.map { it.toString() }.min() == foo.description())
else
// TODO: hack until proper cycle collection in maps.
println(true)
}
println(globalString)
autoreleasepool {
globalString = "Another global string"
}
println(globalString)
println(globalObject)
globalObject = object : NSObject() {
override fun description() = "global object"
}
println(globalObject)
globalObject = null // Prevent Kotlin object above from leaking.
println(formatStringLength("%d %d", 42, 17))
println(STRING_MACRO)
println(CFSTRING_MACRO)
// Ensure that overriding method bridge has retain-autorelease sequence:
createObjectWithFactory(object : NSObject(), ObjectFactoryProtocol {
override fun create() = autoreleasepool { NSObject() }
})
}
fun MutablePairProtocol.swap() {
update(0, add = second)
update(1, sub = first)
update(0, add = second)
update(1, sub = second*2)
}
class Bar : Foo() {
override fun helloWithPrinter(printer: PrinterProtocol?) = memScoped {
printer!!.print("Hello from Kotlin".cstr.getPointer(memScope))
}
}
@Suppress("CONFLICTING_OVERLOADS")
class MutablePairImpl(first: Int, second: Int) : NSObject(), MutablePairProtocol {
private var elements = intArrayOf(first, second)
override fun first() = elements.first()
override fun second() = elements.last()
override fun update(index: Int, add: Int) {
elements[index] += add
}
override fun update(index: Int, sub: Int) {
elements[index] -= sub
}
constructor() : this(123, 321)
}
interface Zzz
fun testTypeOps() {
assertTrue(99.asAny() is NSNumber)
assertTrue(null.asAny() is NSNumber?)
assertFalse(null.asAny() is NSNumber)
assertFalse("".asAny() is NSNumber)
assertTrue("bar".asAny() is NSString)
assertTrue(Foo.asAny() is FooMeta)
assertFalse(Foo.asAny() is Zzz)
assertTrue(Foo.asAny() is NSObjectMeta)
assertTrue(Foo.asAny() is NSObject)
assertFalse(Foo.asAny() is Foo)
assertTrue(NSString.asAny() is NSCopyingProtocolMeta)
assertFalse(NSString.asAny() is NSCopyingProtocol)
assertTrue(NSValue.asAny() is NSObjectProtocolMeta)
assertFalse(NSValue.asAny() is NSObjectProtocol) // Must be true, but not implemented properly yet.
assertFalse(Any() is ObjCClass)
assertFalse(Any() is ObjCClassOf<*>)
assertFalse(NSObject().asAny() is ObjCClass)
assertFalse(NSObject().asAny() is ObjCClassOf<*>)
assertTrue(NSObject.asAny() is ObjCClass)
assertTrue(NSObject.asAny() is ObjCClassOf<*>)
assertFalse(Any() is ObjCProtocol)
assertTrue(getPrinterProtocolRaw() is ObjCProtocol)
val printerProtocol = getPrinterProtocol()!!
assertTrue(printerProtocol.asAny() is ObjCProtocol)
assertEquals(3u, ("foo" as NSString).length())
assertEquals(4u, ((1..4).joinToString("") as NSString).length())
assertEquals(2u, (listOf(0, 1) as NSArray).count())
assertEquals(42L, (42 as NSNumber).longLongValue())
assertFails { "bar" as NSNumber }
assertFails { 42 as NSArray }
assertFails { listOf(1) as NSString }
assertFails { NSObject() as Bar }
assertFails { NSObject() as NSValue }
MutablePairImpl(1, 2).asAny() as MutablePairProtocol
assertFails { MutablePairImpl(1, 2).asAny() as Foo }
}
private lateinit var retainedMustNotBeDeallocated: MustNotBeDeallocated
fun testCustomRetain() {
fun test() {
useCustomRetainMethods(object : Foo(), CustomRetainMethodsProtocol {
override fun returnRetained(obj: Any?) = obj
override fun consume(obj: Any?) {}
override fun consumeSelf() {}
override fun returnRetainedBlock(block: (() -> Unit)?) = block
})
CustomRetainMethodsImpl().let {
it.returnRetained(Any())
retainedMustNotBeDeallocated = MustNotBeDeallocated() // Retain to detect possible over-release.
it.consume(retainedMustNotBeDeallocated)
it.consumeSelf()
it.returnRetainedBlock({})!!()
}
}
autoreleasepool {
test()
kotlin.native.internal.GC.collect()
}
assertFalse(unexpectedDeallocation)
}
private const val TestExportObjCClass1Name = "TestExportObjCClass"
@ExportObjCClass(TestExportObjCClass1Name) class TestExportObjCClass1 : NSObject()
@ExportObjCClass class TestExportObjCClass2 : NSObject()
const val TestExportObjCClass34Name = "TestExportObjCClass34"
@ExportObjCClass(TestExportObjCClass34Name) class TestExportObjCClass3 : NSObject()
@ExportObjCClass(TestExportObjCClass34Name) class TestExportObjCClass4 : NSObject()
fun testExportObjCClass() {
assertEquals(TestExportObjCClass1Name, TestExportObjCClass1().objCClassName)
assertEquals("TestExportObjCClass2", TestExportObjCClass2().objCClassName)
assertTrue((TestExportObjCClass3().objCClassName == TestExportObjCClass34Name)
xor (TestExportObjCClass4().objCClassName == TestExportObjCClass34Name))
}
fun testLocalizedStrings() {
val key = "screen_main_plural_string"
val localizedString = NSBundle.mainBundle.localizedStringForKey(key, value = "", table = "Localizable")
val string = NSString.localizedStringWithFormat(localizedString, 5)
assertEquals("Plural: 5 apples", string)
}
private val Any.objCClassName: String
get() = object_getClassName(this)!!.toKString()
fun Any?.asAny(): Any? = this
@@ -0,0 +1,97 @@
#import <stdio.h>
#import <Foundation/NSString.h>
#import "smoke.h"
@interface CPrinter : NSObject <Printer>
-(void)print:(const char*)string;
@end;
@implementation CPrinter
-(void)print:(const char*)string {
printf("%s\n", string);
fflush(stdout);
}
@end;
@implementation Foo
@synthesize name;
-(instancetype)init {
if (self = [super init]) {
self.name = @"World";
}
return self;
}
-(void)helloWithPrinter:(id <Printer>)printer {
NSString* message = [NSString stringWithFormat:@"Hello, %@!", self.name];
[printer print:message.UTF8String];
}
-(void)dealloc {
printf("Deallocated\n");
}
@end;
@implementation Foo (FooExtensions)
-(void)hello {
CPrinter* printer = [[CPrinter alloc] init];
[self helloWithPrinter:printer];
}
@end;
void replacePairElements(id <MutablePair> pair, int first, int second) {
[pair update:0 add:(first - pair.first)];
[pair update:1 sub:(pair.second - second)];
}
int (^getSupplier(int x))(void) {
return ^{
return x;
};
}
Class (^ _Nonnull getClassGetter(NSObject* obj))() {
return ^{ return obj.class; };
}
NSString* globalString = @"Global string";
NSObject* globalObject = nil;
int formatStringLength(NSString* format, ...) {
va_list args;
va_start(args, format);
NSString* result = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
return result.length;
}
BOOL unexpectedDeallocation = NO;
@implementation MustNotBeDeallocated
-(void)dealloc {
unexpectedDeallocation = YES;
}
@end;
static CustomRetainMethodsImpl* retainedCustomRetainMethodsImpl;
@implementation CustomRetainMethodsImpl
-(id)returnRetained:(id)obj __attribute__((ns_returns_retained)) {
return obj;
}
-(void)consume:(id) __attribute__((ns_consumed)) obj {
}
-(void)consumeSelf __attribute__((ns_consumes_self)) {
retainedCustomRetainMethodsImpl = self; // Retain to detect possible over-release.
}
-(void (^)(void))returnRetainedBlock:(void (^)(void))block __attribute__((ns_returns_retained)) {
return block;
}
@end;
@@ -0,0 +1,9 @@
#import <Foundation/NSObject.h>
@protocol KT38234_P1
-(int)foo;
@end;
@interface KT38234_Base : NSObject <KT38234_P1>
-(int)callFoo;
@end;
@@ -0,0 +1,10 @@
import kotlin.test.*
import objcTests.*
class KT38234_Impl : KT38234_P1Protocol, KT38234_Base() {
override fun foo(): Int = 566
}
@Test fun testKT38234() {
assertEquals(566, KT38234_Impl().callFoo())
}
@@ -0,0 +1,10 @@
#include "KT38234_override.h"
@implementation KT38234_Base
-(int)foo {
return 1;
}
-(int)callFoo {
return [self foo];
}
@end;
@@ -0,0 +1,5 @@
#import <Foundation/NSObject.h>
@interface TestAllocNoRetain : NSObject
@property BOOL ok;
@end;
@@ -0,0 +1,27 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testAllocNoRetain() {
// Ensure that calling Kotlin constructor generated for Objective-C initializer doesn't result in
// redundant retain-release sequence for `alloc` result, since it may provoke specific bugs to reproduce, e.g.
// the one found in [[NSOutputStream alloc] initToMemory] sequence where initToMemory deallocates its receiver
// forcibly when replacing it with other object: (to be compiled with ARC enabled)
/*
#import <Foundation/Foundation.h>
void* mem;
NSOutputStream* allocated = nil;
int main() {
allocated = [NSOutputStream alloc];
NSOutputStream* initialized = [allocated initToMemory];
mem = calloc(1, 0x10); // To corrupt the 'allocated' object header.
allocated = nil; // Crashes here in objc_release.
return 0;
}
*/
assertTrue(TestAllocNoRetain().ok)
}
@@ -0,0 +1,14 @@
#import "allocNoRetain.h"
@implementation TestAllocNoRetain
-(instancetype)init {
__weak id weakSelf = self;
self = [TestAllocNoRetain alloc];
if (self = [super init]) {
// Ensure that original self value was deallocated:
self.ok = (weakSelf == nil);
// So it's RC was 1, which means there wasn't redundant retain applied to it.
}
return self;
}
@end;
@@ -0,0 +1,27 @@
#import <Foundation/NSObject.h>
@protocol BlockProvider
@required
-(int (^)(int)) block;
@end;
int callProvidedBlock(id<BlockProvider> blockProvider, int argument) {
return [blockProvider block](argument);
}
@protocol BlockConsumer
@required
-(int)callBlock:(int (^)(int))block argument:(int)argument;
@end;
int callPlusOneBlock(id<BlockConsumer> blockConsumer, int argument) {
return [blockConsumer callBlock:^int(int p) { return p + 1; } argument:argument];
}
@interface Blocks : NSObject
+(BOOL)blockIsNull:(void (^)(void))block;
+(int (^)(int, int, int, int))same:(int (^)(int, int, int, int))block;
@property (class) void (^nullBlock)(void);
@property (class) void (^notNullBlock)(void);
@end;
@@ -0,0 +1,21 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testBlocks() {
assertTrue(Blocks.blockIsNull(null))
assertFalse(Blocks.blockIsNull({}))
assertEquals(null, Blocks.nullBlock)
assertNotEquals(null, Blocks.notNullBlock)
assertEquals(10, Blocks.same({ a, b, c, d -> a + b + c + d })!!(1, 2, 3, 4))
assertEquals(222, callProvidedBlock(object : NSObject(), BlockProviderProtocol {
override fun block(): (Int) -> Int = { it * 2 }
}, 111))
assertEquals(322, callPlusOneBlock(object : NSObject(), BlockConsumerProtocol {
override fun callBlock(block: ((Int) -> Int)?, argument: Int) = block!!(argument)
}, 321))
}
@@ -0,0 +1,20 @@
#import "blocks.h"
@implementation Blocks
+(BOOL)blockIsNull:(void (^)(void))block {
return block == nil;
}
+(int (^)(int, int, int, int))same:(int (^)(int, int, int, int))block {
return block;
}
+(void (^)(void)) nullBlock {
return nil;
}
+(void (^)(void)) notNullBlock {
return ^{};
}
@end;
@@ -0,0 +1,7 @@
#import <Foundation/NSObject.h>
@interface TestCallableReferences : NSObject
@property int value;
- (int)instanceMethod;
+ (int)classMethod:(int)first :(int)second;
@end;
@@ -0,0 +1,28 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testCallableReferences() {
val createTestCallableReferences = ::TestCallableReferences
assertEquals("<init>", createTestCallableReferences.name)
val testCallableReferences: Any = createTestCallableReferences()
assertTrue(testCallableReferences is TestCallableReferences)
val valueRef: kotlin.reflect.KMutableProperty0<Int> = testCallableReferences::value
assertEquals("value", valueRef.name)
assertEquals(0, valueRef())
valueRef.set(42)
assertEquals(42, valueRef())
val classMethodRef = (TestCallableReferences)::classMethod
assertEquals("classMethod", classMethodRef.name)
assertEquals(3, classMethodRef(1, 2))
val instanceMethodRef = TestCallableReferences::instanceMethod
assertEquals("instanceMethod", instanceMethodRef.name)
assertEquals(42, instanceMethodRef(testCallableReferences))
val boundInstanceMethodRef = testCallableReferences::instanceMethod
assertEquals("instanceMethod", boundInstanceMethodRef.name)
assertEquals(42, boundInstanceMethodRef())
}
@@ -0,0 +1,11 @@
#import "callableReferences.h"
@implementation TestCallableReferences
- (int)instanceMethod {
return self.value;
}
+ (int)classMethod:(int)first :(int)second {
return first + second;
}
@end;
@@ -0,0 +1,22 @@
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
@interface TestClashingWithAny1 : NSObject
-(NSString*)toString;
-(NSString*)toString_;
-(int)hashCode;
-(BOOL)equals:(id _Nullable)other;
@end;
@interface TestClashingWithAny2 : NSObject
-(void)toString;
-(void)hashCode;
-(void)equals:(int)p; // May clash.
@end;
@interface TestClashingWithAny3 : NSObject
// Not clashing actually.
-(NSString*)toString:(int)p;
-(int)hashCode:(int)p;
-(BOOL)equals;
@end;
@@ -0,0 +1,27 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testClashingWithAny() {
assertEquals("description", TestClashingWithAny1().toString())
assertEquals("toString", TestClashingWithAny1().toString_())
assertEquals("toString_", TestClashingWithAny1().toString__())
assertEquals(1, TestClashingWithAny1().hashCode())
assertEquals(31, TestClashingWithAny1().hashCode_())
assertFalse(TestClashingWithAny1().equals(TestClashingWithAny1()))
assertTrue(TestClashingWithAny1().equals_(TestClashingWithAny1()))
assertEquals("description", TestClashingWithAny2().toString())
assertEquals(Unit, TestClashingWithAny2().toString_())
assertEquals(2, TestClashingWithAny2().hashCode())
assertEquals(Unit, TestClashingWithAny2().hashCode_())
assertFalse(TestClashingWithAny2().equals(TestClashingWithAny2()))
assertEquals(Unit, TestClashingWithAny2().equals_(42))
assertEquals("description", TestClashingWithAny3().toString())
assertEquals("toString:11", TestClashingWithAny3().toString(11))
assertEquals(3, TestClashingWithAny3().hashCode())
assertEquals(4, TestClashingWithAny3().hashCode(3))
assertFalse(TestClashingWithAny3().equals(TestClashingWithAny3()))
assertTrue(TestClashingWithAny3().equals())
}
@@ -0,0 +1,68 @@
#import "clashingWithAny.h"
@implementation TestClashingWithAny1
-(NSString*)description {
return @"description";
}
-(NSString*)toString {
return @"toString";
}
-(NSString*)toString_ {
return @"toString_";
}
-(NSUInteger)hash {
return 1;
}
-(int)hashCode {
return 31;
}
-(BOOL)equals:(id _Nullable)other {
return YES;
}
@end;
@implementation TestClashingWithAny2
-(NSString*)description {
return @"description";
}
-(void)toString {
}
-(NSUInteger)hash {
return 2;
}
-(void)hashCode {
}
-(void)equals:(int)p {
}
@end;
@implementation TestClashingWithAny3
-(NSString*)description {
return @"description";
}
-(NSString*)toString:(int)p {
return [NSString stringWithFormat:@"%s:%d", "toString", p];
}
-(NSUInteger)hash {
return 3;
}
-(int)hashCode:(int)p {
return p + 1;
}
-(BOOL)equals {
return YES;
}
@end;
@@ -0,0 +1,5 @@
#import <Foundation/NSObject.h>
@interface TestConstructorReturnsNull : NSObject
- (instancetype)init;
@end;
@@ -0,0 +1,9 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testConstructorReturnsNull() {
assertFailsWith<NullPointerException>() {
TestConstructorReturnsNull()
}
}
@@ -0,0 +1,7 @@
#import "constructorReturnsNull.h"
@implementation TestConstructorReturnsNull
- (instancetype)init {
return nil;
}
@end;
@@ -0,0 +1,18 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testConversions() {
testMethodsOfAny(emptyList<Nothing>(), NSArray())
testMethodsOfAny(listOf(1, "foo"), nsArrayOf(1, "foo"))
testMethodsOfAny(42, NSNumber.numberWithInt(42), 17)
testMethodsOfAny(true, NSNumber.numberWithBool(true), false)
}
private fun testMethodsOfAny(kotlinObject: Any, equalNsObject: NSObject, otherObject: Any = Any()) {
assertEquals(kotlinObject.hashCode(), equalNsObject.hashCode())
assertEquals(kotlinObject.toString(), equalNsObject.toString())
assertEquals(kotlinObject, equalNsObject)
assertEquals(equalNsObject, kotlinObject)
assertNotEquals(equalNsObject, otherObject)
}
@@ -0,0 +1,16 @@
#import <Foundation/NSString.h>
@interface CustomString : NSString
- (instancetype)initWithValue:(int)value;
@property int value;
@end;
CustomString* _Nonnull createCustomString(int value) {
return [[CustomString alloc] initWithValue:value];
}
int getCustomStringValue(CustomString* str) {
return str.value;
}
extern BOOL customStringDeallocated;
@@ -0,0 +1,21 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testCustomString() {
assertFalse(customStringDeallocated)
fun test() = autoreleasepool {
val str: String = createCustomString(321)
assertEquals("321", str)
assertEquals("CustomString", str.objCClassName)
assertEquals(321, getCustomStringValue(str))
}
test()
kotlin.native.internal.GC.collect()
assertTrue(customStringDeallocated)
}
private val Any.objCClassName: String
get() = object_getClassName(this)!!.toKString()
@@ -0,0 +1,32 @@
#import "customString.h"
BOOL customStringDeallocated = NO;
@implementation CustomString {
NSString* delegate;
}
- (instancetype)initWithValue:(int)value {
if (self = [super init]) {
self->delegate = @(value).description;
self.value = value;
}
return self;
}
- (unichar)characterAtIndex:(NSUInteger)index {
return [self->delegate characterAtIndex:index];
}
- (NSUInteger)length {
return self->delegate.length;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (void)dealloc {
customStringDeallocated = YES;
}
@end;
@@ -0,0 +1,9 @@
#import <Foundation/NSObject.h>
@protocol ExceptionThrower
-(void)throwException;
@end;
@interface ExceptionThrowerManager : NSObject
+(void)throwExceptionWith:(id<ExceptionThrower>)thrower;
@end;
@@ -0,0 +1,15 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testExceptions() {
assertFailsWith<MyException> {
ExceptionThrowerManager.throwExceptionWith(object : NSObject(), ExceptionThrowerProtocol {
override fun throwException() {
throw MyException()
}
})
}
}
private class MyException : Throwable()
@@ -0,0 +1,7 @@
#import "exceptions.h"
@implementation ExceptionThrowerManager
+(void)throwExceptionWith:(id<ExceptionThrower>)thrower {
[thrower throwException];
}
@end;
@@ -0,0 +1,8 @@
#import <Foundation/NSObject.h>
@interface TestInitWithCustomSelector : NSObject
-(instancetype)initCustom;
@property BOOL custom;
+(instancetype _Nonnull)createCustom;
@end;
@@ -0,0 +1,25 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testInitWithCustomSelector() {
assertFalse(TestInitWithCustomSelector().custom)
assertTrue(TestInitWithCustomSelector(custom = Unit).custom)
val customSubclass: TestInitWithCustomSelector = TestInitWithCustomSelectorSubclass.createCustom()
assertTrue(customSubclass is TestInitWithCustomSelectorSubclass)
assertTrue(customSubclass.custom)
// Test side effect:
var ok = false
assertTrue(TestInitWithCustomSelector(run { ok = true }).custom)
assertTrue(ok)
}
private class TestInitWithCustomSelectorSubclass : TestInitWithCustomSelector {
@OverrideInit constructor(custom: Unit) : super(custom) {
assertSame(Unit, custom)
}
companion object : TestInitWithCustomSelectorMeta()
}
@@ -0,0 +1,23 @@
#import "initWithCustomSelector.h"
@implementation TestInitWithCustomSelector
-(instancetype)initCustom {
if (self = [super init]) {
self.custom = YES;
}
return self;
}
-(instancetype)init {
if (self = [super init]) {
self.custom = NO;
}
return self;
}
+(instancetype)createCustom {
return [[self alloc] initCustom];
}
@end;
@@ -0,0 +1 @@
void kt36766(void (^block)()) {}
@@ -0,0 +1,6 @@
import kotlin.test.*
import objcTests.*
@Test fun testKt36766() {
kt36766(null)
}
@@ -0,0 +1,24 @@
#import <Foundation/NSObject.h>
extern BOOL deallocRetainReleaseDeallocated;
@interface DeallocRetainRelease : NSObject
@end;
extern DeallocRetainRelease* globalDeallocRetainRelease;
@protocol WeakReference
@required
@property (weak) id referent;
@end;
@interface ObjCWeakReference : NSObject <WeakReference>
@property (weak) id referent;
@end;
extern id <WeakReference> weakDeallocLoadWeak;
extern BOOL deallocLoadWeakDeallocated;
@interface DeallocLoadWeak : NSObject
-(void)checkWeak;
@end;
@@ -0,0 +1,118 @@
import kotlin.native.ref.WeakReference
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
// Note: these tests rely on GC assertions: without the fix and the assertions it won't actually crash.
// GC should fire an assertion if it obtains a reference to Kotlin object that is being (or has been) deallocated.
@Test
fun testKT41811() {
// Attempt to make the state predictable:
kotlin.native.internal.GC.collect()
deallocRetainReleaseDeallocated = false
assertFalse(deallocRetainReleaseDeallocated)
createGarbageDeallocRetainRelease()
// Runs [DeallocRetainRelease dealloc]:
kotlin.native.internal.GC.collect()
assertTrue(deallocRetainReleaseDeallocated)
// Might crash due to double-dispose if the dealloc applied addRef/releaseRef to reclaimed Kotlin object:
kotlin.native.internal.GC.collect()
}
private fun createGarbageDeallocRetainRelease() {
autoreleasepool {
object : DeallocRetainRelease() {}
}
}
@Test
fun testKT41811LoadWeak() {
testKT41811LoadWeak(ObjCWeakReference())
}
@Test
fun testKT41811LoadKotlinWeak() {
val kotlinWeak = object : NSObject(), WeakReferenceProtocol {
lateinit var weakReference: WeakReference<Any>
override fun referent(): Any? {
return weakReference.value
}
override fun setReferent(referent: Any?) {
weakReference = WeakReference(referent!!)
}
}
testKT41811LoadWeak(kotlinWeak)
}
private fun testKT41811LoadWeak(weakRef: WeakReferenceProtocol) {
// Attempt to make the state predictable:
kotlin.native.internal.GC.collect()
deallocLoadWeakDeallocated = false
assertFalse(deallocLoadWeakDeallocated)
createGarbageDeallocLoadWeak(weakRef)
// Runs [DeallocLoadWeak dealloc]:
kotlin.native.internal.GC.collect()
assertTrue(deallocLoadWeakDeallocated)
// Might crash due to double-dispose if the dealloc applied addRef/releaseRef to reclaimed Kotlin object:
kotlin.native.internal.GC.collect()
weakDeallocLoadWeak = null
}
private fun createGarbageDeallocLoadWeak(weakRef: WeakReferenceProtocol) {
autoreleasepool {
val obj = object : DeallocLoadWeak() {}
weakDeallocLoadWeak = weakRef.apply { referent = obj }
obj.checkWeak()
assertSame(obj, weakDeallocLoadWeak!!.referent)
}
}
@Test
fun testKT41811WithGlobal() {
// Attempt to make the state predictable:
kotlin.native.internal.GC.collect()
deallocRetainReleaseDeallocated = false
assertFalse(deallocRetainReleaseDeallocated)
autoreleasepool {
{
globalDeallocRetainRelease = object: DeallocRetainRelease() {}
}()
}
assertFalse(deallocRetainReleaseDeallocated)
// Clean up local DeallocRetainRelease on Kotlin side
kotlin.native.internal.GC.collect()
assertFalse(deallocRetainReleaseDeallocated)
// And drop the last reference to DeallocRetainRelease from ObjC global scope.
globalDeallocRetainRelease = null
assertFalse(deallocRetainReleaseDeallocated)
// This will dispose `DeallocRetainRelease` on Kotlin side, which will cause `dealloc`
// on ObjC side, which triggers `retain` and `release` of `self`. If these messages
// were to reach Kotlin side, the `release` would have immediately scheduled the
// second disposal of Kotlin object.
kotlin.native.internal.GC.collect()
assertTrue(deallocRetainReleaseDeallocated)
}
@@ -0,0 +1,39 @@
#import "kt41811.h"
#import "assert.h"
id retainObject = nil;
BOOL deallocRetainReleaseDeallocated = NO;
@implementation DeallocRetainRelease
-(void)dealloc {
retainObject = self;
assert(retainObject == self);
retainObject = nil;
assert(!deallocRetainReleaseDeallocated);
deallocRetainReleaseDeallocated = YES;
}
@end;
DeallocRetainRelease* globalDeallocRetainRelease = nil;
@implementation ObjCWeakReference
@end;
id <WeakReference> weakDeallocLoadWeak = nil;
BOOL deallocLoadWeakDeallocated = NO;
@implementation DeallocLoadWeak
-(void)checkWeak {
assert(weakDeallocLoadWeak != nil);
assert(weakDeallocLoadWeak.referent == self);
}
-(void)dealloc {
assert(weakDeallocLoadWeak != nil);
assert(weakDeallocLoadWeak.referent == nil);
assert(!deallocLoadWeakDeallocated);
deallocLoadWeakDeallocated = YES;
}
@end;
@@ -0,0 +1,11 @@
import kotlin.system.exitProcess
import kotlinx.cinterop.autoreleasepool
import kotlin.native.internal.test.testLauncherEntryPoint
fun main(args: Array<String>) {
autoreleasepool {
val exitCode = testLauncherEntryPoint(args)
// Note: this test runner checks for memory leaks after successful execution, unlike standard one.
if (exitCode != 0) exitProcess(exitCode)
}
}
@@ -0,0 +1,25 @@
#import <Foundation/NSObject.h>
// [KT-36067] cinterop tool fails when there is a structure member named Companion
struct EnumFieldMangleStruct {
enum {Companion, Any} smth;
};
struct EnumFieldMangleStruct enumMangledStruct = { Any };
struct MyStruct {
int Companion; // simple clash
int _Companion;
int $_Companion;
int super;
};
struct MyStruct myStruct = {11, 12, 13, 14};
@protocol Proto
@property int Companion; // clash on implementing
@end;
@interface FooMangled : NSObject<Proto>
//- (void) CompanionS; // mangleSimple does not support this: it may clash after mangling
@end;
@@ -0,0 +1,18 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testMangling() {
assertEquals(11, myStruct.`Companion$`)
assertEquals(12, myStruct._Companion)
assertEquals(13, myStruct.`$_Companion`)
assertEquals(14, myStruct.`super`)
val objc = FooMangled()
objc.`Companion$` = 99
assertEquals(99, objc.Companion())
assertEquals(99, objc.`Companion$`)
enumMangledStruct.smth = Companion
assertEquals(Companion, enumMangledStruct.smth)
}
@@ -0,0 +1,6 @@
#import "mangling.h"
// [KT-36067] mangling
@implementation FooMangled : NSObject
@synthesize Companion;
@end;
@@ -0,0 +1,17 @@
#import <Foundation/NSObject.h>
@interface MultipleInheritanceClashBase : NSObject
@property (nonnull) MultipleInheritanceClashBase* delegate;
@end;
@protocol MultipleInheritanceClash
@optional
@property (nullable) id<MultipleInheritanceClash> delegate;
@end;
@interface MultipleInheritanceClash1 : MultipleInheritanceClashBase <MultipleInheritanceClash>
@end;
@interface MultipleInheritanceClash2 : MultipleInheritanceClashBase <MultipleInheritanceClash>
@property MultipleInheritanceClashBase* delegate;
@end;
@@ -0,0 +1,18 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testMultipleInheritanceClash() {
val clash1 = MultipleInheritanceClash1()
val clash2 = MultipleInheritanceClash2()
clash1.delegate = clash1
assertEquals(clash1, clash1.delegate)
clash1.setDelegate(clash2)
assertEquals(clash2, clash1.delegate())
clash2.delegate = clash1
assertEquals(clash1, clash2.delegate)
clash2.setDelegate(clash2)
assertEquals(clash2, clash2.delegate())
}
@@ -0,0 +1,10 @@
#import "multipleInheritanceClash.h"
@implementation MultipleInheritanceClashBase
@end;
@implementation MultipleInheritanceClash1
@end;
@implementation MultipleInheritanceClash2
@end;
@@ -0,0 +1,8 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testNSOutputStreamToMemoryConstructor() {
val stream: Any = NSOutputStream(toMemory = Unit)
assertTrue(stream is NSOutputStream)
}
@@ -0,0 +1,13 @@
#import <Foundation/NSObject.h>
@class DeallocListener;
@interface DeallocExecutor : NSObject
@property DeallocListener* deallocListener;
@end;
@interface DeallocListener : NSObject
@property (weak) DeallocExecutor* deallocExecutor;
@property BOOL deallocated;
-(BOOL)deallocExecutorIsNil;
@end;
@@ -0,0 +1,50 @@
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
import kotlin.test.*
import objcTests.*
@Test fun testObjCWeakRef() {
val deallocListener = DeallocListener()
assertFalse(deallocListener.deallocated)
// [deallocListener.deallocExecutorIsNil()] calls deallocExecutor getter, which retains the result and either
// puts it to autoreleasepool or releases it immediately (Obj-C ARC optimization). It seems to depend on the platform.
// Wrap the call to autoreleasepool to ensure the object will be released:
autoreleasepool {
testObjCWeakRef0(deallocListener)
}
kotlin.native.internal.GC.collect()
assertTrue(deallocListener.deallocated)
assertTrue(deallocListener.deallocExecutorIsNil())
}
private fun testObjCWeakRef0(deallocListener: DeallocListener) = withWorker {
assertTrue(deallocListener.deallocExecutorIsNil())
val obj = object : DeallocExecutor() {}
deallocListener.deallocExecutor = obj
obj.deallocListener = deallocListener
assertFalse(deallocListener.deallocExecutorIsNil())
// TODO: can't actually test, Obj-C runtime doesn't expect _tryRetain throwing an exception.
// runInWorker {
// assertFailsWith<IncorrectDereferenceException> {
// deallocListener.deallocExecutorIsNil()
// }
// }
obj.freeze()
runInWorker {
// [deallocListener.deallocExecutorIsNil()] calls deallocExecutor getter, which retains [obj] and either
// puts it to autoreleasepool or releases it immediately (Obj-C ARC optimization).
// Wrap the call to autoreleasepool to ensure [obj] will be released:
autoreleasepool {
assertFalse(deallocListener.deallocExecutorIsNil())
}
// Process release of Kotlin reference to [obj] in any case:
kotlin.native.internal.GC.collect()
}
}
@@ -0,0 +1,13 @@
#import "objcWeakRefs.h"
@implementation DeallocExecutor
-(void)dealloc {
self.deallocListener.deallocated = YES;
}
@end;
@implementation DeallocListener
-(BOOL)deallocExecutorIsNil {
return self.deallocExecutor == nil;
}
@end;
@@ -0,0 +1,6 @@
#import <Foundation/NSObject.h>
@interface TestOverrideInit : NSObject
-(instancetype)initWithValue:(int)value NS_DESIGNATED_INITIALIZER;
+(instancetype)createWithValue:(int)value;
@end;
@@ -0,0 +1,22 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testOverrideInit1() {
assertEquals(42, (TestOverrideInitImpl1.createWithValue(42) as TestOverrideInitImpl1).value)
}
private class TestOverrideInitImpl1 @OverrideInit constructor(val value: Int) : TestOverrideInit(value) {
companion object : TestOverrideInitMeta()
}
// See https://youtrack.jetbrains.com/issue/KT-41910
@Test fun testOverrideInitWithDefaultArguments() {
assertEquals(42, (TestOverrideInitImpl2.createWithValue(42) as TestOverrideInitImpl2).value)
assertEquals(123, TestOverrideInitImpl2(123).value)
assertEquals(17, TestOverrideInitImpl2().value)
}
private class TestOverrideInitImpl2 @OverrideInit constructor(val value: Int = 17) : TestOverrideInit(value) {
companion object : TestOverrideInitMeta()
}
@@ -0,0 +1,11 @@
#import "overrideInit.h"
@implementation TestOverrideInit
-(instancetype)initWithValue:(int)value {
return self = [super init];
}
+(instancetype)createWithValue:(int)value {
return [[self alloc] initWithValue:value];
}
@end;
@@ -0,0 +1,31 @@
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
import kotlin.test.*
import objcTests.*
private class NSObjectImpl : NSObject() {
var x = 111
}
// Also see counterpart interop/objc/illegal_sharing.kt
@Test fun testSharing() = withWorker {
val obj = NSObjectImpl()
val array = nsArrayOf(obj)
assertFalse(obj.isFrozen)
obj.x = 222
obj.freeze()
assertTrue(obj.isFrozen)
runInWorker {
val obj1 = array.objectAtIndex(0) as NSObjectImpl
assertFailsWith<InvalidMutabilityException> {
obj1.x = 333
}
}
assertEquals(222, obj.x)
// TODO: test [obj release] etc.
}
@@ -0,0 +1,17 @@
#import <Foundation/NSString.h>
struct CStructWithNSObjects {
id any;
NSString* nsString;
NSString* _Nonnull nonNullString;
NSObject* object;
NSArray* array;
NSMutableArray* mutableArray;
NSSet* set;
NSDictionary* dictionary;
};
@@ -0,0 +1,65 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
private class NSObjectSubClass : NSObject() {
val x = 111
}
@Test
fun testStructWithNSObject() {
memScoped {
val struct = alloc<CStructWithNSObjects>()
struct.any = 5
assertEquals(5, struct.any)
struct.any = null
assertEquals(null, struct.any)
struct.nsString = "hello"
assertEquals("hello", struct.nsString)
struct.nsString = null
assertEquals(null, struct.nsString)
struct.nonNullString = "world"
assertEquals("world", struct.nonNullString)
struct.`object` = NSObjectSubClass()
assertEquals(111, (struct.`object` as NSObjectSubClass).x)
struct.`object` = null
assertEquals(null, struct.`object`)
struct.array = null
assertEquals(null, struct.array)
struct.array = listOf(1, 2, 3)
assertEquals(listOf(1, 2, 3), struct.array)
struct.set = null
assertEquals(null, struct.set)
struct.set = setOf("hello", "world")
assertEquals(setOf("hello", "world"), struct.set)
struct.dictionary = null
assertEquals(null, struct.dictionary)
struct.dictionary = mapOf("k1" to "v1", "k2" to "v2")
assertEquals(mapOf("k1" to "v1", "k2" to "v2"), struct.dictionary)
struct.mutableArray = null
assertEquals(null, struct.mutableArray)
struct.mutableArray = mutableListOf(1, 2)
struct.mutableArray!! += 3
assertEquals(mutableListOf(1, 2, 3), struct.mutableArray)
// Check that subtyping via Nothing-returning functions does not break compiler.
assertFailsWith<NotImplementedError> {
struct.any = TODO()
struct.nsString = TODO()
struct.nonNullString = TODO()
struct.`object` = TODO()
struct.array = TODO()
struct.set = TODO()
struct.dictionary = TODO()
struct.mutableArray = TODO()
}
}
}
@@ -0,0 +1,6 @@
#import <Foundation/NSObject.h>
@interface WeakRefHolder : NSObject
@property (weak) id obj;
-(void)loadManyTimes;
@end;
@@ -0,0 +1,25 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test
fun testTryRetainGC() {
kotlin.native.internal.GC.collect()
val weakRefHolder = WeakRefHolder()
createGarbageNSObjects(weakRefHolder)
weakRefHolder.obj = object : NSObject() {}
// Loading weak ref takes a lock. If K/N runtime runs GC while the lock is taken,
// then it releases garbage objects and thus Obj-C runtime might take a recursive lock
// and abort in _os_unfair_lock_recursive_abort.
weakRefHolder.loadManyTimes()
}
private fun createGarbageNSObjects(weakRefHolder: WeakRefHolder) {
autoreleasepool {
repeat(100) {
// Assigning the object to a weak reference so Obj-C would take a lock when deallocating it:
weakRefHolder.obj = NSObject()
}
weakRefHolder.obj = null
}
}
@@ -0,0 +1,11 @@
#import "tryRetainGC.h"
#import <Foundation/NSArray.h>
@implementation WeakRefHolder
-(void)loadManyTimes {
NSMutableArray* array = [NSMutableArray new];
for (int i = 0; i < 10000; ++i) {
[array addObject:self.obj];
}
}
@end;
@@ -0,0 +1,17 @@
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
import objcTests.*
fun Worker.runInWorker(block: () -> Unit) {
block.freeze()
val future = this.execute(TransferMode.SAFE, { block }) {
it()
}
future.result // Throws on failure.
}
fun nsArrayOf(vararg elements: Any): NSArray = NSMutableArray().apply {
elements.forEach {
this.addObject(it as ObjCObject)
}
}
@@ -0,0 +1,20 @@
#import <Foundation/NSObject.h>
@interface TestVarargs : NSObject
-(instancetype _Nonnull)initWithFormat:(NSString*)format, ...;
+(instancetype _Nonnull)testVarargsWithFormat:(NSString*)format, ...;
@property NSString* formatted;
+(NSString* _Nonnull)stringWithFormat:(NSString*)format, ...;
+(NSObject* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args;
@end;
@interface TestVarargs (TestVarargsExtension)
-(instancetype _Nonnull)initWithFormat:(NSString*)format, ...;
@end;
@interface TestVarargsSubclass : TestVarargs
// Test clashes:
-(instancetype _Nonnull)initWithFormat:(NSString*)format args:(void*)args;
+(NSString* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args;
@end;
@@ -0,0 +1,53 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testVarargs() {
assertEquals(
"a b -1",
TestVarargs.testVarargsWithFormat(
"%@ %s %d",
"a" as NSString, "b".cstr, (-1).toByte()
).formatted
)
assertEquals(
"2 3 9223372036854775807",
TestVarargs(
"%d %d %lld",
2.toShort(), 3, Long.MAX_VALUE
).formatted
)
assertEquals(
"0.1 0.2 1 0",
TestVarargs.create(
"%.1f %.1lf %d %d",
0.1.toFloat(), 0.2, true, false
).formatted
)
assertEquals(
"1 2 3",
TestVarargs(
format = "%d %d %d",
args = *arrayOf(1, 2, 3)
).formatted
)
assertEquals(
"4 5 6",
TestVarargs(
args = *arrayOf(4, *arrayOf(5, 6)),
format = "%d %d %d"
).formatted
)
assertEquals(
"7",
TestVarargsSubclass.stringWithFormat(
"%d",
7
)
)
}
@@ -0,0 +1,51 @@
#import <stdlib.h>
#import <Foundation/NSString.h>
#import "varargs.h"
@implementation TestVarargs
-(instancetype _Nonnull)initWithFormat:(NSString*)format, ... {
self = [super init];
va_list args;
va_start(args, format);
self.formatted = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
return self;
}
+(instancetype _Nonnull)testVarargsWithFormat:(NSString*)format, ... {
TestVarargs* result = [[self alloc] init];
va_list args;
va_start(args, format);
result.formatted = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
return result;
}
+(NSString* _Nonnull)stringWithFormat:(NSString*)format, ... {
va_list args;
va_start(args, format);
NSString* result = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
return result;
}
+(NSObject* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args {
abort();
}
@end;
@implementation TestVarargsSubclass
-(instancetype _Nonnull)initWithFormat:(NSString*)format args:(void*)args {
abort();
}
+(NSString* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args {
abort();
}
@end;
@@ -0,0 +1,5 @@
#import <Foundation/NSObject.h>
NSObject* createNSObject() {
return [NSObject new];
}
@@ -0,0 +1,35 @@
import kotlin.native.ref.*
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test fun testWeakRefs() {
testWeakReference({ createNSObject()!! })
createAndAbandonWeakRef(NSObject())
testWeakReference({ NSArray.arrayWithArray(listOf(42)) as NSArray })
}
private fun testWeakReference(block: () -> NSObject) {
val ref = autoreleasepool {
createAndTestWeakReference(block)
}
kotlin.native.internal.GC.collect()
assertNull(ref.get())
}
private fun createAndTestWeakReference(block: () -> NSObject): WeakReference<NSObject> {
val ref = createWeakReference(block)
assertNotNull(ref.get())
assertEquals(ref.get()!!.hash(), ref.get()!!.hash())
return ref
}
private fun createWeakReference(block: () -> NSObject) = WeakReference(block())
private fun createAndAbandonWeakRef(obj: NSObject) {
WeakReference(obj)
}