All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.js.translate.callTranslator.VariableCallCases.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jetbrains.kotlin.js.translate.callTranslator

import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor
import org.jetbrains.kotlin.js.translate.declaration.contextWithPropertyMetadataCreationIntrinsified
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.reference.buildReifiedTypeArgs
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import java.util.*

object NativeVariableAccessCase : VariableAccessCase() {
    override fun VariableAccessInfo.extensionReceiver(): JsExpression {
        return constructAccessExpression(JsNameRef(variableName, extensionReceiver!!))
    }

    override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
        val descriptor = resolvedCall.resultingDescriptor
        return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
            val methodRef = context.getNameForDescriptor(getAccessDescriptorIfNeeded())
            JsInvocation(pureFqn(methodRef, dispatchReceiver!!), *additionalArguments.toTypedArray())
        }
        else {
            constructAccessExpression(JsNameRef(variableName, dispatchReceiver!!))
        }
    }

    override fun VariableAccessInfo.noReceivers(): JsExpression {
        val descriptor = resolvedCall.resultingDescriptor
        return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
            val methodRef = ReferenceTranslator.translateAsValueReference(getAccessDescriptorIfNeeded(), context)
            JsInvocation(methodRef, *additionalArguments.toTypedArray())
        }
        else {
            constructAccessExpression(context.getQualifiedReference(callableDescriptor))
        }
    }
}

object DefaultVariableAccessCase : VariableAccessCase() {
    override fun VariableAccessInfo.noReceivers(): JsExpression {
        val variableDescriptor = this.variableDescriptor

        if (variableDescriptor is PropertyDescriptor &&
            !JsDescriptorUtils.isSimpleFinalProperty(variableDescriptor) &&
            context.isFromCurrentModule(variableDescriptor)
        ) {
            val methodRef = context.getInnerReference(getAccessDescriptor())
            return JsInvocation(methodRef, *additionalArguments.toTypedArray())
        }

        val descriptor = resolvedCall.resultingDescriptor
        if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
            val methodRef = ReferenceTranslator.translateAsValueReference(getAccessDescriptorIfNeeded(), context)
            return JsInvocation(methodRef, *additionalArguments.toTypedArray())
        }

        if (descriptor is FakeCallableDescriptorForObject) {
            return ReferenceTranslator.translateAsValueReference(descriptor.getReferencedObject(), context)
        }

        val functionRef = ReferenceTranslator.translateAsValueReference(callableDescriptor, context)
        val ref = if (isVarCapturedInClosure(context.bindingContext(), callableDescriptor)) {
            getCapturedVarAccessor(functionRef)
        }
        else {
            functionRef.apply {
                if (isGetAccess()) {
                    sideEffects = SideEffectKind.DEPENDS_ON_STATE
                }
            }
        }

        val localVariableDescriptor = resolvedCall.resultingDescriptor as? LocalVariableDescriptor
        val accessorDescriptor = if (isGetAccess()) localVariableDescriptor?.getter else localVariableDescriptor?.setter
        val delegatedCall = accessorDescriptor?.let { context.bindingContext()[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, it] }
        if (delegatedCall != null) {
            val delegateContext = context.contextWithPropertyMetadataCreationIntrinsified(
                    delegatedCall, localVariableDescriptor!!, JsNullLiteral())
            val delegateContextWithArgs = if (!isGetAccess()) {
                val valueArg = delegatedCall.valueArgumentsByIndex!![2].arguments[0].getArgumentExpression()
                delegateContext.innerContextWithAliasesForExpressions(mapOf(valueArg to value!!))
            }
            else {
                delegateContext
            }
            val localVariableRef = context.getAliasForDescriptor(localVariableDescriptor) ?:
                                   JsAstUtils.pureFqn(context.getNameForDescriptor(localVariableDescriptor), null)
            return CallTranslator.translate(delegateContextWithArgs, delegatedCall, localVariableRef)
        }

        return constructAccessExpression(ref)
    }

    override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
        val descriptor = resolvedCall.resultingDescriptor
        return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
            val callExpr = pureFqn(context.getNameForDescriptor(getAccessDescriptorIfNeeded()), dispatchReceiver!!)
            JsInvocation(callExpr, *additionalArguments.toTypedArray())
        }
        else {
            val accessor = JsNameRef(variableName, dispatchReceiver!!)
            if (descriptor is PropertyDescriptor && !JsDescriptorUtils.sideEffectsPossibleOnRead(descriptor)) {
                accessor.sideEffects = SideEffectKind.DEPENDS_ON_STATE
            }
            constructAccessExpression(accessor)
        }
    }

    override fun VariableAccessInfo.extensionReceiver(): JsExpression {
        val functionRef = ReferenceTranslator.translateAsValueReference(getAccessDescriptorIfNeeded(), context)
        val reifiedTypeArguments = resolvedCall.typeArguments.buildReifiedTypeArgs(context)
        return  JsInvocation(functionRef, reifiedTypeArguments + listOf(extensionReceiver!!) + additionalArguments)
    }

    override fun VariableAccessInfo.bothReceivers(): JsExpression {
        val funRef = JsAstUtils.pureFqn(context.getNameForDescriptor(getAccessDescriptorIfNeeded()), dispatchReceiver!!)
        return JsInvocation(funRef, extensionReceiver!!, *additionalArguments.toTypedArray())
    }
}

object DelegatePropertyAccessIntrinsic : DelegateIntrinsic {
    override fun VariableAccessInfo.canBeApply(): Boolean {
        if(variableDescriptor is PropertyDescriptor) {
            return isGetAccess() || (variableDescriptor as PropertyDescriptor).isVar
        }
        return false
    }

    override fun VariableAccessInfo.getArgs(): List {
        return if (isGetAccess())
            Collections.emptyList()
        else
            Collections.singletonList(value!!)
    }

    override fun VariableAccessInfo.getDescriptor(): CallableDescriptor {
        val propertyDescriptor = variableDescriptor as PropertyDescriptor
        return if (isGetAccess()) {
            propertyDescriptor.getter!!
        } else {
            propertyDescriptor.setter!!
        }
    }
}

object SuperPropertyAccessCase : VariableAccessCase() {
    override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
        val variableName = JsStringLiteral(this.variableName.ident)
        val descriptor = resolvedCall.resultingDescriptor

        return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
            val accessor = getAccessDescriptorIfNeeded()
            val containingRef = ReferenceTranslator.translateAsValueReference(descriptor.containingDeclaration, context)
            val prototype = pureFqn(Namer.getPrototypeName(), containingRef)
            val funRef = Namer.getFunctionCallRef(pureFqn(context.getNameForDescriptor(accessor), prototype))
            val arguments = listOf(dispatchReceiver!!) + additionalArguments
            JsInvocation(funRef, *arguments.toTypedArray())
        }
        else {
            val callExpr = if (isGetAccess()) context.namer().callGetProperty else context.namer().callSetProperty
            val arguments = listOf(dispatchReceiver!!, JsAstUtils.prototypeOf(calleeOwner), variableName) + additionalArguments
            JsInvocation(callExpr, *arguments.toTypedArray())
        }
    }
}

private val VariableAccessInfo.additionalArguments: List get() = value?.let { listOf(it) }.orEmpty()

fun VariableAccessInfo.translateVariableAccess(): JsExpression {
    val intrinsic = DelegatePropertyAccessIntrinsic.intrinsic(this)

    return when {
        intrinsic != null ->
            intrinsic
        isSuperInvocation() ->
            SuperPropertyAccessCase.translate(this)
        isNative() ->
            NativeVariableAccessCase.translate(this)
        else ->
            DefaultVariableAccessCase.translate(this)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy