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(
name: String,
override val location: Location
override val location: Location,
override val isForwardDeclaration: Boolean
) : ObjCProtocol(name), ObjCContainerImpl {
override val protocols = mutableListOf<ObjCProtocol>()
override val methods = mutableListOf<ObjCMethod>()
@@ -58,7 +59,8 @@ private class ObjCProtocolImpl(
private class ObjCClassImpl(
name: String,
override val location: Location
override val location: Location,
override val isForwardDeclaration: Boolean
) : ObjCClass(name), ObjCContainerImpl {
override val protocols = mutableListOf<ObjCProtocol>()
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 {
assert(cursor.kind == CXCursorKind.CXCursor_ObjCInterfaceDecl) { cursor.kind }
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)
}
}
private fun getObjCProtocolAt(cursor: CValue<CXCursor>): ObjCProtocolImpl? {
private fun getObjCProtocolAt(cursor: CValue<CXCursor>): ObjCProtocolImpl {
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()
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)
}
}
@@ -340,10 +369,9 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
result.baseClass = getObjCClassAt(clang_getCursorReferenced(child))
}
CXCursorKind.CXCursor_ObjCProtocolRef -> {
getObjCProtocolAt(clang_getCursorReferenced(child))?.let {
if (it !in result.protocols) {
result.protocols.add(it)
}
val protocol = getObjCProtocolAt(clang_getCursorReferenced(child))
if (protocol !in result.protocols) {
result.protocols.add(protocol)
}
}
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> {
val num = clang_Type_getNumProtocols(type)
return (0 until num).mapNotNull { index ->
return (0 until num).map { index ->
getObjCProtocolAt(clang_Type_getProtocol(type, index))
}
}
@@ -745,7 +773,7 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {
val objCContainer: ObjCContainerImpl? = when (container.kind) {
CXCursorKind.CXCursor_ObjCCategoryDecl -> getObjCCategoryAt(container)
CXCursorKind.CXCursor_ObjCInterfaceDecl -> getObjCClassAt(container)
CXCursorKind.CXCursor_ObjCProtocolDecl -> getObjCProtocolAt(container)!!
CXCursorKind.CXCursor_ObjCProtocolDecl -> getObjCProtocolAt(container)
else -> error(container.kind)
}
@@ -136,7 +136,9 @@ sealed class ObjCContainer {
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(
val selector: String, val encoding: String, val parameters: List<Parameter>, private val returnType: Type,
@@ -29,7 +29,7 @@ fun DeclarationMapper.getKotlinClassFor(
objCClassOrProtocol: ObjCClassOrProtocol,
isMeta: Boolean = false
): Classifier {
val pkg = if (objCClassOrProtocol.shouldBeImportedAsForwardDeclaration()) {
val pkg = if (objCClassOrProtocol.isForwardDeclaration) {
when (objCClassOrProtocol) {
is ObjCClass -> "objcnames.classes"
is ObjCProtocol -> "objcnames.protocols"
@@ -506,17 +506,6 @@ fun ObjCClassOrProtocol.kotlinClassName(isMeta: Boolean): String {
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() =
(if (this.nsConsumed) "__attribute__((ns_consumed)) " else "") + type.getStringRepresentation()
@@ -785,13 +785,13 @@ class StubGenerator(
stubs.addAll(generateStubsForFunctions(functionsToBind))
nativeIndex.objCProtocols.forEach {
if (!it.shouldBeImportedAsForwardDeclaration()) {
if (!it.isForwardDeclaration) {
stubs.add(ObjCProtocolStub(this, it))
}
}
nativeIndex.objCClasses.forEach {
if (!it.shouldBeImportedAsForwardDeclaration()) {
if (!it.isForwardDeclaration) {
stubs.add(ObjCClassStub(this, it))
}
}
+18 -4
View File
@@ -1,13 +1,22 @@
#import <objc/NSObject.h>
@protocol Printer
@required
-(void)print:(const char*)string;
@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
@interface Foo : NSObject <Empty>
@property NSStringTypedef* name;
-(void)helloWithPrinter:(id <Printer>)printer;
@end;
@@ -16,6 +25,11 @@ typedef NSString NSStringTypedef;
-(void)hello;
@end;
@protocol Printer
@required
-(void)print:(const char*)string;
@end;
@protocol MutablePair
@required
@property (readonly) int first;