For reproduce:
Module1:
package test1
abstract class TestBase<T>
////////////////////////////////////////////////////////////////////////////////
Module2
package test2
class TestDerived: TestBase<Any>
fun main() {
console.info(TestDerived().toString()) }
////////////////////////////////////////////////////////////////////////////////
SyntheticResolveExtension
override fun generateSyntheticSecondaryConstructors(thisDescriptor: ClassDescriptor, bindingContext: BindingContext, result: MutableCollection<ClassConstructorDescriptor>) {
super.generateSyntheticSecondaryConstructors(thisDescriptor, bindingContext, result)
if (thisDescriptor.fqNameOrNull() in arrayOf(FqName("test1.TestBase"), FqName("test2.TestDerived"))) {
result.add(ClassConstructorDescriptorImpl.createSynthesized(
thisDescriptor,
Annotations.EMPTY,
false,
thisDescriptor.source
).apply {
initialize(
null,
null,
ArrayList(thisDescriptor.declaredTypeParameters),
mutableListOf(
ValueParameterDescriptorImpl(
this,
null,
0,
Annotations.EMPTY,
Name.identifier("stub"),
thisDescriptor.module.builtIns.unitType,
false,
false,
false,
null,
thisDescriptor.source
) as ValueParameterDescriptor
),
thisDescriptor.defaultType,
Modality.OPEN,
Visibilities.PUBLIC
)
})
}
}
////////////////////////////////////////////////////////////////////////////////
IrGenerationExtension
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
moduleFragment.transformChildren(object : IrElementTransformer<Unit> {
override fun visitClass(declaration: IrClass, data: Unit): IrStatement {
if (declaration.fqNameWhenAvailable() in arrayOf(FqName("test1.TestBase"), FqName("test2.TestDerived"))) {
generateTestConstructor(declaration, pluginContext)
}
return super.visitClass(declaration, data)
}
}
}
private fun generateTestConstructor(klass: IrClass, pluginContext: IrPluginContext) {
val constructor = klass.constructors.find { it.valueParameters.size == 1 && it.valueParameters[0].type.isUnit() }!!
val superClass = klass.superTypes.find { it.classOrNull != null }!!.classOrNull!!.owner
val superClassIsAny = superClass.symbol == pluginContext.irBuiltIns.anyClass
val superConstructor = if (superClassIsAny) {
superClass.constructors.find { it.valueParameters.isEmpty() }!!
} else {
superClass.constructors.find { it.valueParameters.size == 1 && it.valueParameters[0].type.isUnit() }!!
}
constructor.body = IrBlockBodyImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
listOf(
IrDelegatingConstructorCallImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
superConstructor.returnType,
superConstructor.symbol,
superConstructor.typeParameters.size,
if (superClassIsAny) 0 else 1
).also { constructorCall ->
val anyType = pluginContext.irBuiltIns.anyType
for (param in superConstructor.typeParameters.withIndex()) {
constructorCall.putTypeArgument(param.index, anyType)
}
if (!superClassIsAny) {
constructorCall.putValueArgument(0, pluginContext.unitValue)
}
}
)
)
}