Transform CharSequence.length to property
This commit is contained in:
committed by
Mikhail Glukhikh
parent
6c0d55e4ed
commit
1305d9755a
-1
@@ -98,7 +98,6 @@ internal val unaryOperations: HashMap<UnaryOperationKey<*>, Pair<Function1<Any?,
|
||||
unaryOperation(SHORT, "toLong", { a -> a.toLong() }, emptyUnaryFun),
|
||||
unaryOperation(SHORT, "toShort", { a -> a.toShort() }, emptyUnaryFun),
|
||||
unaryOperation(SHORT, "toString", { a -> a.toString() }, emptyUnaryFun),
|
||||
unaryOperation(STRING, "length", { a -> a.length() }, emptyUnaryFun),
|
||||
unaryOperation(STRING, "toString", { a -> a.toString() }, emptyUnaryFun)
|
||||
)
|
||||
|
||||
|
||||
+4
-2
@@ -262,8 +262,9 @@ public final class CharRange : kotlin.Range<kotlin.Char>, kotlin.Progression<kot
|
||||
}
|
||||
|
||||
public interface CharSequence {
|
||||
public abstract val length: kotlin.Int
|
||||
public abstract fun <get-length>(): kotlin.Int
|
||||
public abstract operator fun get(/*0*/ index: kotlin.Int): kotlin.Char
|
||||
public abstract fun length(): kotlin.Int
|
||||
public abstract fun subSequence(/*0*/ start: kotlin.Int, /*1*/ end: kotlin.Int): kotlin.CharSequence
|
||||
}
|
||||
|
||||
@@ -1247,9 +1248,10 @@ public final class ShortRange : kotlin.Range<kotlin.Short>, kotlin.Progression<k
|
||||
|
||||
public final class String : kotlin.Comparable<kotlin.String>, kotlin.CharSequence {
|
||||
/*primary*/ public constructor String()
|
||||
public open override /*1*/ val length: kotlin.Int
|
||||
public open override /*1*/ fun <get-length>(): kotlin.Int
|
||||
public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int
|
||||
public open override /*1*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
|
||||
public open override /*1*/ fun length(): kotlin.Int
|
||||
public final operator fun plus(/*0*/ other: kotlin.Any?): kotlin.String
|
||||
public open override /*1*/ fun subSequence(/*0*/ start: kotlin.Int, /*1*/ end: kotlin.Int): kotlin.CharSequence
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import java.util.*;
|
||||
public class J {
|
||||
|
||||
public static class B extends A {
|
||||
public int getLength() { return 456; }
|
||||
public char get(int index) {
|
||||
if (index == 1) return 'a';
|
||||
return super.get(index);
|
||||
@@ -13,6 +14,10 @@ public class J {
|
||||
B b = new B();
|
||||
CharSequence cs = (CharSequence) b;
|
||||
|
||||
if (cs.length() != 456) return "fail 01";
|
||||
if (b.length() != 456) return "fail 02";
|
||||
if (b.getLength() != 456) return "fail 03";
|
||||
|
||||
if (cs.charAt(0) != 'z') return "fail 1";
|
||||
if (b.get(0) != 'z') return "fail 2";
|
||||
|
||||
|
||||
+9
-3
@@ -1,7 +1,5 @@
|
||||
open class A : CharSequence {
|
||||
override fun length(): Int {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
override val length: Int = 123
|
||||
|
||||
override fun get(index: Int) = 'z';
|
||||
|
||||
@@ -24,5 +22,13 @@ fun box(): String {
|
||||
if (b.get(1) != 'a') return "fail 12"
|
||||
if (a.get(1) != 'z') return "fail 13"
|
||||
|
||||
var cs: CharSequence = a
|
||||
if (a.length != 123) return "fail 14"
|
||||
if (cs.length != 123) return "fail 15"
|
||||
|
||||
cs = b
|
||||
if (b.length != 456) return "fail 16"
|
||||
if (b.length != 456) return "fail 17"
|
||||
|
||||
return J.foo();
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ public final class JSub : java.lang.CharSequence {
|
||||
|
||||
public final class Sub : kotlin.CharSequence {
|
||||
public constructor Sub()
|
||||
public abstract override /*1*/ /*fake_override*/ val length: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun length(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun subSequence(/*0*/ start: kotlin.Int, /*1*/ end: kotlin.Int): kotlin.CharSequence
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
+5
@@ -1,17 +1,20 @@
|
||||
// FILE: A.java
|
||||
abstract public class A implements CharSequence {
|
||||
public char charAt(int x) { }
|
||||
public int length() { return 1; }
|
||||
}
|
||||
|
||||
// FILE: C.java
|
||||
abstract public class C implements CharSequence {
|
||||
public char get(int x) { }
|
||||
public int length() { return 1; }
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
abstract class B : A(), CharSequence {
|
||||
override operator fun get(index: Int) = '1'
|
||||
override val length: Int get() = 1
|
||||
}
|
||||
|
||||
fun main(a: A, b: B, c: C) {
|
||||
@@ -22,4 +25,6 @@ fun main(a: A, b: B, c: C) {
|
||||
a.get(0)
|
||||
b.get(0)
|
||||
c.get(0)
|
||||
|
||||
a.length + b.length + c.length
|
||||
}
|
||||
|
||||
+3
-3
@@ -4,30 +4,30 @@ public fun main(/*0*/ a: A, /*1*/ b: B, /*2*/ c: C): kotlin.Unit
|
||||
|
||||
public abstract class A : kotlin.CharSequence {
|
||||
public constructor A()
|
||||
public open override /*1*/ val length: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ fun get(/*0*/ x: kotlin.Int): kotlin.Char
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun length(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun subSequence(/*0*/ start: kotlin.Int, /*1*/ end: kotlin.Int): kotlin.CharSequence
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public abstract class B : A, kotlin.CharSequence {
|
||||
public constructor B()
|
||||
public open override /*2*/ val length: kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*2*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract override /*2*/ /*fake_override*/ fun length(): kotlin.Int
|
||||
public abstract override /*2*/ /*fake_override*/ fun subSequence(/*0*/ start: kotlin.Int, /*1*/ end: kotlin.Int): kotlin.CharSequence
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public abstract class C : kotlin.CharSequence {
|
||||
public constructor C()
|
||||
public open override /*1*/ val length: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun length(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun subSequence(/*0*/ start: kotlin.Int, /*1*/ end: kotlin.Int): kotlin.CharSequence
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
+2
-1
@@ -5,8 +5,9 @@ package test
|
||||
}
|
||||
|
||||
public interface Foo</*0*/ T : @test.A() kotlin.Number> : @test.A() kotlin.CharSequence {
|
||||
public abstract override /*1*/ /*fake_override*/ val length: kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun <get-length>(): kotlin.Int
|
||||
public abstract fun </*0*/ E, /*1*/ F : @test.A() E> bar(): kotlin.Unit
|
||||
public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
|
||||
public abstract override /*1*/ /*fake_override*/ fun length(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun subSequence(/*0*/ start: kotlin.Int, /*1*/ end: kotlin.Int): kotlin.CharSequence
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public interface CharSequence {
|
||||
/**
|
||||
* Returns the length of this character sequence.
|
||||
*/
|
||||
public fun length(): Int
|
||||
public val length: Int
|
||||
|
||||
/**
|
||||
* Returns the character at the specified [index] in the sequence.
|
||||
|
||||
@@ -28,7 +28,7 @@ public class String : Comparable<String>, CharSequence {
|
||||
*/
|
||||
public operator fun plus(other: Any?): String
|
||||
|
||||
public override fun length(): Int
|
||||
public override val length: Int
|
||||
|
||||
public override fun get(index: Int): Char
|
||||
|
||||
|
||||
+8
-24
@@ -25,8 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.isBuiltinSpecialPropertyName
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getBuiltinSpecialPropertyAccessorName
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getBuiltinSpecialPropertyGetterName
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialMethods.sameAsRenamedInJvmBuiltin
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialMethods.isRemoveAtByIndex
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialJvmSignature.sameAsBuiltinMethodWithErasedValueParameters
|
||||
@@ -86,25 +85,13 @@ public class LazyJavaClassMemberScope(
|
||||
}
|
||||
|
||||
override fun JavaMethodDescriptor.isVisibleAsFunction(): Boolean {
|
||||
val nameAsString = name.asString()
|
||||
|
||||
if (JvmAbi.isGetterName(nameAsString)) {
|
||||
val propertyName = propertyNameByGetMethodName(name) ?: return true
|
||||
return !doesClassOverrideAnyProperty(getPropertiesFromSupertypes(propertyName))
|
||||
}
|
||||
|
||||
if (JvmAbi.isSetterName(nameAsString)) {
|
||||
return propertyNamesBySetMethodName(name).none {
|
||||
propertyName ->
|
||||
getPropertiesFromSupertypes(propertyName).any {
|
||||
property -> property.isVar && doesClassOverridesProperty(property)
|
||||
}
|
||||
if (getPropertyNamesCandidatesByAccessorName(name).any {
|
||||
propertyName ->
|
||||
getPropertiesFromSupertypes(propertyName).any {
|
||||
property ->
|
||||
doesClassOverridesProperty(property) && (property.isVar || !JvmAbi.isSetterName(name.asString()))
|
||||
}
|
||||
}
|
||||
|
||||
if (name.isBuiltinSpecialPropertyName) {
|
||||
return !doesClassOverrideAnyProperty(getPropertiesFromSupertypes(name))
|
||||
}
|
||||
}) return false
|
||||
|
||||
val javaMethod = (source as? JavaSourceElement)?.javaElement as? JavaMethod
|
||||
if (javaMethod?.doesOverrideRenamedBuiltins() ?: false) {
|
||||
@@ -136,11 +123,8 @@ public class LazyJavaClassMemberScope(
|
||||
).result == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
|
||||
}
|
||||
|
||||
private fun doesClassOverrideAnyProperty(properties: Collection<PropertyDescriptor>)
|
||||
= properties.any { property -> doesClassOverridesProperty(property) }
|
||||
|
||||
private fun PropertyDescriptor.findGetterOverride(): JavaMethodDescriptor? {
|
||||
val getterName = getter?.getBuiltinSpecialOverridden()?.getBuiltinSpecialPropertyAccessorName() ?: JvmAbi.getterName(name.asString())
|
||||
val getterName = getter?.getBuiltinSpecialOverridden()?.getBuiltinSpecialPropertyGetterName() ?: JvmAbi.getterName(name.asString())
|
||||
return memberIndex().findMethodsByName(Name.identifier(getterName)).firstNotNullResult factory@{
|
||||
javaMethod ->
|
||||
val descriptor = resolveMethodToFunctionDescriptor(javaMethod)
|
||||
|
||||
+17
@@ -18,6 +18,9 @@ package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getPropertyNameCandidatesBySpecialGetterName
|
||||
|
||||
|
||||
fun propertyNameByGetMethodName(methodName: Name): Name?
|
||||
= propertyNameFromAccessorMethodName(methodName, "get") ?: propertyNameFromAccessorMethodName(methodName, "is", removePrefix = false)
|
||||
@@ -45,3 +48,17 @@ private fun propertyNameFromAccessorMethodName(methodName: Name, prefix: String,
|
||||
if (!Name.isValidIdentifier(name)) return null
|
||||
return Name.identifier(name)
|
||||
}
|
||||
|
||||
fun getPropertyNamesCandidatesByAccessorName(name: Name): List<Name> {
|
||||
val nameAsString = name.asString()
|
||||
|
||||
if (JvmAbi.isGetterName(nameAsString)) {
|
||||
return propertyNameByGetMethodName(name).singletonOrEmptyList()
|
||||
}
|
||||
|
||||
if (JvmAbi.isSetterName(nameAsString)) {
|
||||
return propertyNamesBySetMethodName(name)
|
||||
}
|
||||
|
||||
return getPropertyNameCandidatesBySpecialGetterName(name)
|
||||
}
|
||||
+24
-13
@@ -28,10 +28,20 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getBuiltinSpecialPropertyAccessorName
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getBuiltinSpecialPropertyGetterName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
|
||||
object BuiltinSpecialProperties {
|
||||
private val FQ_NAMES = setOf(FqName("kotlin.Collection.size"), FqName("kotlin.Map.size"))
|
||||
private val PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP = mapOf(
|
||||
FqName("kotlin.Collection.size") to Name.identifier("size"),
|
||||
FqName("kotlin.Map.size") to Name.identifier("size"),
|
||||
FqName("kotlin.CharSequence.length") to Name.identifier("length")
|
||||
)
|
||||
|
||||
private val GETTER_JVM_NAME_TO_PROPERTIES_SHORT_NAME_MAP: Map<Name, List<Name>> =
|
||||
PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP.getInversedShortNamesMap()
|
||||
|
||||
private val FQ_NAMES = PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP.keySet()
|
||||
private val SHORT_NAMES = FQ_NAMES.map { it.shortName() }.toSet()
|
||||
|
||||
fun hasBuiltinSpecialPropertyFqName(callableMemberDescriptor: CallableMemberDescriptor): Boolean {
|
||||
@@ -47,12 +57,14 @@ object BuiltinSpecialProperties {
|
||||
return overriddenDescriptors.any { hasBuiltinSpecialPropertyFqName(it) }
|
||||
}
|
||||
|
||||
val Name.isBuiltinSpecialPropertyName: Boolean get() = this in SHORT_NAMES
|
||||
fun getPropertyNameCandidatesBySpecialGetterName(name1: Name): List<Name> =
|
||||
GETTER_JVM_NAME_TO_PROPERTIES_SHORT_NAME_MAP[name1] ?: emptyList()
|
||||
|
||||
fun CallableMemberDescriptor.getBuiltinSpecialPropertyAccessorName(): String? {
|
||||
return propertyIfAccessor.check {
|
||||
hasBuiltinSpecialPropertyFqName(it)
|
||||
}?.name?.asString()
|
||||
fun CallableMemberDescriptor.getBuiltinSpecialPropertyGetterName(): String? {
|
||||
assert(isFromBuiltins()) { "This method is defined only for builtin members, but $this found" }
|
||||
|
||||
val descriptor = propertyIfAccessor.firstOverridden { hasBuiltinSpecialPropertyFqName(it) } ?: return null
|
||||
return PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP[descriptor.fqNameSafe]?.asString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +127,7 @@ object BuiltinSpecialMethods {
|
||||
|
||||
val ORIGINAL_SHORT_NAMES: List<Name> = FQ_NAMES_TO_JVM_MAP.keySet().map { it.shortName() }
|
||||
|
||||
private val JVM_SHORT_NAME_TO_BUILTIN_FQ_NAMES_MAP: Map<Name, List<FqName>> =
|
||||
FQ_NAMES_TO_JVM_MAP.entrySet().groupBy { it.value }.mapValues { entry -> entry.value.map { it.key } }
|
||||
|
||||
val JVM_SHORT_NAME_TO_BUILTIN_SHORT_NAMES_MAP: Map<Name, List<Name>> =
|
||||
JVM_SHORT_NAME_TO_BUILTIN_FQ_NAMES_MAP.mapValues { it.value.map { it.shortName() } }
|
||||
val JVM_SHORT_NAME_TO_BUILTIN_SHORT_NAMES_MAP: Map<Name, List<Name>> = FQ_NAMES_TO_JVM_MAP.getInversedShortNamesMap()
|
||||
|
||||
val Name.sameAsRenamedInJvmBuiltin: Boolean
|
||||
get() = this in ORIGINAL_SHORT_NAMES
|
||||
@@ -157,7 +165,7 @@ fun getJvmMethodNameIfSpecial(callableMemberDescriptor: CallableMemberDescriptor
|
||||
val builtinOverridden = getBuiltinOverriddenThatAffectsJvmName(callableMemberDescriptor)?.propertyIfAccessor
|
||||
?: return null
|
||||
return when (builtinOverridden) {
|
||||
is PropertyDescriptor -> builtinOverridden.getBuiltinSpecialPropertyAccessorName()
|
||||
is PropertyDescriptor -> builtinOverridden.getBuiltinSpecialPropertyGetterName()
|
||||
else -> BuiltinSpecialMethods.getSpecialJvmName(builtinOverridden)?.asString()
|
||||
}
|
||||
}
|
||||
@@ -209,3 +217,6 @@ private fun CallableMemberDescriptor.firstOverridden(
|
||||
}
|
||||
|
||||
private fun CallableMemberDescriptor.isFromJavaOrBuiltins() = isFromJava || isFromBuiltins()
|
||||
|
||||
private fun Map<FqName, Name>.getInversedShortNamesMap(): Map<Name, List<Name>> =
|
||||
entrySet().groupBy { it.value }.mapValues { entry -> entry.value.map { it.key.shortName() } }
|
||||
@@ -31,6 +31,9 @@ public fun <E> MutableList<E>.remove(index: Int): E = removeAt(index)
|
||||
@Deprecated("Use explicit cast to MutableCollection<Any?> instead", ReplaceWith("(this as MutableCollection<Any?>).remove(o)"))
|
||||
public fun <E> MutableCollection<E>.remove(o: Any?): Boolean = remove(o as E)
|
||||
|
||||
@Deprecated("Use 'length' property instead", ReplaceWith("this.length"))
|
||||
public fun CharSequence.length(): Int = length
|
||||
|
||||
/**
|
||||
* Adds the specified [element] to this mutable collection.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user