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
@@ -69,7 +69,7 @@ public fun <Function : FunctionHandle, Signature> generateBridges(
return bridgesToGenerate.map { Bridge(it, method) }.toSet()
}
private fun <Function : FunctionHandle> findAllReachableDeclarations(function: Function): MutableSet<Function> {
public fun <Function : FunctionHandle> findAllReachableDeclarations(function: Function): MutableSet<Function> {
val collector = object : DFS.NodeHandlerWithListResult<Function, Function>() {
override fun afterChildren(current: Function) {
if (current.isDeclaration) {
@@ -86,7 +86,7 @@ private fun <Function : FunctionHandle> findAllReachableDeclarations(function: F
* Given a concrete function, finds an implementation (a concrete declaration) of this function in the supertypes.
* The implementation is guaranteed to exist because if it wouldn't, the given function would've been abstract
*/
private fun <Function : FunctionHandle> findConcreteSuperDeclaration(function: Function): Function {
public fun <Function : FunctionHandle> findConcreteSuperDeclaration(function: Function): Function {
require(!function.isAbstract, { "Only concrete functions have implementations: $function" })
if (function.isDeclaration) return function
@@ -47,7 +47,7 @@ public fun <Signature> generateBridgesForFunctionDescriptor(
* can generate a bridge near an implementation (of course, in case it has a super-declaration with a different signature). Ultimately this
* eases the process of determining what bridges are already generated in our supertypes and need to be inherited, not regenerated.
*/
private data class DescriptorBasedFunctionHandle(val descriptor: FunctionDescriptor) : FunctionHandle {
public data class DescriptorBasedFunctionHandle(val descriptor: FunctionDescriptor) : FunctionHandle {
private val overridden = descriptor.getOverriddenDescriptors().map { DescriptorBasedFunctionHandle(it.getOriginal()) }
override val isDeclaration: Boolean =
@@ -96,7 +96,6 @@ public abstract class ClassBodyCodegen extends MemberCodegen<JetClassOrObject> {
return !(declaration instanceof JetProperty || declaration instanceof JetNamedFunction);
}
protected void generateDeclaration(JetDeclaration declaration) {
if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
genFunctionOrProperty(declaration);
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
import org.jetbrains.kotlin.load.java.BuiltinsPropertiesUtilKt;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage;
import org.jetbrains.kotlin.name.FqName;
@@ -513,20 +514,53 @@ public class FunctionCodegen {
// If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
if (CallResolverUtilPackage.isOrOverridesSynthesized(descriptor)) return;
Set<Bridge<Method>> bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor(
descriptor,
new Function1<FunctionDescriptor, Method>() {
@Override
public Method invoke(FunctionDescriptor descriptor) {
return typeMapper.mapSignature(descriptor).getAsmMethod();
}
}
);
boolean isSpecial = BuiltinsPropertiesUtilKt.overridesBuiltinSpecialDeclaration(descriptor);
if (!bridgesToGenerate.isEmpty()) {
PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
for (Bridge<Method> bridge : bridgesToGenerate) {
generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo());
Set<Bridge<Method>> bridgesToGenerate;
if (!isSpecial) {
bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor(
descriptor,
new Function1<FunctionDescriptor, Method>() {
@Override
public Method invoke(FunctionDescriptor descriptor) {
return typeMapper.mapSignature(descriptor).getAsmMethod();
}
}
);
if (!bridgesToGenerate.isEmpty()) {
PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
for (Bridge<Method> bridge : bridgesToGenerate) {
generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), false, false);
}
}
}
else {
Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
descriptor,
new Function1<FunctionDescriptor, Method>() {
@Override
public Method invoke(FunctionDescriptor descriptor) {
return typeMapper.mapSignature(descriptor).getAsmMethod();
}
}
);
if (!specials.isEmpty()) {
PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
for (BridgeForBuiltinSpecial<Method> bridge : specials) {
generateBridge(
origin, descriptor, bridge.getFrom(), bridge.getTo(),
bridge.isSpecial(), bridge.isDelegateToSuper());
}
}
if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) {
CallableDescriptor overridden = BuiltinsPropertiesUtilKt.getBuiltinSpecialOverridden(descriptor);
assert overridden != null;
Method method = typeMapper.mapSignature(descriptor).getAsmMethod();
int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor);
v.newMethod(OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null);
}
}
}
@@ -760,9 +794,11 @@ public class FunctionCodegen {
@Nullable PsiElement origin,
@NotNull FunctionDescriptor descriptor,
@NotNull Method bridge,
@NotNull Method delegateTo
@NotNull Method delegateTo,
boolean isSpecialBridge,
boolean superCallNeeded
) {
int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialBridge ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO.
MethodVisitor mv =
v.newMethod(DiagnosticsPackage.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null);
@@ -783,7 +819,16 @@ public class FunctionCodegen {
reg += argTypes[i].getSize();
}
iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
if (superCallNeeded) {
ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration());
assert parentClass != null;
String parentInternalName = typeMapper.mapClass(parentClass).getInternalName();
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
}
else {
iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
}
StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
iv.areturn(bridge.getReturnType());
@@ -0,0 +1,120 @@
/*
* Copyright 2010-2015 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.codegen
import org.jetbrains.kotlin.backend.common.bridges.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.builtinSpecialOverridden
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
import org.jetbrains.kotlin.utils.singletonOrEmptyList
import java.util.*
class BridgeForBuiltinSpecial<Signature>(
val from: Signature, val to: Signature,
val isSpecial: Boolean = false,
val isDelegateToSuper: Boolean = false
)
object BuiltinSpecialBridgesUtil {
@JvmStatic
public fun <Signature> generateBridgesForBuiltinSpecial(
function: FunctionDescriptor,
signatureByDescriptor: (FunctionDescriptor) -> Signature
): Set<BridgeForBuiltinSpecial<Signature>> {
val functionHandle = DescriptorBasedFunctionHandle(function)
val fake = !functionHandle.isDeclaration
val overriddenBuiltin = function.builtinSpecialOverridden!!
val reachableDeclarations = findAllReachableDeclarations(function)
val needGenerateSpecialBridge = needGenerateSpecialBridge(function, reachableDeclarations, overriddenBuiltin)
// e.g. `getSize()I`
val methodItself = signatureByDescriptor(function)
// e.g. `size()I`
val overriddenBuiltinSignature = signatureByDescriptor(overriddenBuiltin)
val specialBridge = if (needGenerateSpecialBridge)
BridgeForBuiltinSpecial(overriddenBuiltinSignature, methodItself, isSpecial = true)
else null
val bridgesToGenerate = reachableDeclarations.mapTo(LinkedHashSet<Signature>(), signatureByDescriptor)
bridgesToGenerate.remove(overriddenBuiltinSignature)
bridgesToGenerate.remove(methodItself)
if (fake) {
for (overridden in function.overriddenDescriptors.map { it.original }) {
if (!DescriptorBasedFunctionHandle(overridden).isAbstract) {
bridgesToGenerate.removeAll(findAllReachableDeclarations(overridden).map(signatureByDescriptor))
}
}
}
val bridges: MutableSet<BridgeForBuiltinSpecial<Signature>> =
(bridgesToGenerate.map { BridgeForBuiltinSpecial(it, methodItself) } + specialBridge.singletonOrEmptyList()).toMutableSet()
if (function.modality == Modality.OPEN && fake) {
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function)).descriptor
if (!DescriptorUtils.isInterface(implementation.containingDeclaration)) {
bridges.add(BridgeForBuiltinSpecial(methodItself, signatureByDescriptor(implementation), isDelegateToSuper = true))
}
}
return bridges
}
}
private fun findAllReachableDeclarations(functionDescriptor: FunctionDescriptor): MutableSet<FunctionDescriptor> =
findAllReachableDeclarations(DescriptorBasedFunctionHandle(functionDescriptor)).map { it.descriptor }.toMutableSet()
private fun needGenerateSpecialBridge(
functionDescriptor: FunctionDescriptor,
reachableDeclarations: Collection<FunctionDescriptor>,
specialCallableDescriptor: CallableDescriptor
): Boolean {
val classDescriptor = functionDescriptor.containingDeclaration as ClassDescriptor
val builtinContainerDefaultType = (specialCallableDescriptor.containingDeclaration as ClassDescriptor).defaultType
var superClassDescriptor = DescriptorUtils.getSuperClassDescriptor(classDescriptor)
while (superClassDescriptor != null) {
val implementsBuiltinDeclaration =
TypeCheckingProcedure.findCorrespondingSupertype(superClassDescriptor.defaultType, builtinContainerDefaultType) != null
if (superClassDescriptor !is JavaClassDescriptor) {
// Kotlin class
// ?
if (implementsBuiltinDeclaration) return false
}
else {
// java super class inherits builtin class and it's declaration is final
if (implementsBuiltinDeclaration
&& reachableDeclarations.any { it.containingDeclaration == superClassDescriptor && it.modality == Modality.FINAL }) {
return false
}
}
superClassDescriptor = DescriptorUtils.getSuperClassDescriptor(superClassDescriptor as ClassDescriptor)
}
return true
}
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.fileClasses.FileClasses;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
import org.jetbrains.kotlin.load.java.BuiltinsPropertiesUtilKt;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
@@ -725,7 +726,13 @@ public class JetTypeMapper {
invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
}
signature = mapSignature(functionDescriptor.getOriginal());
FunctionDescriptor overriddenSpecialBuiltinFunction =
BuiltinsPropertiesUtilKt.<FunctionDescriptor>getBuiltinSpecialOverridden(functionDescriptor.getOriginal());
FunctionDescriptor functionToCall = overriddenSpecialBuiltinFunction != null
? overriddenSpecialBuiltinFunction.getOriginal()
: functionDescriptor.getOriginal();
signature = mapSignature(functionToCall);
ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor
? declarationOwner
@@ -803,6 +810,9 @@ public class JetTypeMapper {
if (platformName != null) return platformName;
}
String nameForSpecialFunction = BuiltinsPropertiesUtilKt.getJvmMethodNameIfSpecial(descriptor);
if (nameForSpecialFunction != null) return nameForSpecialFunction;
if (descriptor instanceof PropertyAccessorDescriptor) {
PropertyDescriptor property = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
if (isAnnotationClass(property.getContainingDeclaration())) {
@@ -0,0 +1,101 @@
import java.util.*;
interface A0 {
val size: Int get() = 56
}
class B0 : Collection<String>, A0 {
override fun isEmpty() = throw UnsupportedOperationException()
override fun contains(o: Any?) = throw UnsupportedOperationException()
override fun iterator() = throw UnsupportedOperationException()
override fun containsAll(c: Collection<Any?>) = throw UnsupportedOperationException()
}
open class A1 {
val size: Int = 56
}
class B1 : Collection<String>, A1() {
override fun isEmpty() = throw UnsupportedOperationException()
override fun contains(o: Any?) = throw UnsupportedOperationException()
override fun iterator() = throw UnsupportedOperationException()
override fun containsAll(c: Collection<Any?>) = throw UnsupportedOperationException()
}
interface I2 {
val size: Int
}
val list = ArrayList<String>()
class B2 : ArrayList<String>(list), I2
interface I3<T> {
val size: T
}
class B3 : ArrayList<String>(list), I3<Int>
interface I4<T> {
val size: T get() = 56 as T
}
class B4 : Collection<String>, I4<Int> {
override fun isEmpty() = throw UnsupportedOperationException()
override fun contains(o: Any?) = throw UnsupportedOperationException()
override fun iterator() = throw UnsupportedOperationException()
override fun containsAll(c: Collection<Any?>) = throw UnsupportedOperationException()
}
interface I5 : Collection<String> {
override val size: Int get() = 56
}
class B5 : I5 {
override fun isEmpty() = throw UnsupportedOperationException()
override fun contains(o: Any?) = throw UnsupportedOperationException()
override fun iterator() = throw UnsupportedOperationException()
override fun containsAll(c: Collection<Any?>) = throw UnsupportedOperationException()
}
fun box(): String {
list.add("1")
val b0 = B0()
if (b0.size != 56) return "fail 0: ${b0.size}"
var x: Collection<String> = B0()
if (x.size != 56) return "fail 00: ${x.size}"
val a0: A0 = b0
if (a0.size != 56) return "fail 000: ${a0.size}"
val b1 = B1()
if (b1.size != 56) return "fail 1: ${b1.size}"
x = B1()
if (x.size != 56) return "fail 2: ${x.size}"
val b2 = B2()
if (b2.size != 1) return "fail 3: ${b2.size}"
x = B2()
if (x.size != 1) return "fail 4: ${x.size}"
val i2: I2 = b2
if (i2.size != 1) return "fail 5: ${i2.size}"
val b3 = B3()
if (b3.size != 1) return "fail 6: ${b3.size}"
x = B3()
if (x.size != 1) return "fail 7: ${x.size}"
val i3: I3<Int> = b3
if (i3.size != 1) return "fail 8: ${i3.size}"
val b4 = B4()
if (b4.size != 56) return "fail 9: ${b4.size}"
x = B4()
if (x.size != 56) return "fail 10: ${x.size}"
val b5 = B5()
if (b5.size != 56) return "fail 11: ${b5.size}"
x = B5()
if (x.size != 56) return "fail 12: ${x.size}"
return "OK"
}
@@ -0,0 +1,94 @@
class A1 : MutableCollection<String> {
override val size: Int
get() = 56
override fun isEmpty(): Boolean {
throw UnsupportedOperationException()
}
override fun contains(o: Any?): Boolean {
throw UnsupportedOperationException()
}
override fun iterator(): MutableIterator<String> {
throw UnsupportedOperationException()
}
override fun containsAll(c: Collection<Any?>): Boolean {
throw UnsupportedOperationException()
}
override fun add(e: String): Boolean {
throw UnsupportedOperationException()
}
override fun remove(o: Any?): Boolean {
throw UnsupportedOperationException()
}
override fun addAll(c: Collection<String>): Boolean {
throw UnsupportedOperationException()
}
override fun removeAll(c: Collection<Any?>): Boolean {
throw UnsupportedOperationException()
}
override fun retainAll(c: Collection<Any?>): Boolean {
throw UnsupportedOperationException()
}
override fun clear() {
throw UnsupportedOperationException()
}
}
class A2 : java.util.AbstractCollection<String>() {
override val size: Int
get() = 56
override fun iterator(): MutableIterator<String> {
throw UnsupportedOperationException()
}
}
class A3 : java.util.ArrayList<String>() {
override val size: Int
get() = 56
}
interface Sized {
val size: Int
}
class A4 : java.util.ArrayList<String>(), Sized {
override val size: Int
get() = 56
}
fun check56(x: Collection<String>) {
if (x.size != 56) throw java.lang.RuntimeException("fail ${x.size}")
}
fun box(): String {
val a1 = A1()
if (a1.size != 56) return "fail 1: ${a1.size}"
check56(a1)
val a2 = A2()
if (a2.size != 56) return "fail 2: ${a2.size}"
check56(a2)
val a3 = A3()
if (a3.size != 56) return "fail 3: ${a3.size}"
check56(a3)
val a4 = A4()
if (a4.size != 56) return "fail 4: ${a4.size}"
check56(a4)
val sized: Sized = a4
if (sized.size != 56) return "fail 5: ${a4.size}"
return "OK"
}
@@ -0,0 +1,10 @@
class A : java.util.ArrayList<String>() {
override val size: Int get() = super.size + 56
}
fun box(): String {
val a = A()
if (a.size != 56) return "fail: ${a.size}"
return "OK"
}
@@ -0,0 +1,41 @@
class A : Map<String, String> {
override val size: Int get() = 56
override fun isEmpty(): Boolean {
throw UnsupportedOperationException()
}
override fun containsKey(key: Any?): Boolean {
throw UnsupportedOperationException()
}
override fun containsValue(value: Any?): Boolean {
throw UnsupportedOperationException()
}
override fun get(key: Any?): String? {
throw UnsupportedOperationException()
}
override fun keySet(): Set<String> {
throw UnsupportedOperationException()
}
override fun values(): Collection<String> {
throw UnsupportedOperationException()
}
override fun entrySet(): Set<Map.Entry<String, String>> {
throw UnsupportedOperationException()
}
}
fun box(): String {
val a = A()
if (a.size != 56) return "fail 1: ${a.size}"
val x: Map<String, String> = a
if (x.size != 56) return "fail 2: ${x.size}"
return "OK"
}
@@ -0,0 +1,5 @@
public class Test extends java.util.ArrayList<String> {
public final int size() {
return 56;
}
}
@@ -0,0 +1,12 @@
class OurTest : Test()
fun box(): String {
val t = OurTest()
val x: MutableCollection<String> = t
if (t.size != 56) return "fail 1: ${t.size}"
if (x.size != 56) return "fail 1: ${x.size}"
return "OK"
}
@@ -0,0 +1,65 @@
abstract class A1 : Collection<String> {
override val size: Int get() = 1
}
abstract class A2 : Collection<String> {
abstract override val size: Int
}
abstract class A3 : java.util.AbstractCollection<String>() {
override val size: Int get() = 1
}
abstract class A4 : java.util.AbstractCollection<String>() {
abstract override val size: Int
}
abstract class A5 : java.util.ArrayList<String>() {
override val size: Int get() = 1
}
abstract class A6 : java.util.ArrayList<String>() {
abstract override val size: Int
}
abstract class A7 : MutableList<String>
abstract class A8 : java.util.ArrayList<String>()
interface A9 : List<String> {}
fun box(
a1: A1,
a2: A2,
a3: A3,
a4: A4,
a5: A5,
a6: A6,
a7: A7,
a8: A8,
a9: A9,
c1: Collection<String>,
c2: MutableCollection<String>
) {
a1.size
a2.size
a3.size
a4.size
a5.size
a6.size
a7.size
a8.size
a9.size
c1.size
c2.size
}
/*
*/
// 8 public final bridge size\(\)I
// 8 INVOKEVIRTUAL A[0-9]+\.size \(\)I
// 1 INVOKEINTERFACE A9+\.size \(\)I
// 8 INVOKEVIRTUAL A[0-9]+\.getSize() \(\)I
// 2 INVOKEINTERFACE java\/util\/Collection.size \(\)I
// 4 public abstract getSize\(\)I
@@ -359,6 +359,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/builtinFunctions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class BuiltinFunctions extends AbstractBytecodeTextTest {
public void testAllFilesPresentInBuiltinFunctions() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/builtinFunctions"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("size.kt")
public void testSize() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/builtinFunctions/size.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/conditions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -920,6 +920,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@TestMetadata("compiler/testData/codegen/box/builtinsProperties")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class BuiltinsProperties extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInBuiltinsProperties() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/builtinsProperties"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("bridges.kt")
public void testBridges() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/builtinsProperties/bridges.kt");
doTest(fileName);
}
@TestMetadata("collectionImpl.kt")
public void testCollectionImpl() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/builtinsProperties/collectionImpl.kt");
doTest(fileName);
}
@TestMetadata("explicitSuperCall.kt")
public void testExplicitSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/builtinsProperties/explicitSuperCall.kt");
doTest(fileName);
}
@TestMetadata("maps.kt")
public void testMaps() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/builtinsProperties/maps.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/casts")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -319,6 +319,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName);
}
@TestMetadata("collectionSize")
public void testCollectionSize() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/properties/collectionSize/");
doTestWithJava(fileName);
}
@TestMetadata("substituteJavaSuperField")
public void testSubstituteJavaSuperField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/properties/substituteJavaSuperField/");
@@ -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
@@ -366,6 +366,18 @@ public class DescriptorUtils {
return getBuiltIns(classDescriptor).getAnyType();
}
@Nullable
public static ClassDescriptor getSuperClassDescriptor(@NotNull ClassDescriptor classDescriptor) {
Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
for (JetType type : superclassTypes) {
ClassDescriptor superClassDescriptor = getClassDescriptorForType(type);
if (superClassDescriptor.getKind() != ClassKind.INTERFACE) {
return superClassDescriptor;
}
}
return null;
}
@NotNull
public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
return getClassDescriptorForTypeConstructor(type.getConstructor());