diff --git a/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/J.java b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/J.java new file mode 100644 index 00000000000..19d0543fb14 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/J.java @@ -0,0 +1,6 @@ +public class J { + public void publicMemberJ() {} + private void privateMemberJ() {} + public static void publicStaticJ() {} + private static void privateStaticJ() {} +} diff --git a/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/K.kt b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/K.kt new file mode 100644 index 00000000000..c56a8d37967 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/K.kt @@ -0,0 +1,65 @@ +import kotlin.reflect.* +import kotlin.test.assertEquals + +open class K : J() { + public fun publicMemberK() {} + private fun privateMemberK() {} + public fun Any.publicMemberExtensionK() {} + private fun Any.privateMemberExtensionK() {} +} + +class L : K() + +fun Collection>.names(): Set = + this.map { it.name }.toSet() + +fun check(c: Collection>, names: Set) { + assertEquals(names, c.names()) +} + +fun box(): String { + val any = setOf("equals", "hashCode", "toString") + + val j = J::class + + check(j.staticFunctions, + setOf("publicStaticJ", "privateStaticJ")) + check(j.declaredFunctions, + setOf("publicMemberJ", "privateMemberJ", "publicStaticJ", "privateStaticJ")) + check(j.declaredMemberFunctions, + setOf("publicMemberJ", "privateMemberJ")) + check(j.declaredMemberExtensionFunctions, + emptySet()) + + check(j.functions, any + j.declaredFunctions.names()) + check(j.memberFunctions, any + j.declaredMemberFunctions.names()) + check(j.memberExtensionFunctions, emptySet()) + + val k = K::class + + check(k.staticFunctions, + emptySet()) + check(k.declaredFunctions, + setOf("publicMemberK", "privateMemberK", "publicMemberExtensionK", "privateMemberExtensionK")) + check(k.declaredMemberFunctions, + setOf("publicMemberK", "privateMemberK")) + check(k.declaredMemberExtensionFunctions, + setOf("publicMemberExtensionK", "privateMemberExtensionK")) + + check(k.memberFunctions, any + setOf("publicMemberJ") + k.declaredMemberFunctions.names()) + check(k.memberExtensionFunctions, k.declaredMemberExtensionFunctions.names()) + check(k.functions, any + (k.memberFunctions + k.memberExtensionFunctions).names()) + + + val l = L::class + + check(l.staticFunctions, emptySet()) + check(l.declaredFunctions, emptySet()) + check(l.declaredMemberFunctions, emptySet()) + check(l.declaredMemberExtensionFunctions, emptySet()) + check(l.memberFunctions, any + setOf("publicMemberJ", "publicMemberK")) + check(l.memberExtensionFunctions, setOf("publicMemberExtensionK")) + check(l.functions, any + (l.memberFunctions + l.memberExtensionFunctions).names()) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 7dd799c5048..00128d87b81 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -285,6 +285,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava(fileName); } + @TestMetadata("declaredVsInheritedFunctions") + public void testDeclaredVsInheritedFunctions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/"); + doTestWithJava(fileName); + } + @TestMetadata("functionReferenceErasedToKFunction") public void testFunctionReferenceErasedToKFunction() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/functionReferenceErasedToKFunction/"); diff --git a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt index fc3d768916e..f84643f8ec9 100644 --- a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt +++ b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt @@ -30,13 +30,60 @@ public val KClass.primaryConstructor: KFunction? ((it as KFunctionImpl).descriptor as ConstructorDescriptor).isPrimary } +/** + * Returns static functions declared in this class. + */ +public val KClass<*>.staticFunctions: Collection> + get() = (this as KClassImpl) + .getMembers(staticScope, declaredOnly = false, nonExtensions = true, extensions = true) + .filterIsInstance>() + .toList() + +/** + * Returns non-extension non-static functions declared in this class and all of its superclasses. + */ +public val KClass<*>.memberFunctions: Collection> + get() = (this as KClassImpl) + .getMembers(memberScope, declaredOnly = false, nonExtensions = true, extensions = false) + .filterIsInstance>() + .toList() + +/** + * Returns extension functions declared in this class and all of its superclasses. + */ +public val KClass<*>.memberExtensionFunctions: Collection> + get() = (this as KClassImpl) + .getMembers(memberScope, declaredOnly = false, nonExtensions = false, extensions = true) + .filterIsInstance>() + .toList() + /** * Returns all functions declared in this class. - * If this is a Java class, it includes both non-static and static methods. + * If this is a Java class, it includes all non-static methods (both extensions and non-extensions) + * declared in the class and the superclasses, as well as static methods declared in the class. */ public val KClass<*>.declaredFunctions: Collection> get() = (this as KClassImpl) - .getMembers(declaredOnly = true, nonExtensions = true, extensions = true) + .getMembers(memberScope, declaredOnly = true, nonExtensions = true, extensions = true) + .plus(getMembers(staticScope, declaredOnly = true, nonExtensions = true, extensions = true)) + .filterIsInstance>() + .toList() + +/** + * Returns non-extension non-static functions declared in this class. + */ +public val KClass<*>.declaredMemberFunctions: Collection> + get() = (this as KClassImpl) + .getMembers(memberScope, declaredOnly = true, nonExtensions = true, extensions = false) + .filterIsInstance>() + .toList() + +/** + * Returns extension functions declared in this class. + */ +public val KClass<*>.declaredMemberExtensionFunctions: Collection> + get() = (this as KClassImpl) + .getMembers(memberScope, declaredOnly = true, nonExtensions = false, extensions = true) .filterIsInstance>() .toList() @@ -45,7 +92,7 @@ public val KClass<*>.declaredFunctions: Collection> */ public val KClass.memberProperties: Collection> get() = (this as KClassImpl) - .getMembers(declaredOnly = false, nonExtensions = true, extensions = false) + .getMembers(memberScope, declaredOnly = false, nonExtensions = true, extensions = false) .filterIsInstance>() .toList() @@ -54,7 +101,7 @@ public val KClass.memberProperties: Collection> */ public val KClass.memberExtensionProperties: Collection> get() = (this as KClassImpl) - .getMembers(declaredOnly = false, nonExtensions = false, extensions = true) + .getMembers(memberScope, declaredOnly = false, nonExtensions = false, extensions = true) .filterIsInstance>() .toList() @@ -63,7 +110,7 @@ public val KClass.memberExtensionProperties: Collection KClass.declaredMemberProperties: Collection> get() = (this as KClassImpl) - .getMembers(declaredOnly = true, nonExtensions = true, extensions = false) + .getMembers(memberScope, declaredOnly = true, nonExtensions = true, extensions = false) .filterIsInstance>() .toList() @@ -72,6 +119,6 @@ public val KClass.declaredMemberProperties: Collection KClass.declaredMemberExtensionProperties: Collection> get() = (this as KClassImpl) - .getMembers(declaredOnly = true, nonExtensions = false, extensions = true) + .getMembers(memberScope, declaredOnly = true, nonExtensions = false, extensions = true) .filterIsInstance>() .toList() diff --git a/core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt index f239d9bf0ef..ff2b170d8b0 100644 --- a/core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt +++ b/core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt @@ -16,15 +16,10 @@ package kotlin.reflect -import kotlin.reflect.jvm.internal.KDeclarationContainerImpl - /** * Returns all functions declared in this container. * If this container is a Java class, it includes all non-static methods declared in the class * and the superclasses, as well as static methods declared in the class. */ public val KDeclarationContainer.functions: Collection> - get() = (this as KDeclarationContainerImpl) - .getMembers(declaredOnly = false, nonExtensions = true, extensions = true) - .filterIsInstance>() - .toList() + get() = members.filterIsInstance>() diff --git a/core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt index 45f27b73490..b93b0efb33e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt +++ b/core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt @@ -23,7 +23,7 @@ import kotlin.reflect.jvm.internal.KPackageImpl */ public val KPackage.properties: Collection> get() = (this as KPackageImpl) - .getMembers(declaredOnly = false, nonExtensions = true, extensions = false) + .getMembers(scope, declaredOnly = false, nonExtensions = true, extensions = false) .filterIsInstance>() .toList() @@ -32,6 +32,6 @@ public val KPackage.properties: Collection> */ public val KPackage.extensionProperties: Collection> get() = (this as KPackageImpl) - .getMembers(declaredOnly = false, nonExtensions = false, extensions = true) + .getMembers(scope, declaredOnly = false, nonExtensions = false, extensions = true) .filterIsInstance>() .toList() diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index c7d4648b3b5..044554ae6f3 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -18,12 +18,16 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotated +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.resolve.scopes.ChainedScope +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies +import kotlin.reflect.KCallable import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KotlinReflectionInternalError @@ -43,9 +47,14 @@ class KClassImpl(override val jClass: Class) : KDeclarationContainer private val classId: ClassId get() = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass) - override val scope: JetScope get() = ChainedScope( - descriptor, "KClassImpl scope", descriptor.getDefaultType().getMemberScope(), descriptor.getStaticScope() - ) + internal val memberScope: JetScope get() = descriptor.defaultType.memberScope + + internal val staticScope: JetScope get() = descriptor.staticScope + + override val members: Collection> + get() = getMembers(memberScope, declaredOnly = false, nonExtensions = true, extensions = true) + .plus(getMembers(staticScope, declaredOnly = false, nonExtensions = true, extensions = true)) + .toList() override val constructorDescriptors: Collection get() { @@ -56,6 +65,15 @@ class KClassImpl(override val jClass: Class) : KDeclarationContainer return emptyList() } + @suppress("UNCHECKED_CAST") + override fun getProperties(name: Name): Collection = + (memberScope.getProperties(name, NoLookupLocation.FROM_REFLECTION) + + staticScope.getProperties(name, NoLookupLocation.FROM_REFLECTION)) as Collection + + override fun getFunctions(name: Name): Collection = + memberScope.getFunctions(name, NoLookupLocation.FROM_REFLECTION) + + staticScope.getFunctions(name, NoLookupLocation.FROM_REFLECTION) + override val simpleName: String? get() { if (jClass.isAnonymousClass()) return null diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt index 53d5718feb6..effdfd75c6d 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt @@ -18,7 +18,6 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.structure.reflect.classId import org.jetbrains.kotlin.load.java.structure.reflect.createArrayType import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader @@ -42,14 +41,13 @@ abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer { jClass.getOrCreateModule() } - abstract val scope: JetScope - abstract val constructorDescriptors: Collection - override val members: Collection> - get() = getMembers(declaredOnly = false, nonExtensions = true, extensions = true).toList() + abstract fun getProperties(name: Name): Collection - fun getMembers(declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence> { + abstract fun getFunctions(name: Name): Collection + + fun getMembers(scope: JetScope, declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence> { val visitor = object : DeclarationDescriptorVisitorEmptyBodies?, Unit>() { private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean { if (declaredOnly && !descriptor.getKind().isReal()) return true @@ -105,8 +103,7 @@ abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer { } fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor { - val properties = scope - .getProperties(Name.guess(name), NoLookupLocation.FROM_REFLECTION) + val properties = getProperties(Name.guess(name)) .filter { descriptor -> descriptor is PropertyDescriptor && RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature @@ -120,11 +117,11 @@ abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer { ) } - return properties.single() as PropertyDescriptor + return properties.single() } fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor { - val functions = (if (name == "") constructorDescriptors.toList() else scope.getFunctions(Name.guess(name), NoLookupLocation.FROM_REFLECTION)) + val functions = (if (name == "") constructorDescriptors.toList() else getFunctions(Name.guess(name))) .filter { descriptor -> RuntimeTypeMapper.mapSignature(descriptor).asString() == signature } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt index d13231de7ee..6222f7e6dc6 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt @@ -17,8 +17,11 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.ConstructorDescriptor -import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.name.Name import kotlin.jvm.internal.FunctionReference +import kotlin.reflect.KCallable import kotlin.reflect.KotlinReflectionInternalError class KFunctionFromReferenceImpl( @@ -63,11 +66,15 @@ object EmptyContainerForLocal : KDeclarationContainerImpl() { override val jClass: Class<*> get() = fail() - override val scope: JetScope + override val members: Collection> get() = fail() override val constructorDescriptors: Collection get() = fail() + override fun getProperties(name: Name): Collection = fail() + + override fun getFunctions(name: Name): Collection = fail() + private fun fail() = throw KotlinReflectionInternalError("Introspecting local functions is not yet supported in Kotlin reflection") } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index 9329a78af98..33c507d8b9c 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -17,9 +17,14 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.structure.reflect.classId +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.JetScope import kotlin.jvm.internal.KotlinPackage +import kotlin.reflect.KCallable import kotlin.reflect.KPackage class KPackageImpl(override val jClass: Class<*>) : KDeclarationContainerImpl(), KPackage { @@ -30,11 +35,21 @@ class KPackageImpl(override val jClass: Class<*>) : KDeclarationContainerImpl(), moduleData.module.getPackage(fqName) } - override val scope: JetScope get() = descriptor.memberScope + internal val scope: JetScope get() = descriptor.memberScope + + override val members: Collection> + get() = getMembers(scope, declaredOnly = false, nonExtensions = true, extensions = true).toList() override val constructorDescriptors: Collection get() = emptyList() + @suppress("UNCHECKED_CAST") + override fun getProperties(name: Name): Collection = + scope.getProperties(name, NoLookupLocation.FROM_REFLECTION) as Collection + + override fun getFunctions(name: Name): Collection = + scope.getFunctions(name, NoLookupLocation.FROM_REFLECTION) + override fun equals(other: Any?): Boolean = other is KPackageImpl && jClass == other.jClass diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt index 4cad1486a0f..1bb5a683606 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.java.structure.reflect.* import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.platform.JavaToKotlinClassMap +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.serialization.ProtoBuf @@ -117,7 +118,9 @@ sealed class JvmPropertySignature { object RuntimeTypeMapper { fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): JvmFunctionSignature { - val function = possiblySubstitutedFunction.original + // Fake overrides don't have a source element, so we need to take a declaration. + // TODO: support the case when a fake override overrides several declarations with different signatures + val function = DescriptorUtils.unwrapFakeOverride(possiblySubstitutedFunction).original when (function) { is DeserializedCallableMemberDescriptor -> {