Improve support for Objective-C forward declarations

This commit is contained in:
Svyatoslav Scherbina
2017-10-20 16:29:39 +03:00
committed by SvyatoslavScherbina
parent 91ab69b835
commit 905390cd45
6 changed files with 69 additions and 36 deletions
@@ -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)
} }
@@ -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,
@@ -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"
@@ -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()
@@ -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))
} }
} }
+18 -4
View File
@@ -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;