[K/N] Add objcClassesIncludingCategories cinterop property
It allows to list Objective-C classes that should include corresponding categories from the same file. The current implementation is super-simple and slow, but it is OK since it is not intended to be a general-purpose solution for now.
This commit is contained in:
committed by
Space Team
parent
ab205edeab
commit
2f0bdfc5e2
+41
-2
@@ -64,6 +64,7 @@ private class ObjCClassImpl(
|
||||
override val methods = mutableListOf<ObjCMethod>()
|
||||
override val properties = mutableListOf<ObjCProperty>()
|
||||
override var baseClass: ObjCClass? = null
|
||||
override val includedCategories = mutableListOf<ObjCCategory>()
|
||||
}
|
||||
|
||||
private class ObjCCategoryImpl(
|
||||
@@ -392,10 +393,48 @@ public open class NativeIndexImpl(val library: NativeLibrary, val verbose: Boole
|
||||
return objCClassRegistry.getOrPut(cursor, {
|
||||
ObjCClassImpl(name, getLocation(cursor), isForwardDeclaration = false,
|
||||
binaryName = getObjCBinaryName(cursor).takeIf { it != name })
|
||||
}) {
|
||||
addChildrenToObjCContainer(cursor, it)
|
||||
}) { objcClass ->
|
||||
addChildrenToObjCContainer(cursor, objcClass)
|
||||
if (name in this.library.objCClassesIncludingCategories) {
|
||||
// We don't include methods from categories to class during indexing
|
||||
// because indexing does not care about how class is represented in Kotlin.
|
||||
// Instead, it should be done during StubIR construction.
|
||||
objcClass.includedCategories += collectClassCategories(cursor, name).mapNotNull { getObjCCategoryAt(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all categories for a class that is pointed by [classCursor] in the same file.
|
||||
* NB: Current implementation is rather slow as it walks the whole translation unit.
|
||||
*/
|
||||
private fun collectClassCategories(classCursor: CValue<CXCursor>, className: String): List<CValue<CXCursor>> {
|
||||
assert(classCursor.kind == CXCursorKind.CXCursor_ObjCInterfaceDecl) { classCursor.kind }
|
||||
val classFile = getContainingFile(classCursor)
|
||||
val result = mutableListOf<CValue<CXCursor>>()
|
||||
// Accessing the whole translation unit (TU) is overkill, but it is the simplest solution which is doable
|
||||
// since we use this function for a narrow set of cases.
|
||||
// Possible improvements:
|
||||
// 1. Find/create a function that returns a file scope. `clang_findReferencesInFile` does not seem to work because for categories
|
||||
// it returns `CXCursor_ObjCClassRef` (@interface >CLASS_REFERENCE<(CategoryName)) and there is no easy way to access category from
|
||||
// there.
|
||||
// 2. Extract categories collection into a separate TU pass and create Class -> [Category] mapping. This way we can avoid visiting
|
||||
// TU for every class.
|
||||
val translationUnit = clang_getCursorLexicalParent(classCursor)
|
||||
visitChildren(translationUnit) { childCursor, _ ->
|
||||
if (childCursor.kind == CXCursorKind.CXCursor_ObjCCategoryDecl) {
|
||||
val categoryClassCursor = getObjCCategoryClassCursor(childCursor)
|
||||
val categoryClassName = clang_getCursorDisplayName(categoryClassCursor).convertAndDispose()
|
||||
if (className == categoryClassName) {
|
||||
val categoryFile = getContainingFile(childCursor)
|
||||
if (clang_File_isEqual(categoryFile, classFile) != 0) {
|
||||
result += childCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
CXChildVisitResult.CXChildVisit_Continue
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getObjCProtocolAt(cursor: CValue<CXCursor>): ObjCProtocolImpl {
|
||||
|
||||
+21
-10
@@ -100,16 +100,23 @@ data class CompilationWithPCH(
|
||||
get() = emptyList()
|
||||
}
|
||||
|
||||
// TODO: Compilation hierarchy seems to require some refactoring.
|
||||
|
||||
data class NativeLibrary(override val includes: List<IncludeInfo>,
|
||||
override val additionalPreambleLines: List<String>,
|
||||
override val compilerArgs: List<String>,
|
||||
val headerToIdMapper: HeaderToIdMapper,
|
||||
override val language: Language,
|
||||
val excludeSystemLibs: Boolean, // TODO: drop?
|
||||
val headerExclusionPolicy: HeaderExclusionPolicy,
|
||||
val headerFilter: NativeLibraryHeaderFilter) : Compilation
|
||||
/**
|
||||
*
|
||||
* @param objCClassesIncludingCategories Objective-C classes that should be merged with categories from the same file.
|
||||
*
|
||||
* TODO: Compilation hierarchy seems to require some refactoring.
|
||||
*/
|
||||
data class NativeLibrary(
|
||||
override val includes: List<IncludeInfo>,
|
||||
override val additionalPreambleLines: List<String>,
|
||||
override val compilerArgs: List<String>,
|
||||
val headerToIdMapper: HeaderToIdMapper,
|
||||
override val language: Language,
|
||||
val excludeSystemLibs: Boolean, // TODO: drop?
|
||||
val headerExclusionPolicy: HeaderExclusionPolicy,
|
||||
val headerFilter: NativeLibraryHeaderFilter,
|
||||
val objCClassesIncludingCategories: Set<String>,
|
||||
) : Compilation
|
||||
|
||||
data class IndexerResult(val index: NativeIndex, val compilation: CompilationWithPCH)
|
||||
|
||||
@@ -270,6 +277,10 @@ data class ObjCProperty(val name: String, val getter: ObjCMethod, val setter: Ob
|
||||
abstract class ObjCClass(name: String) : ObjCClassOrProtocol(name) {
|
||||
abstract val binaryName: String?
|
||||
abstract val baseClass: ObjCClass?
|
||||
/**
|
||||
* Categories whose methods and properties should be generated as members of Kotlin class.
|
||||
*/
|
||||
abstract val includedCategories: List<ObjCCategory>
|
||||
}
|
||||
abstract class ObjCProtocol(name: String) : ObjCClassOrProtocol(name)
|
||||
|
||||
|
||||
+3
-1
@@ -568,6 +568,7 @@ internal fun buildNativeLibrary(
|
||||
|
||||
val headerExclusionPolicy = HeaderExclusionPolicyImpl(imports)
|
||||
|
||||
val objCClassesIncludingCategories = def.config.objcClassesIncludingCategories.toSet()
|
||||
return NativeLibrary(
|
||||
includes = includes,
|
||||
additionalPreambleLines = compilation.additionalPreambleLines,
|
||||
@@ -576,7 +577,8 @@ internal fun buildNativeLibrary(
|
||||
language = compilation.language,
|
||||
excludeSystemLibs = excludeSystemLibs,
|
||||
headerExclusionPolicy = headerExclusionPolicy,
|
||||
headerFilter = headerFilter
|
||||
headerFilter = headerFilter,
|
||||
objCClassesIncludingCategories = objCClassesIncludingCategories
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,9 @@ class DefFile(val file:File?, val config:DefFileConfig, val manifestAddendProper
|
||||
properties.getProperty("plugin")
|
||||
}
|
||||
|
||||
val objcClassesIncludingCategories by lazy {
|
||||
properties.getSpaceSeparated("objcClassesIncludingCategories")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user