Extend ObjC warning collector to handle exceptions as well

This commit is contained in:
Florian Kistner
2021-01-29 02:24:09 +01:00
committed by Vasily Levchenko
parent 3bf1f55990
commit 846d691b2d
5 changed files with 126 additions and 119 deletions
@@ -40,10 +40,12 @@ interface ObjCExportTranslator {
interface ObjCExportWarningCollector { interface ObjCExportWarningCollector {
fun reportWarning(text: String) fun reportWarning(text: String)
fun reportWarning(method: FunctionDescriptor, text: String) fun reportWarning(method: FunctionDescriptor, text: String)
fun reportException(throwable: Throwable)
object SILENT : ObjCExportWarningCollector { object SILENT : ObjCExportWarningCollector {
override fun reportWarning(text: String) {} override fun reportWarning(text: String) {}
override fun reportWarning(method: FunctionDescriptor, text: String) {} override fun reportWarning(method: FunctionDescriptor, text: String) {}
override fun reportException(throwable: Throwable) {}
} }
} }
@@ -57,64 +59,72 @@ internal class ObjCExportTranslatorImpl(
private val kotlinAnyName = namer.kotlinAnyName private val kotlinAnyName = namer.kotlinAnyName
override fun generateBaseDeclarations(): List<ObjCTopLevel<*>> { override fun generateBaseDeclarations(): List<ObjCTopLevel<*>> = buildTopLevel {
val stubs = mutableListOf<ObjCTopLevel<*>>() add {
objCInterface(namer.kotlinAnyName, superClass = "NSObject", members = buildMembers {
stubs.add(objCInterface(namer.kotlinAnyName, superClass = "NSObject", members = buildMembers { add { ObjCMethod(null, true, ObjCInstanceType, listOf("init"), emptyList(), listOf("unavailable")) }
+ObjCMethod(null, true, ObjCInstanceType, listOf("init"), emptyList(), listOf("unavailable")) add { ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable")) }
+ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable")) add { ObjCMethod(null, false, ObjCVoidType, listOf("initialize"), emptyList(), listOf("objc_requires_super")) }
+ObjCMethod(null, false, ObjCVoidType, listOf("initialize"), emptyList(), listOf("objc_requires_super")) })
})) }
// TODO: add comment to the header. // TODO: add comment to the header.
stubs.add(ObjCInterfaceImpl( add {
namer.kotlinAnyName.objCName, ObjCInterfaceImpl(
superProtocols = listOf("NSCopying"), namer.kotlinAnyName.objCName,
categoryName = "${namer.kotlinAnyName.objCName}Copying" superProtocols = listOf("NSCopying"),
)) categoryName = "${namer.kotlinAnyName.objCName}Copying"
)
}
// TODO: only if appears // TODO: only if appears
stubs.add(objCInterface( add {
namer.mutableSetName, objCInterface(
generics = listOf("ObjectType"), namer.mutableSetName,
superClass = "NSMutableSet<ObjectType>" generics = listOf("ObjectType"),
)) superClass = "NSMutableSet<ObjectType>"
)
}
// TODO: only if appears // TODO: only if appears
stubs.add(objCInterface( add {
namer.mutableMapName, objCInterface(
generics = listOf("KeyType", "ObjectType"), namer.mutableMapName,
superClass = "NSMutableDictionary<KeyType, ObjectType>" generics = listOf("KeyType", "ObjectType"),
)) superClass = "NSMutableDictionary<KeyType, ObjectType>"
)
}
val nsErrorCategoryName = "NSError${namer.topLevelNamePrefix}KotlinException" val nsErrorCategoryName = "NSError${namer.topLevelNamePrefix}KotlinException"
stubs.add(ObjCInterfaceImpl("NSError", categoryName = nsErrorCategoryName, members = buildMembers { add {
+ObjCProperty("kotlinException", null, ObjCNullableReferenceType(ObjCIdType), listOf("readonly")) ObjCInterfaceImpl("NSError", categoryName = nsErrorCategoryName, members = buildMembers {
})) add { ObjCProperty("kotlinException", null, ObjCNullableReferenceType(ObjCIdType), listOf("readonly")) }
})
}
genKotlinNumbers(stubs) genKotlinNumbers()
return stubs
} }
private fun genKotlinNumbers(stubs: MutableList<ObjCTopLevel<*>>) { private fun StubBuilder<ObjCTopLevel<*>>.genKotlinNumbers() {
val members = buildMembers { val members = buildMembers {
NSNumberKind.values().forEach { NSNumberKind.values().forEach {
+nsNumberFactory(it, listOf("unavailable")) add { nsNumberFactory(it, listOf("unavailable")) }
} }
NSNumberKind.values().forEach { NSNumberKind.values().forEach {
+nsNumberInit(it, listOf("unavailable")) add { nsNumberInit(it, listOf("unavailable")) }
} }
} }
stubs.add(objCInterface( add {
namer.kotlinNumberName, objCInterface(
superClass = "NSNumber", namer.kotlinNumberName,
members = members superClass = "NSNumber",
)) members = members
)
}
NSNumberKind.values().forEach { NSNumberKind.values().forEach {
if (it.mappedKotlinClassId != null) { if (it.mappedKotlinClassId != null) add {
stubs += genKotlinNumber(it.mappedKotlinClassId, it) genKotlinNumber(it.mappedKotlinClassId, it)
} }
} }
} }
@@ -123,8 +133,8 @@ internal class ObjCExportTranslatorImpl(
val name = namer.numberBoxName(kotlinClassId) val name = namer.numberBoxName(kotlinClassId)
val members = buildMembers { val members = buildMembers {
+nsNumberFactory(kind) add { nsNumberFactory(kind) }
+nsNumberInit(kind) add { nsNumberInit(kind) }
} }
return objCInterface( return objCInterface(
name, name,
@@ -316,19 +326,19 @@ internal class ObjCExportTranslatorImpl(
val selector = getSelector(it) val selector = getSelector(it)
if (!descriptor.isArray) presentConstructors += selector if (!descriptor.isArray) presentConstructors += selector
+buildMethod(it, it, genericExportScope) add { buildMethod(it, it, genericExportScope) }
exportThrown(it) exportThrown(it)
if (selector == "init") { if (selector == "init") add {
+ObjCMethod(it, false, ObjCInstanceType, listOf("new"), emptyList(), ObjCMethod(it, false, ObjCInstanceType, listOf("new"), emptyList(),
listOf("availability(swift, unavailable, message=\"use object initializers instead\")")) listOf("availability(swift, unavailable, message=\"use object initializers instead\")"))
} }
} }
if (descriptor.isArray || descriptor.kind == ClassKind.OBJECT || descriptor.kind == ClassKind.ENUM_CLASS) { if (descriptor.isArray || descriptor.kind == ClassKind.OBJECT || descriptor.kind == ClassKind.ENUM_CLASS) {
+ObjCMethod(null, false, ObjCInstanceType, listOf("alloc"), emptyList(), listOf("unavailable")) add { ObjCMethod(null, false, ObjCInstanceType, listOf("alloc"), emptyList(), listOf("unavailable")) }
val parameter = ObjCParameter("zone", null, ObjCRawType("struct _NSZone *")) val parameter = ObjCParameter("zone", null, ObjCRawType("struct _NSZone *"))
+ObjCMethod(descriptor, false, ObjCInstanceType, listOf("allocWithZone:"), listOf(parameter), listOf("unavailable")) add { ObjCMethod(descriptor, false, ObjCInstanceType, listOf("allocWithZone:"), listOf(parameter), listOf("unavailable")) }
} }
// Hide "unimplemented" super constructors: // Hide "unimplemented" super constructors:
@@ -338,10 +348,10 @@ internal class ObjCExportTranslatorImpl(
?.forEach { ?.forEach {
val selector = getSelector(it) val selector = getSelector(it)
if (selector !in presentConstructors) { if (selector !in presentConstructors) {
+buildMethod(it, it, ObjCNoneExportScope, unavailable = true) add { buildMethod(it, it, ObjCNoneExportScope, unavailable = true) }
if (selector == "init") { if (selector == "init") {
+ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable")) add { ObjCMethod(null, false, ObjCInstanceType, listOf("new"), emptyList(), listOf("unavailable")) }
} }
// TODO: consider adding exception-throwing impls for these. // TODO: consider adding exception-throwing impls for these.
@@ -350,8 +360,8 @@ internal class ObjCExportTranslatorImpl(
// TODO: consider adding exception-throwing impls for these. // TODO: consider adding exception-throwing impls for these.
when (descriptor.kind) { when (descriptor.kind) {
ClassKind.OBJECT -> { ClassKind.OBJECT -> add {
+ObjCMethod( ObjCMethod(
null, false, ObjCInstanceType, null, false, ObjCInstanceType,
listOf(namer.getObjectInstanceSelector(descriptor)), emptyList(), listOf(namer.getObjectInstanceSelector(descriptor)), emptyList(),
listOf(swiftNameAttribute("init()")) listOf(swiftNameAttribute("init()"))
@@ -362,8 +372,10 @@ internal class ObjCExportTranslatorImpl(
descriptor.enumEntries.forEach { descriptor.enumEntries.forEach {
val entryName = namer.getEnumEntrySelector(it) val entryName = namer.getEnumEntrySelector(it)
+ObjCProperty(entryName, it, type, listOf("class", "readonly"), add {
declarationAttributes = listOf(swiftNameAttribute(entryName))) ObjCProperty(entryName, it, type, listOf("class", "readonly"),
declarationAttributes = listOf(swiftNameAttribute(entryName)))
}
} }
// Note: it is possible to support this function through a common machinery, // Note: it is possible to support this function through a common machinery,
@@ -371,7 +383,7 @@ internal class ObjCExportTranslatorImpl(
// to keep this ad hoc here than to add special cases to the most complicated parts // to keep this ad hoc here than to add special cases to the most complicated parts
// of the machinery. // of the machinery.
descriptor.getEnumValuesFunctionDescriptor()?.let { enumValues -> descriptor.getEnumValuesFunctionDescriptor()?.let { enumValues ->
+buildEnumValuesMethod(enumValues, genericExportScope) add { buildEnumValuesMethod(enumValues, genericExportScope) }
} }
} }
else -> { else -> {
@@ -434,12 +446,12 @@ internal class ObjCExportTranslatorImpl(
.filter { mapper.shouldBeExposed(it) } .filter { mapper.shouldBeExposed(it) }
.toList() .toList()
private fun StubBuilder.translateClassMembers(descriptor: ClassDescriptor, objCExportScope: ObjCExportScope) { private fun StubBuilder<Stub<*>>.translateClassMembers(descriptor: ClassDescriptor, objCExportScope: ObjCExportScope) {
require(!descriptor.isInterface) require(!descriptor.isInterface)
translateClassMembers(descriptor.getExposedMembers(), objCExportScope) translateClassMembers(descriptor.getExposedMembers(), objCExportScope)
} }
private fun StubBuilder.translateInterfaceMembers(descriptor: ClassDescriptor) { private fun StubBuilder<Stub<*>>.translateInterfaceMembers(descriptor: ClassDescriptor) {
require(descriptor.isInterface) require(descriptor.isInterface)
translateBaseMembers(descriptor.getExposedMembers()) translateBaseMembers(descriptor.getExposedMembers())
} }
@@ -460,7 +472,7 @@ internal class ObjCExportTranslatorImpl(
} }
} }
private fun StubBuilder.translateClassMembers( private fun StubBuilder<Stub<*>>.translateClassMembers(
members: List<CallableMemberDescriptor>, members: List<CallableMemberDescriptor>,
objCExportScope: ObjCExportScope objCExportScope: ObjCExportScope
) { ) {
@@ -480,18 +492,18 @@ internal class ObjCExportTranslatorImpl(
mapper.getBaseMethods(method) mapper.getBaseMethods(method)
.asSequence() .asSequence()
.distinctBy { namer.getSelector(it) } .distinctBy { namer.getSelector(it) }
.forEach { base -> +buildMethod(method, base, objCExportScope) } .forEach { base -> add { buildMethod(method, base, objCExportScope) } }
} }
properties.forEach { property -> properties.forEach { property ->
mapper.getBaseProperties(property) mapper.getBaseProperties(property)
.asSequence() .asSequence()
.distinctBy { namer.getPropertyName(it) } .distinctBy { namer.getPropertyName(it) }
.forEach { base -> +buildProperty(property, base, objCExportScope) } .forEach { base -> add { buildProperty(property, base, objCExportScope) } }
} }
} }
private fun StubBuilder.translateBaseMembers(members: List<CallableMemberDescriptor>) { private fun StubBuilder<Stub<*>>.translateBaseMembers(members: List<CallableMemberDescriptor>) {
// TODO: add some marks about modality. // TODO: add some marks about modality.
val methods = mutableListOf<FunctionDescriptor>() val methods = mutableListOf<FunctionDescriptor>()
@@ -515,7 +527,7 @@ internal class ObjCExportTranslatorImpl(
translatePlainMembers(methods, properties, ObjCNoneExportScope) translatePlainMembers(methods, properties, ObjCNoneExportScope)
} }
private fun StubBuilder.translatePlainMembers(members: List<CallableMemberDescriptor>, objCExportScope: ObjCExportScope) { private fun StubBuilder<Stub<*>>.translatePlainMembers(members: List<CallableMemberDescriptor>, objCExportScope: ObjCExportScope) {
val methods = mutableListOf<FunctionDescriptor>() val methods = mutableListOf<FunctionDescriptor>()
val properties = mutableListOf<PropertyDescriptor>() val properties = mutableListOf<PropertyDescriptor>()
@@ -526,9 +538,9 @@ internal class ObjCExportTranslatorImpl(
translatePlainMembers(methods, properties, objCExportScope) translatePlainMembers(methods, properties, objCExportScope)
} }
private fun StubBuilder.translatePlainMembers(methods: List<FunctionDescriptor>, properties: List<PropertyDescriptor>, objCExportScope: ObjCExportScope) { private fun StubBuilder<Stub<*>>.translatePlainMembers(methods: List<FunctionDescriptor>, properties: List<PropertyDescriptor>, objCExportScope: ObjCExportScope) {
methods.forEach { +buildMethod(it, it, objCExportScope) } methods.forEach { add { buildMethod(it, it, objCExportScope) } }
properties.forEach { +buildProperty(it, it, objCExportScope) } properties.forEach { add { buildProperty(it, it, objCExportScope) } }
} }
// TODO: consider checking that signatures for bases with same selector/name are equal. // TODO: consider checking that signatures for bases with same selector/name are equal.
@@ -943,44 +955,56 @@ internal class ObjCExportTranslatorImpl(
// TODO: consider other namings. // TODO: consider other namings.
} }
} }
private inline fun buildTopLevel(block: StubBuilder<ObjCTopLevel<*>>.() -> Unit) = buildStubs(block)
private inline fun buildMembers(block: StubBuilder<Stub<*>>.() -> Unit) = buildStubs(block)
private inline fun <S : Stub<*>> buildStubs(block: StubBuilder<S>.() -> Unit): List<S> =
StubBuilder<S>(warningCollector).apply(block).build()
} }
abstract class ObjCExportHeaderGenerator internal constructor( abstract class ObjCExportHeaderGenerator internal constructor(
val moduleDescriptors: List<ModuleDescriptor>, val moduleDescriptors: List<ModuleDescriptor>,
internal val mapper: ObjCExportMapper, internal val mapper: ObjCExportMapper,
val namer: ObjCExportNamer, val namer: ObjCExportNamer,
val objcGenerics:Boolean = false val objcGenerics: Boolean,
warningCollector: ObjCExportWarningCollector
) { ) {
constructor( constructor(
moduleDescriptors: List<ModuleDescriptor>, moduleDescriptors: List<ModuleDescriptor>,
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
topLevelNamePrefix: String topLevelNamePrefix: String,
) : this(moduleDescriptors, builtIns, topLevelNamePrefix, ObjCExportMapper()) warningCollector: ObjCExportWarningCollector
) : this(moduleDescriptors, builtIns, topLevelNamePrefix, ObjCExportMapper(), warningCollector)
private constructor( private constructor(
moduleDescriptors: List<ModuleDescriptor>, moduleDescriptors: List<ModuleDescriptor>,
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
topLevelNamePrefix: String, topLevelNamePrefix: String,
mapper: ObjCExportMapper mapper: ObjCExportMapper,
warningCollector: ObjCExportWarningCollector
) : this( ) : this(
moduleDescriptors, moduleDescriptors,
mapper, mapper,
ObjCExportNamerImpl(moduleDescriptors.toSet(), builtIns, mapper, topLevelNamePrefix, local = false) ObjCExportNamerImpl(moduleDescriptors.toSet(), builtIns, mapper, topLevelNamePrefix, local = false),
false,
warningCollector
) )
constructor( constructor(
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
topLevelNamePrefix: String = moduleDescriptor.namePrefix topLevelNamePrefix: String = moduleDescriptor.namePrefix,
) : this(moduleDescriptor, emptyList(), builtIns, topLevelNamePrefix) warningCollector: ObjCExportWarningCollector
) : this(moduleDescriptor, emptyList(), builtIns, topLevelNamePrefix, warningCollector)
constructor( constructor(
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
exportedDependencies: List<ModuleDescriptor>, exportedDependencies: List<ModuleDescriptor>,
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
topLevelNamePrefix: String = moduleDescriptor.namePrefix topLevelNamePrefix: String = moduleDescriptor.namePrefix,
) : this(listOf(moduleDescriptor) + exportedDependencies, builtIns, topLevelNamePrefix) warningCollector: ObjCExportWarningCollector
) : this(listOf(moduleDescriptor) + exportedDependencies, builtIns, topLevelNamePrefix, warningCollector)
private val stubs = mutableListOf<Stub<*>>() private val stubs = mutableListOf<Stub<*>>()
@@ -988,15 +1012,7 @@ abstract class ObjCExportHeaderGenerator internal constructor(
private val protocolForwardDeclarations = linkedSetOf<String>() private val protocolForwardDeclarations = linkedSetOf<String>()
private val extraClassesToTranslate = mutableSetOf<ClassDescriptor>() private val extraClassesToTranslate = mutableSetOf<ClassDescriptor>()
private val translator = ObjCExportTranslatorImpl(this, mapper, namer, private val translator = ObjCExportTranslatorImpl(this, mapper, namer, warningCollector, objcGenerics)
object : ObjCExportWarningCollector {
override fun reportWarning(text: String) =
this@ObjCExportHeaderGenerator.reportWarning(text)
override fun reportWarning(method: FunctionDescriptor, text: String) =
this@ObjCExportHeaderGenerator.reportWarning(method, text)
},
objcGenerics)
private val generatedClasses = mutableSetOf<ClassDescriptor>() private val generatedClasses = mutableSetOf<ClassDescriptor>()
private val extensions = mutableMapOf<ClassDescriptor, MutableList<CallableMemberDescriptor>>() private val extensions = mutableMapOf<ClassDescriptor, MutableList<CallableMemberDescriptor>>()
@@ -1050,10 +1066,6 @@ abstract class ObjCExportHeaderGenerator internal constructor(
fun getExportStubs(): ObjCExportedStubs = fun getExportStubs(): ObjCExportedStubs =
ObjCExportedStubs(classForwardDeclarations, protocolForwardDeclarations, stubs) ObjCExportedStubs(classForwardDeclarations, protocolForwardDeclarations, stubs)
protected abstract fun reportWarning(text: String)
protected abstract fun reportWarning(method: FunctionDescriptor, text: String)
protected open fun getAdditionalImports(): List<String> = emptyList() protected open fun getAdditionalImports(): List<String> = emptyList()
fun translateModule() { fun translateModule() {
@@ -22,21 +22,26 @@ internal class ObjCExportHeaderGeneratorImpl(
mapper: ObjCExportMapper, mapper: ObjCExportMapper,
namer: ObjCExportNamer, namer: ObjCExportNamer,
objcGenerics: Boolean objcGenerics: Boolean
) : ObjCExportHeaderGenerator(moduleDescriptors, mapper, namer, objcGenerics) { ) : ObjCExportHeaderGenerator(moduleDescriptors, mapper, namer, objcGenerics, WarningCollector(context)) {
private class WarningCollector(val context: Context) : ObjCExportWarningCollector {
override fun reportWarning(text: String) {
context.reportCompilationWarning(text)
}
override fun reportWarning(text: String) { override fun reportWarning(method: FunctionDescriptor, text: String) {
context.reportCompilationWarning(text) val psi = (method as? DeclarationDescriptorWithSource)?.source?.getPsi()
} ?: return reportWarning(
"$text\n (at ${DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(method)})"
)
override fun reportWarning(method: FunctionDescriptor, text: String) { val location = MessageUtil.psiElementToMessageLocation(psi)
val psi = (method as? DeclarationDescriptorWithSource)?.source?.getPsi()
?: return reportWarning(
"$text\n (at ${DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(method)})"
)
val location = MessageUtil.psiElementToMessageLocation(psi) context.messageCollector.report(CompilerMessageSeverity.WARNING, text, location)
}
context.messageCollector.report(CompilerMessageSeverity.WARNING, text, location) override fun reportException(throwable: Throwable) {
throw throwable
}
} }
override fun getAdditionalImports(): List<String> = override fun getAdditionalImports(): List<String> =
@@ -95,7 +95,7 @@ internal class ObjCExportLazyImpl(
mapper, mapper,
namer, namer,
warningCollector, warningCollector,
objcGenerics = configuration.objcGenerics configuration.objcGenerics
) )
private val isValid: Boolean private val isValid: Boolean
@@ -2,7 +2,6 @@ package org.jetbrains.kotlin.backend.konan.objcexport
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -11,10 +10,10 @@ class ObjcExportHeaderGeneratorMobile internal constructor(
moduleDescriptors: List<ModuleDescriptor>, moduleDescriptors: List<ModuleDescriptor>,
mapper: ObjCExportMapper, mapper: ObjCExportMapper,
namer: ObjCExportNamer, namer: ObjCExportNamer,
private val warningCollector: ObjCExportWarningCollector, warningCollector: ObjCExportWarningCollector,
objcGenerics: Boolean, objcGenerics: Boolean,
private val restrictToLocalModules: Boolean private val restrictToLocalModules: Boolean
) : ObjCExportHeaderGenerator(moduleDescriptors, mapper, namer, objcGenerics) { ) : ObjCExportHeaderGenerator(moduleDescriptors, mapper, namer, objcGenerics, warningCollector) {
companion object { companion object {
fun createInstance( fun createInstance(
@@ -42,12 +41,4 @@ class ObjcExportHeaderGeneratorMobile internal constructor(
override fun shouldTranslateExtraClass(descriptor: ClassDescriptor): Boolean = override fun shouldTranslateExtraClass(descriptor: ClassDescriptor): Boolean =
!restrictToLocalModules || descriptor.module in moduleDescriptors !restrictToLocalModules || descriptor.module in moduleDescriptors
override fun reportWarning(text: String) {
warningCollector.reportWarning(text)
}
override fun reportWarning(method: FunctionDescriptor, text: String) {
warningCollector.reportWarning(method, text)
}
} }
@@ -5,21 +5,20 @@
package org.jetbrains.kotlin.backend.konan.objcexport package org.jetbrains.kotlin.backend.konan.objcexport
internal class StubBuilder { internal class StubBuilder<S : Stub<*>>(private val warningCollector: ObjCExportWarningCollector) {
private val children = mutableListOf<Stub<*>>() private val children = mutableListOf<S>()
operator fun Stub<*>.unaryPlus() { inline fun add(provider: () -> S) {
children.add(this) try {
children.add(provider())
} catch (t: Throwable) {
warningCollector.reportException(t)
}
} }
operator fun plusAssign(set: Collection<Stub<*>>) { operator fun plusAssign(set: Collection<S>) {
children += set children += set
} }
fun build() = children fun build(): List<S> = children
}
internal inline fun buildMembers(block: StubBuilder.() -> Unit): List<Stub<*>> = StubBuilder().let {
it.block()
it.build()
} }