Improve support for Objective-C forward declarations
This commit is contained in:
committed by
SvyatoslavScherbina
parent
91ab69b835
commit
905390cd45
+45
-17
@@ -49,7 +49,8 @@ private interface ObjCContainerImpl {
|
|||||||
|
|
||||||
private class ObjCProtocolImpl(
|
private class ObjCProtocolImpl(
|
||||||
name: String,
|
name: String,
|
||||||
override val location: Location
|
override val location: Location,
|
||||||
|
override val isForwardDeclaration: Boolean
|
||||||
) : ObjCProtocol(name), ObjCContainerImpl {
|
) : ObjCProtocol(name), ObjCContainerImpl {
|
||||||
override val protocols = mutableListOf<ObjCProtocol>()
|
override val protocols = mutableListOf<ObjCProtocol>()
|
||||||
override val methods = mutableListOf<ObjCMethod>()
|
override val methods = mutableListOf<ObjCMethod>()
|
||||||
@@ -58,7 +59,8 @@ private class ObjCProtocolImpl(
|
|||||||
|
|
||||||
private class ObjCClassImpl(
|
private class ObjCClassImpl(
|
||||||
name: String,
|
name: String,
|
||||||
override val location: Location
|
override val location: Location,
|
||||||
|
override val isForwardDeclaration: Boolean
|
||||||
) : ObjCClass(name), ObjCContainerImpl {
|
) : ObjCClass(name), ObjCContainerImpl {
|
||||||
override val protocols = mutableListOf<ObjCProtocol>()
|
override val protocols = mutableListOf<ObjCProtocol>()
|
||||||
override val methods = mutableListOf<ObjCMethod>()
|
override val methods = mutableListOf<ObjCMethod>()
|
||||||
@@ -285,28 +287,55 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isObjCInterfaceDeclForward(cursor: CValue<CXCursor>): Boolean {
|
||||||
|
assert(cursor.kind == CXCursorKind.CXCursor_ObjCInterfaceDecl) { cursor.kind }
|
||||||
|
|
||||||
|
// It is forward declaration <=> the first child is reference to it:
|
||||||
|
var result = false
|
||||||
|
visitChildren(cursor) { child, _ ->
|
||||||
|
result = (child.kind == CXCursorKind.CXCursor_ObjCClassRef && clang_getCursorReferenced(child) == cursor)
|
||||||
|
CXChildVisitResult.CXChildVisit_Break
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private fun getObjCClassAt(cursor: CValue<CXCursor>): ObjCClassImpl {
|
private fun getObjCClassAt(cursor: CValue<CXCursor>): ObjCClassImpl {
|
||||||
assert(cursor.kind == CXCursorKind.CXCursor_ObjCInterfaceDecl) { cursor.kind }
|
assert(cursor.kind == CXCursorKind.CXCursor_ObjCInterfaceDecl) { cursor.kind }
|
||||||
|
|
||||||
val name = clang_getCursorDisplayName(cursor).convertAndDispose()
|
val name = clang_getCursorDisplayName(cursor).convertAndDispose()
|
||||||
|
|
||||||
return objCClassRegistry.getOrPut(cursor, { ObjCClassImpl(name, getLocation(cursor)) }) {
|
if (isObjCInterfaceDeclForward(cursor)) {
|
||||||
|
return objCClassRegistry.getOrPut(cursor) {
|
||||||
|
ObjCClassImpl(name, getLocation(cursor), isForwardDeclaration = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return objCClassRegistry.getOrPut(cursor, {
|
||||||
|
ObjCClassImpl(name, getLocation(cursor), isForwardDeclaration = false)
|
||||||
|
}) {
|
||||||
addChildrenToObjCContainer(cursor, it)
|
addChildrenToObjCContainer(cursor, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getObjCProtocolAt(cursor: CValue<CXCursor>): ObjCProtocolImpl? {
|
private fun getObjCProtocolAt(cursor: CValue<CXCursor>): ObjCProtocolImpl {
|
||||||
assert(cursor.kind == CXCursorKind.CXCursor_ObjCProtocolDecl) { cursor.kind }
|
assert(cursor.kind == CXCursorKind.CXCursor_ObjCProtocolDecl) { cursor.kind }
|
||||||
if (clang_isCursorDefinition(cursor) == 0) {
|
|
||||||
val definition = clang_getCursorDefinition(cursor)
|
|
||||||
if (clang_isCursorDefinition(cursor) == 0) return null
|
|
||||||
return getObjCProtocolAt(definition)
|
|
||||||
}
|
|
||||||
|
|
||||||
val name = clang_getCursorDisplayName(cursor).convertAndDispose()
|
val name = clang_getCursorDisplayName(cursor).convertAndDispose()
|
||||||
|
|
||||||
return objCProtocolRegistry.getOrPut(cursor, { ObjCProtocolImpl(name, getLocation(cursor)) }) {
|
if (clang_isCursorDefinition(cursor) == 0) {
|
||||||
|
val definition = clang_getCursorDefinition(cursor)
|
||||||
|
return if (clang_isCursorDefinition(definition) != 0) {
|
||||||
|
getObjCProtocolAt(definition)
|
||||||
|
} else {
|
||||||
|
objCProtocolRegistry.getOrPut(cursor) {
|
||||||
|
ObjCProtocolImpl(name, getLocation(cursor), isForwardDeclaration = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return objCProtocolRegistry.getOrPut(cursor, {
|
||||||
|
ObjCProtocolImpl(name, getLocation(cursor), isForwardDeclaration = false)
|
||||||
|
}) {
|
||||||
addChildrenToObjCContainer(cursor, it)
|
addChildrenToObjCContainer(cursor, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,10 +369,9 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
|
|||||||
result.baseClass = getObjCClassAt(clang_getCursorReferenced(child))
|
result.baseClass = getObjCClassAt(clang_getCursorReferenced(child))
|
||||||
}
|
}
|
||||||
CXCursorKind.CXCursor_ObjCProtocolRef -> {
|
CXCursorKind.CXCursor_ObjCProtocolRef -> {
|
||||||
getObjCProtocolAt(clang_getCursorReferenced(child))?.let {
|
val protocol = getObjCProtocolAt(clang_getCursorReferenced(child))
|
||||||
if (it !in result.protocols) {
|
if (protocol !in result.protocols) {
|
||||||
result.protocols.add(it)
|
result.protocols.add(protocol)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CXCursorKind.CXCursor_ObjCClassMethodDecl, CXCursorKind.CXCursor_ObjCInstanceMethodDecl -> {
|
CXCursorKind.CXCursor_ObjCClassMethodDecl, CXCursorKind.CXCursor_ObjCInstanceMethodDecl -> {
|
||||||
@@ -576,7 +604,7 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
|
|||||||
|
|
||||||
private fun getProtocols(type: CValue<CXType>): List<ObjCProtocol> {
|
private fun getProtocols(type: CValue<CXType>): List<ObjCProtocol> {
|
||||||
val num = clang_Type_getNumProtocols(type)
|
val num = clang_Type_getNumProtocols(type)
|
||||||
return (0 until num).mapNotNull { index ->
|
return (0 until num).map { index ->
|
||||||
getObjCProtocolAt(clang_Type_getProtocol(type, index))
|
getObjCProtocolAt(clang_Type_getProtocol(type, index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -745,7 +773,7 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
|
|||||||
val objCContainer: ObjCContainerImpl? = when (container.kind) {
|
val objCContainer: ObjCContainerImpl? = when (container.kind) {
|
||||||
CXCursorKind.CXCursor_ObjCCategoryDecl -> getObjCCategoryAt(container)
|
CXCursorKind.CXCursor_ObjCCategoryDecl -> getObjCCategoryAt(container)
|
||||||
CXCursorKind.CXCursor_ObjCInterfaceDecl -> getObjCClassAt(container)
|
CXCursorKind.CXCursor_ObjCInterfaceDecl -> getObjCClassAt(container)
|
||||||
CXCursorKind.CXCursor_ObjCProtocolDecl -> getObjCProtocolAt(container)!!
|
CXCursorKind.CXCursor_ObjCProtocolDecl -> getObjCProtocolAt(container)
|
||||||
else -> error(container.kind)
|
else -> error(container.kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -136,7 +136,9 @@ sealed class ObjCContainer {
|
|||||||
abstract val properties: List<ObjCProperty>
|
abstract val properties: List<ObjCProperty>
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class ObjCClassOrProtocol(val name: String) : ObjCContainer(), TypeDeclaration
|
sealed class ObjCClassOrProtocol(val name: String) : ObjCContainer(), TypeDeclaration {
|
||||||
|
abstract val isForwardDeclaration: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
data class ObjCMethod(
|
data class ObjCMethod(
|
||||||
val selector: String, val encoding: String, val parameters: List<Parameter>, private val returnType: Type,
|
val selector: String, val encoding: String, val parameters: List<Parameter>, private val returnType: Type,
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ fun DeclarationMapper.getKotlinClassFor(
|
|||||||
objCClassOrProtocol: ObjCClassOrProtocol,
|
objCClassOrProtocol: ObjCClassOrProtocol,
|
||||||
isMeta: Boolean = false
|
isMeta: Boolean = false
|
||||||
): Classifier {
|
): Classifier {
|
||||||
val pkg = if (objCClassOrProtocol.shouldBeImportedAsForwardDeclaration()) {
|
val pkg = if (objCClassOrProtocol.isForwardDeclaration) {
|
||||||
when (objCClassOrProtocol) {
|
when (objCClassOrProtocol) {
|
||||||
is ObjCClass -> "objcnames.classes"
|
is ObjCClass -> "objcnames.classes"
|
||||||
is ObjCProtocol -> "objcnames.protocols"
|
is ObjCProtocol -> "objcnames.protocols"
|
||||||
|
|||||||
-11
@@ -506,17 +506,6 @@ fun ObjCClassOrProtocol.kotlinClassName(isMeta: Boolean): String {
|
|||||||
return if (isMeta) "${baseClassName}Meta" else baseClassName
|
return if (isMeta) "${baseClassName}Meta" else baseClassName
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ObjCClassOrProtocol.shouldBeImportedAsForwardDeclaration(): Boolean {
|
|
||||||
// Note: currently it is not very easy to distinct class or protocol declarations from forward references,
|
|
||||||
// so the code below treats the empty declarations as forward ones;
|
|
||||||
// it is correct because empty and forward declarations feel exactly the same.
|
|
||||||
|
|
||||||
return this.protocols.isEmpty() &&
|
|
||||||
this.methods.isEmpty() &&
|
|
||||||
this.properties.isEmpty() &&
|
|
||||||
(this as? ObjCClass)?.baseClass == null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Parameter.getTypeStringRepresentation() =
|
private fun Parameter.getTypeStringRepresentation() =
|
||||||
(if (this.nsConsumed) "__attribute__((ns_consumed)) " else "") + type.getStringRepresentation()
|
(if (this.nsConsumed) "__attribute__((ns_consumed)) " else "") + type.getStringRepresentation()
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -785,13 +785,13 @@ class StubGenerator(
|
|||||||
stubs.addAll(generateStubsForFunctions(functionsToBind))
|
stubs.addAll(generateStubsForFunctions(functionsToBind))
|
||||||
|
|
||||||
nativeIndex.objCProtocols.forEach {
|
nativeIndex.objCProtocols.forEach {
|
||||||
if (!it.shouldBeImportedAsForwardDeclaration()) {
|
if (!it.isForwardDeclaration) {
|
||||||
stubs.add(ObjCProtocolStub(this, it))
|
stubs.add(ObjCProtocolStub(this, it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeIndex.objCClasses.forEach {
|
nativeIndex.objCClasses.forEach {
|
||||||
if (!it.shouldBeImportedAsForwardDeclaration()) {
|
if (!it.isForwardDeclaration) {
|
||||||
stubs.add(ObjCClassStub(this, it))
|
stubs.add(ObjCClassStub(this, it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
#import <objc/NSObject.h>
|
#import <objc/NSObject.h>
|
||||||
|
|
||||||
@protocol Printer
|
@class Foo;
|
||||||
@required
|
|
||||||
-(void)print:(const char*)string;
|
@protocol Printer;
|
||||||
|
@protocol Printer;
|
||||||
|
|
||||||
|
@protocol Empty
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
|
@protocol Forward;
|
||||||
|
@class Forward;
|
||||||
|
|
||||||
|
void useForward1(Forward * p) {}
|
||||||
|
void useForward2(id<Forward> p) {}
|
||||||
|
|
||||||
typedef NSString NSStringTypedef;
|
typedef NSString NSStringTypedef;
|
||||||
|
|
||||||
@interface Foo : NSObject
|
@interface Foo : NSObject <Empty>
|
||||||
@property NSStringTypedef* name;
|
@property NSStringTypedef* name;
|
||||||
-(void)helloWithPrinter:(id <Printer>)printer;
|
-(void)helloWithPrinter:(id <Printer>)printer;
|
||||||
@end;
|
@end;
|
||||||
@@ -16,6 +25,11 @@ typedef NSString NSStringTypedef;
|
|||||||
-(void)hello;
|
-(void)hello;
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
|
@protocol Printer
|
||||||
|
@required
|
||||||
|
-(void)print:(const char*)string;
|
||||||
|
@end;
|
||||||
|
|
||||||
@protocol MutablePair
|
@protocol MutablePair
|
||||||
@required
|
@required
|
||||||
@property (readonly) int first;
|
@property (readonly) int first;
|
||||||
|
|||||||
Reference in New Issue
Block a user