/*
 * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

// This file was generated automatically. See compiler/ir/ir.tree/tree-generator/ReadMe.md.
// DO NOT MODIFY IT MANUALLY.

package org.jetbrains.kotlin.ir.util

import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrImplementationDetail
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.utils.memoryOptimizedMap
import org.jetbrains.kotlin.utils.addToStdlib.assignFrom

/**
 * Auto-generated by [org.jetbrains.kotlin.ir.generator.print.DeepCopyIrTreeWithSymbolsPrinter]
 */
@OptIn(IrImplementationDetail::class)
open class DeepCopyIrTreeWithSymbols(
    private val symbolRemapper: SymbolRemapper,
    typeRemapper: TypeRemapper? = null,
) : IrDeepCopyBase() {
    private var transformedModule: IrModuleFragment? = null
    private val typeRemapper: TypeRemapper = typeRemapper ?: DeepCopyTypeRemapper(symbolRemapper)
    private val transformedLoops: HashMap<IrLoop, IrLoop> = HashMap()

    init {
        // TODO refactor
        // After removing usages of DeepCopyTypeRemapper constructor from compose, the lateinit property `DeepCopyTypeRemapper.deepCopy`
        // can be refactored to a constructor parameter.
        (this.typeRemapper as? DeepCopyTypeRemapper)?.let {
            it.deepCopy = this
        }
    }

    // You can't call super from extension version, so we must create non-extension to make it easily overridable
    protected open fun remapTypeImpl(type: IrType) = typeRemapper.remapType(type)
    final override fun IrType.remapType() = remapTypeImpl(this)

    override fun visitElement(element: IrElement): IrElement =
        throw IllegalArgumentException("Unsupported element type: $element")

    override fun visitValueParameter(declaration: IrValueParameter): IrValueParameter =
        IrValueParameterImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            type = declaration.type.remapType(),
            isAssignable = declaration.isAssignable,
            symbol = symbolRemapper.getDeclaredValueParameter(declaration.symbol),
            varargElementType = declaration.varargElementType?.remapType(),
            isCrossinline = declaration.isCrossinline,
            isNoinline = declaration.isNoinline,
            isHidden = declaration.isHidden,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            defaultValue = declaration.defaultValue?.transform()
            kind = declaration.kind
            processAttributes(declaration)
        }

    override fun visitClass(declaration: IrClass): IrClass =
        IrClassImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            visibility = declaration.visibility,
            symbol = symbolRemapper.getDeclaredClass(declaration.symbol),
            kind = declaration.kind,
            modality = declaration.modality,
            source = declaration.source,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            isExternal = declaration.isExternal
            typeParameters = declaration.typeParameters.memoryOptimizedMap { it.transform() }
            declarations.assignFrom(declaration.declarations) { it.transform() }
            isCompanion = declaration.isCompanion
            isInner = declaration.isInner
            isData = declaration.isData
            isValue = declaration.isValue
            isExpect = declaration.isExpect
            isFun = declaration.isFun
            hasEnumEntries = declaration.hasEnumEntries
            superTypes = declaration.superTypes.memoryOptimizedMap { it.remapType() }
            thisReceiver = declaration.thisReceiver?.transform()
            valueClassRepresentation = declaration.valueClassRepresentation?.mapUnderlyingType { it.remapType() as IrSimpleType }
            sealedSubclasses = declaration.sealedSubclasses.memoryOptimizedMap { symbolRemapper.getReferencedClass(it) }
            processAttributes(declaration)
        }

    override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrAnonymousInitializer =
        IrAnonymousInitializerImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            symbol = symbolRemapper.getDeclaredAnonymousInitializer(declaration.symbol),
            isStatic = declaration.isStatic,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            body = declaration.body.transform()
            processAttributes(declaration)
        }

    override fun visitTypeParameter(declaration: IrTypeParameter): IrTypeParameter =
        IrTypeParameterImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            symbol = symbolRemapper.getDeclaredTypeParameter(declaration.symbol),
            variance = declaration.variance,
            index = declaration.index,
            isReified = declaration.isReified,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            superTypes = declaration.superTypes.memoryOptimizedMap { it.remapType() }
            processAttributes(declaration)
        }

    override fun visitConstructor(declaration: IrConstructor): IrConstructor =
        IrConstructorImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            isExternal = declaration.isExternal,
            visibility = declaration.visibility,
            containerSource = declaration.containerSource,
            isInline = declaration.isInline,
            isExpect = declaration.isExpect,
            symbol = symbolRemapper.getDeclaredConstructor(declaration.symbol),
            isPrimary = declaration.isPrimary,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            typeParameters = declaration.typeParameters.memoryOptimizedMap { it.transform() }
            returnType = declaration.returnType.remapType()
            body = declaration.body?.transform()
            parameters = declaration.parameters.memoryOptimizedMap { it.transform() }
            processAttributes(declaration)
        }

    override fun visitEnumEntry(declaration: IrEnumEntry): IrEnumEntry =
        IrEnumEntryImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            symbol = symbolRemapper.getDeclaredEnumEntry(declaration.symbol),
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            initializerExpression = declaration.initializerExpression?.transform()
            correspondingClass = declaration.correspondingClass?.transform()
            processAttributes(declaration)
        }

    override fun visitField(declaration: IrField): IrField =
        IrFieldImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            isExternal = declaration.isExternal,
            visibility = declaration.visibility,
            symbol = symbolRemapper.getDeclaredField(declaration.symbol),
            type = declaration.type.remapType(),
            isFinal = declaration.isFinal,
            isStatic = declaration.isStatic,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            initializer = declaration.initializer?.transform()
            correspondingPropertySymbol = declaration.correspondingPropertySymbol?.let(symbolRemapper::getReferencedProperty)
            processAttributes(declaration)
        }

    override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrLocalDelegatedProperty =
        IrLocalDelegatedPropertyImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            symbol = symbolRemapper.getDeclaredLocalDelegatedProperty(declaration.symbol),
            type = declaration.type.remapType(),
            isVar = declaration.isVar,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            delegate = declaration.delegate.transform()
            getter = declaration.getter.transform()
            setter = declaration.setter?.transform()
            processAttributes(declaration)
        }

    override fun visitModuleFragment(declaration: IrModuleFragment): IrModuleFragment =
        IrModuleFragmentImpl(
            descriptor = declaration.descriptor,
        ).apply {
            this@DeepCopyIrTreeWithSymbols.transformedModule = this
            files.assignFrom(declaration.files) { it.transform() }
            this@DeepCopyIrTreeWithSymbols.transformedModule = null
            processAttributes(declaration)
        }

    override fun visitProperty(declaration: IrProperty): IrProperty =
        IrPropertyImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            isExternal = declaration.isExternal,
            visibility = declaration.visibility,
            modality = declaration.modality,
            isFakeOverride = declaration.isFakeOverride,
            containerSource = declaration.containerSource,
            symbol = symbolRemapper.getDeclaredProperty(declaration.symbol),
            isVar = declaration.isVar,
            isConst = declaration.isConst,
            isLateinit = declaration.isLateinit,
            isDelegated = declaration.isDelegated,
            isExpect = declaration.isExpect,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            overriddenSymbols = declaration.overriddenSymbols.memoryOptimizedMap { symbolRemapper.getReferencedProperty(it) }
            backingField = declaration.backingField?.transform()
            getter = declaration.getter?.transform()
            setter = declaration.setter?.transform()
            processAttributes(declaration)
        }

    override fun visitScript(declaration: IrScript): IrScript =
        IrScriptImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            factory = declaration.factory,
            name = declaration.name,
            symbol = symbolRemapper.getDeclaredScript(declaration.symbol),
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            statements.assignFrom(declaration.statements) { it.transform() }
            thisReceiver = declaration.thisReceiver?.transform()
            explicitCallParameters = declaration.explicitCallParameters.memoryOptimizedMap { it.transform() }
            implicitReceiversParameters = declaration.implicitReceiversParameters.memoryOptimizedMap { it.transform() }
            providedPropertiesParameters = declaration.providedPropertiesParameters.memoryOptimizedMap { it.transform() }
            resultProperty = declaration.resultProperty?.let(symbolRemapper::getReferencedProperty)
            earlierScriptsParameter = declaration.earlierScriptsParameter?.transform()
            importedScripts = declaration.importedScripts?.memoryOptimizedMap { symbolRemapper.getReferencedScript(it) }
            earlierScripts = declaration.earlierScripts?.memoryOptimizedMap { symbolRemapper.getReferencedScript(it) }
            targetClass = declaration.targetClass?.let(symbolRemapper::getReferencedClass)
            processAttributes(declaration)
        }

    override fun visitReplSnippet(declaration: IrReplSnippet): IrReplSnippet =
        IrReplSnippetImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            factory = declaration.factory,
            name = declaration.name,
            symbol = symbolRemapper.getDeclaredReplSnippet(declaration.symbol),
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            receiverParameters = declaration.receiverParameters.memoryOptimizedMap { it.transform() }
            variablesFromOtherSnippets.assignFrom(declaration.variablesFromOtherSnippets) { it.transform() }
            declarationsFromOtherSnippets.assignFrom(declaration.declarationsFromOtherSnippets) { it.transform() }
            stateObject = declaration.stateObject?.let(symbolRemapper::getReferencedClass)
            body = declaration.body.transform()
            returnType = declaration.returnType?.remapType()
            targetClass = declaration.targetClass?.let(symbolRemapper::getReferencedClass)
            processAttributes(declaration)
        }

    override fun visitSimpleFunction(declaration: IrSimpleFunction): IrSimpleFunction =
        IrFunctionImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            isExternal = declaration.isExternal,
            visibility = declaration.visibility,
            containerSource = declaration.containerSource,
            isInline = declaration.isInline,
            isExpect = declaration.isExpect,
            modality = declaration.modality,
            isFakeOverride = declaration.isFakeOverride,
            symbol = symbolRemapper.getDeclaredSimpleFunction(declaration.symbol),
            isTailrec = declaration.isTailrec,
            isSuspend = declaration.isSuspend,
            isOperator = declaration.isOperator,
            isInfix = declaration.isInfix,
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            typeParameters = declaration.typeParameters.memoryOptimizedMap { it.transform() }
            returnType = declaration.returnType.remapType()
            body = declaration.body?.transform()
            overriddenSymbols = declaration.overriddenSymbols.memoryOptimizedMap { symbolRemapper.getReferencedSimpleFunction(it) }
            correspondingPropertySymbol = declaration.correspondingPropertySymbol?.let(symbolRemapper::getReferencedProperty)
            parameters = declaration.parameters.memoryOptimizedMap { it.transform() }
            processAttributes(declaration)
        }

    override fun visitTypeAlias(declaration: IrTypeAlias): IrTypeAlias =
        IrTypeAliasImpl(
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            factory = declaration.factory,
            name = declaration.name,
            visibility = declaration.visibility,
            symbol = symbolRemapper.getDeclaredTypeAlias(declaration.symbol),
            isActual = declaration.isActual,
            expandedType = declaration.expandedType.remapType(),
        ).apply {
            with(factory) { declarationCreated() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            typeParameters = declaration.typeParameters.memoryOptimizedMap { it.transform() }
            processAttributes(declaration)
        }

    override fun visitVariable(declaration: IrVariable): IrVariable =
        IrVariableImpl(
            constructorIndicator = null,
            startOffset = declaration.startOffset,
            endOffset = declaration.endOffset,
            origin = declaration.origin,
            name = declaration.name,
            type = declaration.type.remapType(),
            symbol = symbolRemapper.getDeclaredVariable(declaration.symbol),
            isVar = declaration.isVar,
            isConst = declaration.isConst,
            isLateinit = declaration.isLateinit,
        ).apply {
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            initializer = declaration.initializer?.transform()
            processAttributes(declaration)
        }

    override fun visitExternalPackageFragment(declaration: IrExternalPackageFragment): IrExternalPackageFragment =
        IrExternalPackageFragmentImpl(
            packageFqName = declaration.packageFqName,
            symbol = symbolRemapper.getDeclaredExternalPackageFragment(declaration.symbol),
        ).apply {
            declarations.assignFrom(declaration.declarations) { it.transform() }
            processAttributes(declaration)
        }

    override fun visitFile(declaration: IrFile): IrFile =
        IrFileImpl(
            packageFqName = declaration.packageFqName,
            symbol = symbolRemapper.getDeclaredFile(declaration.symbol),
            fileEntry = declaration.fileEntry,
        ).apply {
            declarations.assignFrom(declaration.declarations) { it.transform() }
            annotations = declaration.annotations.memoryOptimizedMap { it.transform() }
            module = transformedModule ?: declaration.module
            processAttributes(declaration)
        }

    override fun visitExpressionBody(body: IrExpressionBody): IrExpressionBody =
        IrExpressionBodyImpl(
            constructorIndicator = null,
            startOffset = body.startOffset,
            endOffset = body.endOffset,
            expression = body.expression.transform(),
        ).apply {
            processAttributes(body)
        }

    override fun visitBlockBody(body: IrBlockBody): IrBlockBody =
        IrBlockBodyImpl(
            constructorIndicator = null,
            startOffset = body.startOffset,
            endOffset = body.endOffset,
        ).apply {
            statements.assignFrom(body.statements) { it.transform() }
            processAttributes(body)
        }

    override fun visitConstructorCall(expression: IrConstructorCall): IrConstructorCall =
        IrConstructorCallImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getReferencedConstructor(expression.symbol),
            source = expression.source,
            constructorTypeArgumentsCount = expression.constructorTypeArgumentsCount,
        ).apply {
            copyRemappedTypeArgumentsFrom(expression)
            transformValueArguments(expression)
            processAttributes(expression)
        }

    override fun visitGetObjectValue(expression: IrGetObjectValue): IrGetObjectValue =
        IrGetObjectValueImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedClass(expression.symbol),
        ).apply {
            processAttributes(expression)
        }

    override fun visitGetEnumValue(expression: IrGetEnumValue): IrGetEnumValue =
        IrGetEnumValueImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedEnumEntry(expression.symbol),
        ).apply {
            processAttributes(expression)
        }

    override fun visitRawFunctionReference(expression: IrRawFunctionReference): IrRawFunctionReference =
        IrRawFunctionReferenceImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedFunction(expression.symbol),
        ).apply {
            processAttributes(expression)
        }

    override fun visitBlock(expression: IrBlock): IrBlock =
        IrBlockImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
        ).apply {
            statements.assignFrom(expression.statements) { it.transform() }
            processAttributes(expression)
        }

    override fun visitComposite(expression: IrComposite): IrComposite =
        IrCompositeImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
        ).apply {
            statements.assignFrom(expression.statements) { it.transform() }
            processAttributes(expression)
        }

    override fun visitReturnableBlock(expression: IrReturnableBlock): IrReturnableBlock =
        IrReturnableBlockImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getDeclaredReturnableBlock(expression.symbol),
        ).apply {
            statements.assignFrom(expression.statements) { it.transform() }
            processAttributes(expression)
        }

    override fun visitInlinedFunctionBlock(inlinedBlock: IrInlinedFunctionBlock): IrInlinedFunctionBlock =
        IrInlinedFunctionBlockImpl(
            constructorIndicator = null,
            startOffset = inlinedBlock.startOffset,
            endOffset = inlinedBlock.endOffset,
            type = inlinedBlock.type.remapType(),
            origin = inlinedBlock.origin,
            inlinedFunctionStartOffset = inlinedBlock.inlinedFunctionStartOffset,
            inlinedFunctionEndOffset = inlinedBlock.inlinedFunctionEndOffset,
            inlinedFunctionSymbol = inlinedBlock.inlinedFunctionSymbol?.let(symbolRemapper::getReferencedFunction),
            inlinedFunctionFileEntry = inlinedBlock.inlinedFunctionFileEntry,
        ).apply {
            statements.assignFrom(inlinedBlock.statements) { it.transform() }
            processAttributes(inlinedBlock)
        }

    override fun visitSyntheticBody(body: IrSyntheticBody): IrSyntheticBody =
        IrSyntheticBodyImpl(
            constructorIndicator = null,
            startOffset = body.startOffset,
            endOffset = body.endOffset,
            kind = body.kind,
        ).apply {
            processAttributes(body)
        }

    override fun visitBreak(jump: IrBreak): IrBreak =
        IrBreakImpl(
            constructorIndicator = null,
            startOffset = jump.startOffset,
            endOffset = jump.endOffset,
            type = jump.type.remapType(),
            loop = transformedLoops.getOrDefault(jump.loop, jump.loop),
        ).apply {
            label = jump.label
            processAttributes(jump)
        }

    override fun visitContinue(jump: IrContinue): IrContinue =
        IrContinueImpl(
            constructorIndicator = null,
            startOffset = jump.startOffset,
            endOffset = jump.endOffset,
            type = jump.type.remapType(),
            loop = transformedLoops.getOrDefault(jump.loop, jump.loop),
        ).apply {
            label = jump.label
            processAttributes(jump)
        }

    override fun visitCall(expression: IrCall): IrCall =
        IrCallImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getReferencedSimpleFunction(expression.symbol),
            superQualifierSymbol = expression.superQualifierSymbol?.let(symbolRemapper::getReferencedClass),
        ).apply {
            copyRemappedTypeArgumentsFrom(expression)
            transformValueArguments(expression)
            processAttributes(expression)
        }

    override fun visitFunctionReference(expression: IrFunctionReference): IrFunctionReference =
        IrFunctionReferenceImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getReferencedFunction(expression.symbol),
            reflectionTarget = expression.reflectionTarget?.let(symbolRemapper::getReferencedFunction),
        ).apply {
            copyRemappedTypeArgumentsFrom(expression)
            transformValueArguments(expression)
            processAttributes(expression)
        }

    override fun visitPropertyReference(expression: IrPropertyReference): IrPropertyReference =
        IrPropertyReferenceImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getReferencedProperty(expression.symbol),
            field = expression.field?.let(symbolRemapper::getReferencedField),
            getter = expression.getter?.let(symbolRemapper::getReferencedSimpleFunction),
            setter = expression.setter?.let(symbolRemapper::getReferencedSimpleFunction),
        ).apply {
            copyRemappedTypeArgumentsFrom(expression)
            transformValueArguments(expression)
            processAttributes(expression)
        }

    override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrLocalDelegatedPropertyReference =
        IrLocalDelegatedPropertyReferenceImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getReferencedLocalDelegatedProperty(expression.symbol),
            delegate = symbolRemapper.getReferencedVariable(expression.delegate),
            getter = symbolRemapper.getReferencedSimpleFunction(expression.getter),
            setter = expression.setter?.let(symbolRemapper::getReferencedSimpleFunction),
        ).apply {
            processAttributes(expression)
        }

    override fun visitRichFunctionReference(expression: IrRichFunctionReference): IrRichFunctionReference =
        IrRichFunctionReferenceImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            reflectionTargetSymbol = expression.reflectionTargetSymbol?.let(symbolRemapper::getReferencedFunction),
            origin = expression.origin,
            overriddenFunctionSymbol = symbolRemapper.getReferencedSimpleFunction(expression.overriddenFunctionSymbol),
            invokeFunction = expression.invokeFunction.transform(),
            hasUnitConversion = expression.hasUnitConversion,
            hasSuspendConversion = expression.hasSuspendConversion,
            hasVarargConversion = expression.hasVarargConversion,
            isRestrictedSuspension = expression.isRestrictedSuspension,
        ).apply {
            boundValues.assignFrom(expression.boundValues) { it.transform() }
            processAttributes(expression)
        }

    override fun visitRichPropertyReference(expression: IrRichPropertyReference): IrRichPropertyReference =
        IrRichPropertyReferenceImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            reflectionTargetSymbol = expression.reflectionTargetSymbol?.let(symbolRemapper::getReferencedDeclarationWithAccessors),
            origin = expression.origin,
            getterFunction = expression.getterFunction.transform(),
            setterFunction = expression.setterFunction?.transform(),
        ).apply {
            boundValues.assignFrom(expression.boundValues) { it.transform() }
            processAttributes(expression)
        }

    override fun visitClassReference(expression: IrClassReference): IrClassReference =
        IrClassReferenceImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedClassifier(expression.symbol),
            classType = expression.classType.remapType(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitConst(expression: IrConst): IrConst =
        IrConstImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            kind = expression.kind,
            value = expression.value,
        ).apply {
            processAttributes(expression)
        }

    override fun visitConstantPrimitive(expression: IrConstantPrimitive): IrConstantPrimitive =
        IrConstantPrimitiveImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            value = expression.value.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitConstantObject(expression: IrConstantObject): IrConstantObject =
        IrConstantObjectImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            constructor = symbolRemapper.getReferencedConstructor(expression.constructor),
        ).apply {
            valueArguments.assignFrom(expression.valueArguments) { it.transform() }
            typeArguments.assignFrom(expression.typeArguments) { it.remapType() }
            processAttributes(expression)
        }

    override fun visitConstantArray(expression: IrConstantArray): IrConstantArray =
        IrConstantArrayImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
        ).apply {
            elements.assignFrom(expression.elements) { it.transform() }
            processAttributes(expression)
        }

    override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrDelegatingConstructorCall =
        IrDelegatingConstructorCallImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getReferencedConstructor(expression.symbol),
        ).apply {
            copyRemappedTypeArgumentsFrom(expression)
            transformValueArguments(expression)
            processAttributes(expression)
        }

    override fun visitDynamicOperatorExpression(expression: IrDynamicOperatorExpression): IrDynamicOperatorExpression =
        IrDynamicOperatorExpressionImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            operator = expression.operator,
        ).apply {
            receiver = expression.receiver.transform()
            arguments.assignFrom(expression.arguments) { it.transform() }
            processAttributes(expression)
        }

    override fun visitDynamicMemberExpression(expression: IrDynamicMemberExpression): IrDynamicMemberExpression =
        IrDynamicMemberExpressionImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            memberName = expression.memberName,
            receiver = expression.receiver.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrEnumConstructorCall =
        IrEnumConstructorCallImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            symbol = symbolRemapper.getReferencedConstructor(expression.symbol),
        ).apply {
            copyRemappedTypeArgumentsFrom(expression)
            transformValueArguments(expression)
            processAttributes(expression)
        }

    override fun visitErrorExpression(expression: IrErrorExpression): IrErrorExpression =
        IrErrorExpressionImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            description = expression.description,
        ).apply {
            processAttributes(expression)
        }

    override fun visitErrorCallExpression(expression: IrErrorCallExpression): IrErrorCallExpression =
        IrErrorCallExpressionImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            description = expression.description,
        ).apply {
            explicitReceiver = expression.explicitReceiver?.transform()
            arguments.assignFrom(expression.arguments) { it.transform() }
            processAttributes(expression)
        }

    override fun visitGetField(expression: IrGetField): IrGetField =
        IrGetFieldImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedField(expression.symbol),
            superQualifierSymbol = expression.superQualifierSymbol?.let(symbolRemapper::getReferencedClass),
            origin = expression.origin,
        ).apply {
            receiver = expression.receiver?.transform()
            processAttributes(expression)
        }

    override fun visitSetField(expression: IrSetField): IrSetField =
        IrSetFieldImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedField(expression.symbol),
            superQualifierSymbol = expression.superQualifierSymbol?.let(symbolRemapper::getReferencedClass),
            origin = expression.origin,
        ).apply {
            receiver = expression.receiver?.transform()
            value = expression.value.transform()
            processAttributes(expression)
        }

    override fun visitFunctionExpression(expression: IrFunctionExpression): IrFunctionExpression =
        IrFunctionExpressionImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
            function = expression.function.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitGetClass(expression: IrGetClass): IrGetClass =
        IrGetClassImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            argument = expression.argument.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrInstanceInitializerCall =
        IrInstanceInitializerCallImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            classSymbol = symbolRemapper.getReferencedClass(expression.classSymbol),
        ).apply {
            processAttributes(expression)
        }

    override fun visitWhileLoop(loop: IrWhileLoop): IrWhileLoop =
        IrWhileLoopImpl(
            constructorIndicator = null,
            startOffset = loop.startOffset,
            endOffset = loop.endOffset,
            type = loop.type.remapType(),
            origin = loop.origin,
        ).apply {
            transformedLoops[loop] = this
            body = loop.body?.transform()
            condition = loop.condition.transform()
            label = loop.label
            processAttributes(loop)
        }

    override fun visitDoWhileLoop(loop: IrDoWhileLoop): IrDoWhileLoop =
        IrDoWhileLoopImpl(
            constructorIndicator = null,
            startOffset = loop.startOffset,
            endOffset = loop.endOffset,
            type = loop.type.remapType(),
            origin = loop.origin,
        ).apply {
            transformedLoops[loop] = this
            body = loop.body?.transform()
            condition = loop.condition.transform()
            label = loop.label
            processAttributes(loop)
        }

    override fun visitReturn(expression: IrReturn): IrReturn =
        IrReturnImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            value = expression.value.transform(),
            returnTargetSymbol = symbolRemapper.getReferencedReturnTarget(expression.returnTargetSymbol),
        ).apply {
            processAttributes(expression)
        }

    override fun visitStringConcatenation(expression: IrStringConcatenation): IrStringConcatenation =
        IrStringConcatenationImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
        ).apply {
            arguments.assignFrom(expression.arguments) { it.transform() }
            processAttributes(expression)
        }

    override fun visitSuspensionPoint(expression: IrSuspensionPoint): IrSuspensionPoint =
        IrSuspensionPointImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            suspensionPointIdParameter = expression.suspensionPointIdParameter.transform(),
            result = expression.result.transform(),
            resumeResult = expression.resumeResult.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitSuspendableExpression(expression: IrSuspendableExpression): IrSuspendableExpression =
        IrSuspendableExpressionImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            suspensionPointId = expression.suspensionPointId.transform(),
            result = expression.result.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitThrow(expression: IrThrow): IrThrow =
        IrThrowImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            value = expression.value.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitTry(aTry: IrTry): IrTry =
        IrTryImpl(
            constructorIndicator = null,
            startOffset = aTry.startOffset,
            endOffset = aTry.endOffset,
            type = aTry.type.remapType(),
        ).apply {
            tryResult = aTry.tryResult.transform()
            catches.assignFrom(aTry.catches) { it.transform() }
            finallyExpression = aTry.finallyExpression?.transform()
            processAttributes(aTry)
        }

    override fun visitCatch(aCatch: IrCatch): IrCatch =
        IrCatchImpl(
            constructorIndicator = null,
            startOffset = aCatch.startOffset,
            endOffset = aCatch.endOffset,
            catchParameter = aCatch.catchParameter.transform(),
            origin = aCatch.origin,
        ).apply {
            result = aCatch.result.transform()
            processAttributes(aCatch)
        }

    override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall =
        IrTypeOperatorCallImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            operator = expression.operator,
            argument = expression.argument.transform(),
            typeOperand = expression.typeOperand.remapType(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitGetValue(expression: IrGetValue): IrGetValue =
        IrGetValueImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedValue(expression.symbol),
            origin = expression.origin,
        ).apply {
            processAttributes(expression)
        }

    override fun visitSetValue(expression: IrSetValue): IrSetValue =
        IrSetValueImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            symbol = symbolRemapper.getReferencedValue(expression.symbol),
            origin = expression.origin,
            value = expression.value.transform(),
        ).apply {
            processAttributes(expression)
        }

    override fun visitVararg(expression: IrVararg): IrVararg =
        IrVarargImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            varargElementType = expression.varargElementType.remapType(),
        ).apply {
            elements.assignFrom(expression.elements) { it.transform() }
            processAttributes(expression)
        }

    override fun visitSpreadElement(spread: IrSpreadElement): IrSpreadElement =
        IrSpreadElementImpl(
            constructorIndicator = null,
            startOffset = spread.startOffset,
            endOffset = spread.endOffset,
            expression = spread.expression.transform(),
        ).apply {
            processAttributes(spread)
        }

    override fun visitWhen(expression: IrWhen): IrWhen =
        IrWhenImpl(
            constructorIndicator = null,
            startOffset = expression.startOffset,
            endOffset = expression.endOffset,
            type = expression.type.remapType(),
            origin = expression.origin,
        ).apply {
            branches.assignFrom(expression.branches) { it.transform() }
            processAttributes(expression)
        }

    override fun visitBranch(branch: IrBranch): IrBranch =
        IrBranchImpl(
            constructorIndicator = null,
            startOffset = branch.startOffset,
            endOffset = branch.endOffset,
            condition = branch.condition.transform(),
            result = branch.result.transform(),
        ).apply {
            processAttributes(branch)
        }

    override fun visitElseBranch(branch: IrElseBranch): IrElseBranch =
        IrElseBranchImpl(
            constructorIndicator = null,
            startOffset = branch.startOffset,
            endOffset = branch.endOffset,
            condition = branch.condition.transform(),
            result = branch.result.transform(),
        ).apply {
            processAttributes(branch)
        }
}
