Make JVM backend work with Collection.size as val

0. Such properties are called special because their accessor JVM name differs from usual one
1. When making call to such property, always choose special name
2. When generating Kotlin class inheriting such property generate `final bridge int size() { return this.getSize(); }`
3. If there is no `size` declaration in current class generate `bridge int getSize() { // super-call }`
This commit is contained in:
Denis Zharkov
2015-10-06 14:10:20 +03:00
parent 252c82abe3
commit 6a1566a6dc
18 changed files with 638 additions and 26 deletions
@@ -16,21 +16,65 @@
package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.utils.addToStdlib.check
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
private val BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES = setOf(FqName("kotlin.Collection.size"), FqName("kotlin.Map.size"))
private val BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES = BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES.map { it.shortName() }.toSet()
private fun DeclarationDescriptor.hasBuiltinSpecialPropertyFqName()
= name in BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES
&& fqNameUnsafe.check { it.isSafe }?.toSafe() in BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES
public fun CallableDescriptor.hasBuiltinSpecialPropertyFqName(): Boolean {
if (this is PropertyAccessorDescriptor) return correspondingProperty.hasBuiltinSpecialPropertyFqName()
if (name !in BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES) return false
return hasBuiltinSpecialPropertyFqNameImpl()
}
private fun CallableDescriptor.hasBuiltinSpecialPropertyFqNameImpl(): Boolean {
if (fqNameUnsafe.check { it.isSafe }?.toSafe() in BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES) return true
if (!fqNameUnsafe.firstSegmentIs(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) return false
if (builtIns.builtInsModule != module) return false
return overriddenDescriptors.any(CallableDescriptor::hasBuiltinSpecialPropertyFqName)
}
val Name.isBuiltinSpecialPropertyName: Boolean get() = this in BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES
val PropertyDescriptor.builtinSpecialOverridden: PropertyDescriptor?
get() = check { hasBuiltinSpecialPropertyFqName() } ?: overriddenDescriptors.firstNotNullResult { it.builtinSpecialOverridden }
private val CallableDescriptor.builtinSpecialPropertyAccessorName: String?
get() = when(this) {
is PropertyAccessorDescriptor -> correspondingProperty.check { it.hasBuiltinSpecialPropertyFqName() }?.name?.asString()
else -> null
}
@Suppress("UNCHECKED_CAST")
val <T : CallableDescriptor> T.builtinSpecialOverridden: T? get() {
return when (this) {
is PropertyAccessorDescriptor -> check { correspondingProperty.hasBuiltinSpecialPropertyFqName() }
?: overriddenDescriptors.firstNotNullResult { it.builtinSpecialOverridden } as T?
is PropertyDescriptor -> check { hasBuiltinSpecialPropertyFqName() }
?: overriddenDescriptors.firstNotNullResult { it.builtinSpecialOverridden } as T?
else -> null
}
}
fun CallableDescriptor.overridesBuiltinSpecialDeclaration(): Boolean = builtinSpecialOverridden != null
public val CallableDescriptor.jvmMethodNameIfSpecial: String?
get() = builtinOverriddenThatAffectsJvmName?.builtinSpecialPropertyAccessorName
public val CallableDescriptor.builtinOverriddenThatAffectsJvmName: CallableDescriptor?
get() = if (hasBuiltinSpecialPropertyFqName() || isFromJava) builtinSpecialOverridden else null
private val CallableDescriptor.isFromJava: Boolean
get() = propertyIfAccessor is JavaCallableMemberDescriptor
private val CallableDescriptor.propertyIfAccessor: CallableDescriptor
get() = if (this is PropertyAccessorDescriptor) correspondingProperty else this