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

org.jetbrains.kotlin.load.kotlin.methodSignatureMapping.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2016 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.load.kotlin

import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.load.java.isFromJavaOrBuiltins
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.types.KotlinType

fun FunctionDescriptor.computeJvmDescriptor(withReturnType: Boolean = true)
        = StringBuilder().apply {
            append(if (this@computeJvmDescriptor is ConstructorDescriptor) "" else name.asString())
            append("(")

            valueParameters.forEach {
                appendErasedType(it.type)
            }

            append(")")

            if (withReturnType) {
                if (hasVoidReturnType(this@computeJvmDescriptor)) {
                    append("V")
                }
                else {
                    appendErasedType(returnType!!)
                }
            }
        }.toString()

// Boxing is only necessary for 'remove(E): Boolean' of a MutableCollection implementation
// Otherwise this method might clash with 'remove(I): E' defined in the java.util.List JDK interface (mapped to kotlin 'removeAt')
fun forceSingleValueParameterBoxing(f: FunctionDescriptor): Boolean {
    if (f.valueParameters.size != 1 || f.isFromJavaOrBuiltins() || f.name.asString() != "remove") return false
    if ((f.original.valueParameters.single().type.mapToJvmType() as? JvmType.Primitive)?.jvmPrimitiveType != JvmPrimitiveType.INT) return false

    val overridden =
            BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(f)
            ?: return false

    val overriddenParameterType = overridden.original.valueParameters.single().type.mapToJvmType()
    return overridden.containingDeclaration.fqNameUnsafe == KotlinBuiltIns.FQ_NAMES.mutableCollection.toUnsafe()
           && overriddenParameterType is JvmType.Object && overriddenParameterType.internalName == "java/lang/Object"
}

// This method only returns not-null for class methods
internal fun CallableDescriptor.computeJvmSignature(): String? = signatures {
    if (DescriptorUtils.isLocal(this@computeJvmSignature)) return null

    val classDescriptor = containingDeclaration as? ClassDescriptor ?: return null
    if (classDescriptor.name.isSpecial) return null

    signature(
            classDescriptor,
            (original as? SimpleFunctionDescriptor ?: return null).computeJvmDescriptor()
    )
}

internal val ClassDescriptor.internalName: String
    get() {
        JavaToKotlinClassMap.mapKotlinToJava(fqNameSafe.toUnsafe())?.let {
            return JvmClassName.byClassId(it).internalName
        }

        return computeInternalName(this)
    }

internal val ClassId.internalName: String
    get() {
        return JvmClassName.byClassId(JavaToKotlinClassMap.mapKotlinToJava(asSingleFqName().toUnsafe()) ?: this).internalName
    }

private fun StringBuilder.appendErasedType(type: KotlinType) {
    append(type.mapToJvmType())
}

internal fun KotlinType.mapToJvmType() =
        mapType(this, JvmTypeFactoryImpl, TypeMappingMode.DEFAULT, TypeMappingConfigurationImpl, descriptorTypeWriter = null)

sealed class JvmType {
    // null means 'void'
    class Primitive(val jvmPrimitiveType: JvmPrimitiveType?) : JvmType()
    class Object(val internalName: String) : JvmType()
    class Array(val elementType: JvmType) : JvmType()

    override fun toString() = JvmTypeFactoryImpl.toString(this)
}

private object JvmTypeFactoryImpl : JvmTypeFactory {
    override fun boxType(possiblyPrimitiveType: JvmType) =
            when {
                possiblyPrimitiveType is JvmType.Primitive && possiblyPrimitiveType.jvmPrimitiveType != null ->
                    createObjectType(
                            JvmClassName.byFqNameWithoutInnerClasses(
                                    possiblyPrimitiveType.jvmPrimitiveType.wrapperFqName).internalName)
                else -> possiblyPrimitiveType
            }

    override fun createFromString(representation: String): JvmType {
        assert(representation.length > 0) { "empty string as JvmType" }
        val firstChar = representation[0]

        JvmPrimitiveType.values().firstOrNull { it.desc[0] == firstChar }?.let {
            return JvmType.Primitive(it)
        }

        return when (firstChar) {
            'V' -> JvmType.Primitive(null)
            '[' -> JvmType.Array(createFromString(representation.substring(1)))
            else -> {
                assert(firstChar == 'L' && representation.endsWith(';')) {
                    "Type that is not primitive nor array should be Object, but '$representation' was found"
                }

                JvmType.Object(representation.substring(1, representation.length - 1))
            }
        }
    }

    override fun createObjectType(internalName: String) = JvmType.Object(internalName)

    override fun toString(type: JvmType): String =
            when (type) {
                is JvmType.Array -> "[" + toString(type.elementType)
                is JvmType.Primitive -> type.jvmPrimitiveType?.desc ?: "V"
                is JvmType.Object -> "L" + type.internalName + ";"
            }

    override val javaLangClassType: JvmType
        get() = createObjectType("java/lang/Class")

}

internal object TypeMappingConfigurationImpl : TypeMappingConfiguration {
    override fun commonSupertype(types: Collection): KotlinType {
        throw AssertionError("There should be no intersection type in existing descriptors, but found: " + types.joinToString())
    }

    override fun getPredefinedTypeForClass(classDescriptor: ClassDescriptor) = null
    override fun getPredefinedInternalNameForClass(classDescriptor: ClassDescriptor): String? = null

    override fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor) {
        // DO nothing
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy