Repository: JetBrains/kotlin
File: compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentDeclarationGenerator.kt (Kotlin)

Code before:
    override val context: GeneratorContext,
    private val fragmentInfo: EvaluatorFragmentInfo
) : Generator {
    private val typeTranslator = context.typeTranslator

    fun KotlinType.toIrType() = typeTranslator.translateType(this)

    fun generateClassForCodeFragment(ktFile: KtBlockCodeFragment): IrClass =
        FragmentClassGenerator(this, fragmentInfo).generateClassForCodeFragment(ktFile)

    fun generateScopedTypeParameterDeclarations(
        irTypeParametersOwner: IrTypeParametersContainer
    ) {
        for (irTypeParameter in irTypeParametersOwner.typeParameters) {
            irTypeParameter.superTypes = irTypeParameter.descriptor.upperBounds.map {
                it.toIrType()
            }
        }
    }

    fun generateFunctionForFragment(ktFile: KtBlockCodeFragment): IrSimpleFunction {
        return FragmentFunctionGenerator(this, fragmentInfo).generateFunctionForFragment(ktFile)
    }
}

abstract class FragmentDeclarationGeneratorExtension(val declarationGenerator: FragmentDeclarationGenerator) : Generator {

    override val context: GeneratorContext get() = declarationGenerator.context

    inline fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T =
        also { irDeclaration ->
            context.symbolTable.withScope(irDeclaration) {
                builder(irDeclaration)
            }
        }

    fun KotlinType.toIrType() = with(declarationGenerator) { toIrType() }
}

Review comment (refactor):
What purpose does this extra abstract class serve? Could `FragmentDeclarationGenerator` just be open and have two subclasses instead of having this extra abstract class?

Code after:
import org.jetbrains.kotlin.psi2ir.generators.Generator
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.createBodyGenerator
import org.jetbrains.kotlin.types.KotlinType

open class FragmentDeclarationGenerator(
    override val context: GeneratorContext,
    private val fragmentInfo: EvaluatorFragmentInfo
) : Generator {

    fun generateClassForCodeFragment(ktFile: KtBlockCodeFragment): IrClass {
        val classDescriptor = fragmentInfo.classDescriptor
        val startOffset = UNDEFINED_OFFSET
        val endOffset = UNDEFINED_OFFSET

        return context.symbolTable.declareClass(classDescriptor) {
            context.irFactory.createIrClassFromDescriptor(
                startOffset, endOffset,
                IrDeclarationOrigin.DEFINED,
                symbol = it,
                classDescriptor,
                context.symbolTable.nameProvider.nameForDeclaration(classDescriptor),
                classDescriptor.visibility,
                Modality.FINAL
            )
        }.buildWithScope { irClass ->
            irClass.thisReceiver = context.symbolTable.declareValueParameter(
                startOffset, endOffset,
                IrDeclarationOrigin.INSTANCE_RECEIVER,
                classDescriptor.thisAsReceiverParameter,
                classDescriptor.thisAsReceiverParameter.type.toIrType()
            )

            generatePrimaryConstructor(irClass)

            irClass.declarations.add(
                generateFunctionForFragment(ktFile)
            )
        }
    }

    private fun generatePrimaryConstructor(irClass: IrClass) {
        val constructor = context.irFactory.createConstructor(
            startOffset = UNDEFINED_OFFSET,
            endOffset = UNDEFINED_OFFSET,
            origin = IrDeclarationOrigin.DEFINED,
            symbol = IrConstructorPublicSymbolImpl(context.symbolTable.signaturer.composeSignature(irClass.descriptor)!!),
            Name.special("<init>"),
            irClass.visibility,
            irClass.defaultType,
            isInline = false,