[ObjCExport] Add translation of functions and properties extensions
KT-65630
This commit is contained in:
committed by
Space Team
parent
a34b87c63a
commit
30b63e4843
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package org.jetbrains.kotlin.objcexport.analysisApiUtils
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
|
||||||
|
import org.jetbrains.kotlin.name.NameUtils
|
||||||
|
import org.jetbrains.kotlin.objcexport.KtObjCExportSession
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
|
context(KtAnalysisSession, KtObjCExportSession)
|
||||||
|
internal fun KtFileSymbol.getFileName(): String? {
|
||||||
|
val ktFile = this.psi as? KtFile ?: return null
|
||||||
|
return NameUtils.getPackagePartClassNamePrefix(FileUtil.getNameWithoutExtension(ktFile.name))
|
||||||
|
}
|
||||||
+1
-1
@@ -44,7 +44,7 @@ context(KtAnalysisSession)
|
|||||||
private val KtCallableSymbol.receiverType: MethodBridgeReceiver
|
private val KtCallableSymbol.receiverType: MethodBridgeReceiver
|
||||||
get() = if (isArrayConstructor) {
|
get() = if (isArrayConstructor) {
|
||||||
MethodBridgeReceiver.Factory
|
MethodBridgeReceiver.Factory
|
||||||
} else if (!isConstructor && isTopLevel) {
|
} else if (!isConstructor && isTopLevel && !isExtension) {
|
||||||
MethodBridgeReceiver.Static
|
MethodBridgeReceiver.Static
|
||||||
} else {
|
} else {
|
||||||
MethodBridgeReceiver.Instance
|
MethodBridgeReceiver.Instance
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ import kotlin.contracts.ExperimentalContracts
|
|||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
context(KtAnalysisSession)
|
context(KtAnalysisSession)
|
||||||
internal fun KtSymbol.isVisibleInObjC(): Boolean = when(this) {
|
internal fun KtSymbol.isVisibleInObjC(): Boolean = when (this) {
|
||||||
is KtCallableSymbol -> this.isVisibleInObjC()
|
is KtCallableSymbol -> this.isVisibleInObjC()
|
||||||
is KtClassOrObjectSymbol -> this.isVisibleInObjC()
|
is KtClassOrObjectSymbol -> this.isVisibleInObjC()
|
||||||
else -> false
|
else -> false
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
package org.jetbrains.kotlin.objcexport
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
|
||||||
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCInterface
|
||||||
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCInterfaceImpl
|
||||||
|
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getFileName
|
||||||
|
|
||||||
|
private const val extensionsCategoryName = "Extensions"
|
||||||
|
|
||||||
|
internal val ObjCInterface.isExtensionsFacade: Boolean
|
||||||
|
get() = this.categoryName == extensionsCategoryName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates extension functions/properties inside the given [this] file as a single [ObjCInterface]
|
||||||
|
* with category [extensionsCategoryName]
|
||||||
|
*
|
||||||
|
* Later interface should be forwarded using [isExtensionsFacade]
|
||||||
|
*
|
||||||
|
* ## example:
|
||||||
|
* given a file "Foo.kt"
|
||||||
|
*
|
||||||
|
* ```kotlin
|
||||||
|
*
|
||||||
|
* fun Foo.func() = 42
|
||||||
|
*
|
||||||
|
* val Foo.prop get() = 42
|
||||||
|
*
|
||||||
|
* class Foo {
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This will be exporting two Interfaces with forwarded class:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* @class Foo
|
||||||
|
*
|
||||||
|
* @interface Foo: Base
|
||||||
|
*
|
||||||
|
* @interface Foo (Extensions)
|
||||||
|
* - func
|
||||||
|
* - prop
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Where `Foo` would be the "top level interface file extensions facade" returned by this function.
|
||||||
|
*
|
||||||
|
* See related [getTopLevelFacade]
|
||||||
|
*/
|
||||||
|
context(KtAnalysisSession, KtObjCExportSession)
|
||||||
|
fun KtFileSymbol.getExtensionsFacade(): ObjCInterface? {
|
||||||
|
|
||||||
|
val extensions = getFileScope()
|
||||||
|
.getCallableSymbols().filter { it.isExtension }
|
||||||
|
.toList().sortedWith(StableCallableOrder)
|
||||||
|
.ifEmpty { return null }
|
||||||
|
|
||||||
|
val fileName = getFileName()
|
||||||
|
?: throw IllegalStateException("File '$this' cannot be translated without file name")
|
||||||
|
|
||||||
|
return ObjCInterfaceImpl(
|
||||||
|
name = fileName,
|
||||||
|
comment = null,
|
||||||
|
origin = null,
|
||||||
|
attributes = emptyList(),
|
||||||
|
superProtocols = emptyList(),
|
||||||
|
members = extensions.mapNotNull { it.translateToObjCExportStub() },
|
||||||
|
categoryName = extensionsCategoryName,
|
||||||
|
generics = emptyList(),
|
||||||
|
superClass = null,
|
||||||
|
superClassGenerics = emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package org.jetbrains.kotlin.objcexport
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
|
||||||
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportFileName
|
||||||
|
import org.jetbrains.kotlin.backend.konan.objcexport.toIdentifier
|
||||||
|
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getFileName
|
||||||
|
|
||||||
|
context(KtAnalysisSession, KtObjCExportSession)
|
||||||
|
internal fun KtFileSymbol.getObjCFileClassOrProtocolName(): ObjCExportFileName? {
|
||||||
|
val fileName = getFileName() ?: return null
|
||||||
|
return (fileName + "Kt").toIdentifier().getObjCFileName()
|
||||||
|
}
|
||||||
+12
-15
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.objcexport.ObjCInterface
|
|||||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCInterfaceImpl
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCInterfaceImpl
|
||||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
|
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates top level functions/properties inside the given [this] file as a single [ObjCInterface].
|
* Translates top level functions/properties inside the given [this] file as a single [ObjCInterface].
|
||||||
* ## example:
|
* ## example:
|
||||||
@@ -40,34 +41,30 @@ import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrPr
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* Where `FooKt` would be the "top level interface file facade" returned by this function.
|
* Where `FooKt` would be the "top level interface file facade" returned by this function.
|
||||||
|
*
|
||||||
|
* See related [getExtensionsFacade]
|
||||||
*/
|
*/
|
||||||
context(KtAnalysisSession, KtObjCExportSession)
|
context(KtAnalysisSession, KtObjCExportSession)
|
||||||
fun KtFileSymbol.translateToObjCTopLevelInterfaceFileFacade(): ObjCInterface? {
|
fun KtFileSymbol.getTopLevelFacade(): ObjCInterface? {
|
||||||
val topLevelCallableStubs = getFileScope().getCallableSymbols()
|
val extensions = getFileScope().getCallableSymbols()
|
||||||
.sortedWith(StableCallableOrder)
|
.filter { !it.isExtension }
|
||||||
.mapNotNull { callableSymbol -> callableSymbol.translateToObjCExportStub() }
|
|
||||||
.toList()
|
.toList()
|
||||||
/* If there are no top level functions or properties, we do not need to export a file facade */
|
.sortedWith(StableCallableOrder)
|
||||||
.ifEmpty { return null }
|
.ifEmpty { return null }
|
||||||
|
|
||||||
val fileName = getObjCFileClassOrProtocolName()
|
val fileName = getObjCFileClassOrProtocolName()
|
||||||
?: throw IllegalStateException("Top level file '$this' cannot be translated without file name")
|
?: throw IllegalStateException("File '$this' cannot be translated without file name")
|
||||||
|
|
||||||
val name = fileName.objCName
|
|
||||||
val attributes = listOf(OBJC_SUBCLASSING_RESTRICTED)
|
|
||||||
|
|
||||||
val superClass = getDefaultSuperClassOrProtocolName()
|
|
||||||
|
|
||||||
return ObjCInterfaceImpl(
|
return ObjCInterfaceImpl(
|
||||||
name = name,
|
name = fileName.objCName,
|
||||||
comment = null,
|
comment = null,
|
||||||
origin = null,
|
origin = null,
|
||||||
attributes = attributes,
|
attributes = listOf(OBJC_SUBCLASSING_RESTRICTED),
|
||||||
superProtocols = emptyList(),
|
superProtocols = emptyList(),
|
||||||
members = topLevelCallableStubs,
|
members = extensions.mapNotNull { it.translateToObjCExportStub() },
|
||||||
categoryName = null,
|
categoryName = null,
|
||||||
generics = emptyList(),
|
generics = emptyList(),
|
||||||
superClass = superClass.objCName,
|
superClass = getDefaultSuperClassOrProtocolName().objCName,
|
||||||
superClassGenerics = emptyList()
|
superClassGenerics = emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+8
-6
@@ -37,7 +37,7 @@ private class KtObjCExportHeaderGenerator {
|
|||||||
* Represents all elements that still have to be processed and translated.
|
* Represents all elements that still have to be processed and translated.
|
||||||
* So far this only includes references to top level entities (such as files or classes):
|
* So far this only includes references to top level entities (such as files or classes):
|
||||||
* Note: Top level functions and properties will be translated as part of the file.
|
* Note: Top level functions and properties will be translated as part of the file.
|
||||||
* See [translateToObjCTopLevelInterfaceFileFacade]
|
* See [translateToObjCTopLevelInterfaceFileFacades]
|
||||||
*/
|
*/
|
||||||
private val symbolDeque = ArrayDeque<QueueElement>()
|
private val symbolDeque = ArrayDeque<QueueElement>()
|
||||||
|
|
||||||
@@ -90,17 +90,17 @@ private class KtObjCExportHeaderGenerator {
|
|||||||
context(KtAnalysisSession, KtObjCExportSession)
|
context(KtAnalysisSession, KtObjCExportSession)
|
||||||
private fun translateFileElement(element: QueueElement.File) {
|
private fun translateFileElement(element: QueueElement.File) {
|
||||||
val fileSymbol = element.psi.getFileSymbol()
|
val fileSymbol = element.psi.getFileSymbol()
|
||||||
translateFileSymbol(fileSymbol)
|
|
||||||
fileSymbol.getAllClassOrObjectSymbols().sortedWith(StableClassifierOrder).forEach { classOrObjectSymbol ->
|
fileSymbol.getAllClassOrObjectSymbols().sortedWith(StableClassifierOrder).forEach { classOrObjectSymbol ->
|
||||||
translateClassOrObjectSymbol(classOrObjectSymbol)
|
translateClassOrObjectSymbol(classOrObjectSymbol)
|
||||||
}
|
}
|
||||||
|
translateFileSymbol(fileSymbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession, KtObjCExportSession)
|
context(KtAnalysisSession, KtObjCExportSession)
|
||||||
private fun translateFileSymbol(symbol: KtFileSymbol) {
|
private fun translateFileSymbol(symbol: KtFileSymbol) {
|
||||||
val objCInterface = symbol.translateToObjCTopLevelInterfaceFileFacade() ?: return
|
val objCFacades = listOfNotNull(symbol.getExtensionsFacade(), symbol.getTopLevelFacade()).ifEmpty { return }
|
||||||
objCStubs += objCInterface
|
objCStubs += objCFacades
|
||||||
enqueueDependencyClasses(objCInterface)
|
objCFacades.forEach { enqueueDependencyClasses(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession, KtObjCExportSession)
|
context(KtAnalysisSession, KtObjCExportSession)
|
||||||
@@ -178,7 +178,9 @@ private class KtObjCExportHeaderGenerator {
|
|||||||
|
|
||||||
val classForwardDeclarations = resolvedObjCForwardDeclarations.filterIsInstance<ObjCInterface>()
|
val classForwardDeclarations = resolvedObjCForwardDeclarations.filterIsInstance<ObjCInterface>()
|
||||||
.map { stub -> ObjCClassForwardDeclaration(stub.name, stub.generics) }
|
.map { stub -> ObjCClassForwardDeclaration(stub.name, stub.generics) }
|
||||||
.plus(listOfNotNull(errorForwardClass.takeIf { hasErrorTypes })).toSet()
|
.plus(listOfNotNull(errorForwardClass.takeIf { hasErrorTypes }))
|
||||||
|
.plus(objCStubs.filterIsInstance<ObjCInterface>().filter { it.isExtensionsFacade }.map { ObjCClassForwardDeclaration(it.name) })
|
||||||
|
.toSet()
|
||||||
|
|
||||||
val stubs = (if (configuration.generateBaseDeclarationStubs) objCBaseDeclarations() else emptyList()).plus(objCStubs)
|
val stubs = (if (configuration.generateBaseDeclarationStubs) objCBaseDeclarations() else emptyList()).plus(objCStubs)
|
||||||
.plus(listOfNotNull(errorInterface.takeIf { hasErrorTypes }))
|
.plus(listOfNotNull(errorInterface.takeIf { hasErrorTypes }))
|
||||||
|
|||||||
+2
-12
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.objcexport
|
package org.jetbrains.kotlin.objcexport
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
|
||||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.analysis.api.annotations.annotationInfos
|
import org.jetbrains.kotlin.analysis.api.annotations.annotationInfos
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||||
@@ -11,11 +10,9 @@ import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
|||||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.NameUtils
|
|
||||||
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSelectors
|
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSelectors
|
||||||
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSwiftNames
|
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSwiftNames
|
||||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.*
|
import org.jetbrains.kotlin.objcexport.analysisApiUtils.*
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
|
|
||||||
internal val KtCallableSymbol.isConstructor: Boolean
|
internal val KtCallableSymbol.isConstructor: Boolean
|
||||||
get() = this is KtConstructorSymbol
|
get() = this is KtConstructorSymbol
|
||||||
@@ -28,13 +25,6 @@ fun KtFunctionSymbol.translateToObjCMethod(): ObjCMethod? {
|
|||||||
return buildObjCMethod()
|
return buildObjCMethod()
|
||||||
}
|
}
|
||||||
|
|
||||||
context(KtAnalysisSession, KtObjCExportSession)
|
|
||||||
fun KtFileSymbol.getObjCFileClassOrProtocolName(): ObjCExportFileName? {
|
|
||||||
val ktFile = this.psi as? KtFile ?: return null
|
|
||||||
val name = NameUtils.getPackagePartClassNamePrefix(FileUtil.getNameWithoutExtension(ktFile.name)) + "Kt"
|
|
||||||
return name.toIdentifier().getObjCFileName()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.buildMethod]
|
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.buildMethod]
|
||||||
*/
|
*/
|
||||||
@@ -272,7 +262,7 @@ fun MethodBridge.valueParametersAssociated(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun String.startsWithWords(words: String) = this.startsWith(words) &&
|
private fun String.startsWithWords(words: String) = this.startsWith(words) &&
|
||||||
(this.length == words.length || !this[words.length].isLowerCase())
|
(this.length == words.length || !this[words.length].isLowerCase())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapReturnType]
|
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mapReturnType]
|
||||||
@@ -292,7 +282,7 @@ fun KtFunctionLikeSymbol.mapReturnType(returnBridge: MethodBridge.ReturnValue):
|
|||||||
if (!returnBridge.successMayBeZero) {
|
if (!returnBridge.successMayBeZero) {
|
||||||
check(
|
check(
|
||||||
successReturnType is ObjCNonNullReferenceType
|
successReturnType is ObjCNonNullReferenceType
|
||||||
|| (successReturnType is ObjCPointerType && !successReturnType.nullable)
|
|| (successReturnType is ObjCPointerType && !successReturnType.nullable)
|
||||||
) {
|
) {
|
||||||
"Unexpected return type: $successReturnType in $this"
|
"Unexpected return type: $successReturnType in $this"
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -117,7 +117,6 @@ class ObjCExportHeaderGeneratorTest(private val generator: HeaderGenerator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TodoAnalysisApi
|
|
||||||
fun `test - functionWithObjCNameAnnotation`() {
|
fun `test - functionWithObjCNameAnnotation`() {
|
||||||
doTest(headersTestDataDir.resolve("functionWithObjCNameAnnotation"))
|
doTest(headersTestDataDir.resolve("functionWithObjCNameAnnotation"))
|
||||||
}
|
}
|
||||||
@@ -243,15 +242,17 @@ class ObjCExportHeaderGeneratorTest(private val generator: HeaderGenerator) {
|
|||||||
doTest(headersTestDataDir.resolve("interfaceImplementingInterfaceOrder"))
|
doTest(headersTestDataDir.resolve("interfaceImplementingInterfaceOrder"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension functions aren't supported KT-65630
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
@TodoAnalysisApi
|
|
||||||
fun `test - extensionFunctions`() {
|
fun `test - extensionFunctions`() {
|
||||||
doTest(headersTestDataDir.resolve("extensionFunctions"))
|
doTest(headersTestDataDir.resolve("extensionFunctions"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - extensionProperties`() {
|
||||||
|
doTest(headersTestDataDir.resolve("extensionProperties"))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - classWithGenerics`() {
|
fun `test - classWithGenerics`() {
|
||||||
doTest(headersTestDataDir.resolve("classWithGenerics"))
|
doTest(headersTestDataDir.resolve("classWithGenerics"))
|
||||||
|
|||||||
Vendored
+9
-2
@@ -24,11 +24,18 @@ __attribute__((objc_subclassing_restricted))
|
|||||||
@interface Foo : Base
|
@interface Foo : Base
|
||||||
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||||
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||||
- (void)funA __attribute__((swift_name("funA()")));
|
- (void)memberFun __attribute__((swift_name("memberFun()")));
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface Foo (Extensions)
|
@interface Foo (Extensions)
|
||||||
- (void)funB __attribute__((swift_name("funB()")));
|
- (void)extensionFunA __attribute__((swift_name("extensionFunA()")));
|
||||||
|
- (void)extensionFunB __attribute__((swift_name("extensionFunB()")));
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_subclassing_restricted))
|
||||||
|
@interface FooKt : Base
|
||||||
|
+ (void)topLevelFunA __attribute__((swift_name("topLevelFunA()")));
|
||||||
|
+ (void)topLevelFunB __attribute__((swift_name("topLevelFunB()")));
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#pragma pop_macro("_Nullable_result")
|
#pragma pop_macro("_Nullable_result")
|
||||||
|
|||||||
+8
-4
@@ -1,5 +1,9 @@
|
|||||||
class Foo {
|
fun topLevelFunA() {}
|
||||||
fun funA() {}
|
fun topLevelFunB() {}
|
||||||
}
|
|
||||||
|
|
||||||
fun Foo.funB() {}
|
fun Foo.extensionFunA() {}
|
||||||
|
fun Foo.extensionFunB() {}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun memberFun() {}
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#import <Foundation/NSArray.h>
|
||||||
|
#import <Foundation/NSDictionary.h>
|
||||||
|
#import <Foundation/NSError.h>
|
||||||
|
#import <Foundation/NSObject.h>
|
||||||
|
#import <Foundation/NSSet.h>
|
||||||
|
#import <Foundation/NSString.h>
|
||||||
|
#import <Foundation/NSValue.h>
|
||||||
|
|
||||||
|
@class Foo;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||||
|
#pragma clang diagnostic ignored "-Wincompatible-property-type"
|
||||||
|
#pragma clang diagnostic ignored "-Wnullability"
|
||||||
|
|
||||||
|
#pragma push_macro("_Nullable_result")
|
||||||
|
#if !__has_feature(nullability_nullable_result)
|
||||||
|
#undef _Nullable_result
|
||||||
|
#define _Nullable_result _Nullable
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__attribute__((objc_subclassing_restricted))
|
||||||
|
@interface Foo : Base
|
||||||
|
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
||||||
|
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
||||||
|
- (void)memberFun __attribute__((swift_name("memberFun()")));
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface Foo (Extensions)
|
||||||
|
@property (readonly) int32_t extensionValA __attribute__((swift_name("extensionValA")));
|
||||||
|
@property (readonly) int32_t extensionValB __attribute__((swift_name("extensionValB")));
|
||||||
|
@property int32_t extensionVarA __attribute__((swift_name("extensionVarA")));
|
||||||
|
@property int32_t extensionVarB __attribute__((swift_name("extensionVarB")));
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_subclassing_restricted))
|
||||||
|
@interface FooKt : Base
|
||||||
|
@property (class, readonly) int32_t topLevelPropA __attribute__((swift_name("topLevelPropA")));
|
||||||
|
@property (class, readonly) int32_t topLevelPropB __attribute__((swift_name("topLevelPropB")));
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma pop_macro("_Nullable_result")
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
val topLevelPropA = 0
|
||||||
|
val topLevelPropB = 1
|
||||||
|
|
||||||
|
val Foo.extensionValA
|
||||||
|
get() = 0
|
||||||
|
val Foo.extensionValB
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
var Foo.extensionVarA
|
||||||
|
get() = 0
|
||||||
|
set(value) {}
|
||||||
|
var Foo.extensionVarB
|
||||||
|
get() = 1
|
||||||
|
set(value) {}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun memberFun() {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user