diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt index acdbabb9aff..16988e44e01 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt @@ -67,13 +67,15 @@ class LazyJavaClassMemberScope( private val jClass: JavaClass ) : LazyJavaScope(c) { - override fun computeMemberIndex(): MemberIndex { - return object : ClassMemberIndex(jClass, { !it.isStatic }) { - // For SAM-constructors - override fun getMethodNames(nameFilter: (Name) -> Boolean): Set - = super.getMethodNames(nameFilter) + computeClassNames(DescriptorKindFilter.CLASSIFIERS, nameFilter) + override fun computeMemberIndex() = ClassMemberIndex(jClass, { !it.isStatic }) + + override fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) = + ownerDescriptor.typeConstructor.supertypes.flatMapTo(HashSet()) { + it.memberScope.getFunctionNames() + }.apply { + addAll(super.computeFunctionNames(kindFilter, null)) + addAll(computeClassNames(kindFilter, nameFilter)) } - } internal val constructors = c.storageManager.createLazyValue { val constructors = jClass.constructors @@ -628,7 +630,7 @@ class LazyJavaClassMemberScope( val field = enumEntryIndex()[name] if (field != null) { val enumMemberNames: NotNullLazyValue> = c.storageManager.createLazyValue { - (memberIndex().getAllFieldNames() + memberIndex().getMethodNames({ true })).toSet() + getFunctionNames() + getVariableNames() } EnumEntrySyntheticClassDescriptor.create( c.storageManager, ownerDescriptor, name, enumMemberNames, c.resolveAnnotations(field), @@ -664,13 +666,10 @@ class LazyJavaClassMemberScope( = nestedClassIndex().keys + enumEntryIndex().keys override fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set { - if (jClass.isAnnotationType) return memberIndex().getMethodNames(nameFilter ?: alwaysTrue()) - - return memberIndex().getAllFieldNames() + - ownerDescriptor.getTypeConstructor().getSupertypes().flatMapTo(LinkedHashSet()) { supertype -> - supertype.memberScope.getContributedDescriptors(kindFilter, nameFilter ?: alwaysTrue()).map { variable -> - variable.getName() - } + if (jClass.isAnnotationType) return getFunctionNames() + val result = LinkedHashSet(memberIndex().getAllFieldNames()) + return ownerDescriptor.typeConstructor.supertypes.flatMapTo(result) { supertype -> + supertype.memberScope.getVariableNames() } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt index 8015cb7e49c..8b348031290 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.storage.NullableLazyValue import org.jetbrains.kotlin.utils.alwaysTrue +import java.util.* class LazyJavaPackageScope( c: LazyJavaResolverContext, @@ -133,10 +134,7 @@ class LazyJavaPackageScope( override fun getContributedVariables(name: Name, location: LookupLocation): Collection = emptyList() - override fun computeMemberIndex(): MemberIndex = object : MemberIndex by EMPTY_MEMBER_INDEX { - // For SAM-constructors - override fun getMethodNames(nameFilter: (Name) -> Boolean): Set = computeClassNames(DescriptorKindFilter.CLASSIFIERS, nameFilter) - } + override fun computeMemberIndex(): MemberIndex = EMPTY_MEMBER_INDEX override fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set { // neither objects nor enum members can be in java package @@ -151,7 +149,8 @@ class LazyJavaPackageScope( // optimization: only SAM-constructors may exist in java package if (kindFilter.excludes.contains(SamConstructorDescriptorKindExclude)) return emptySet() - return super.computeFunctionNames(kindFilter, nameFilter) + // For SAM-constructors + return computeClassNames(DescriptorKindFilter.CLASSIFIERS, nameFilter) } override fun computeNonDeclaredFunctions(result: MutableCollection, name: Name) { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt index e3af865b65f..046b0e34310 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt @@ -46,7 +46,6 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.addIfNotNull -import org.jetbrains.kotlin.utils.alwaysTrue import org.jetbrains.kotlin.utils.toReadOnlyList import java.util.* @@ -221,17 +220,19 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS override fun getFunctionNames() = functionNamesLazy override fun getVariableNames() = propertyNamesLazy - protected open fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set - = memberIndex().getMethodNames(nameFilter ?: alwaysTrue()) override fun getContributedFunctions(name: Name, location: LookupLocation): Collection { if (name !in getFunctionNames()) return emptyList() return functions(name) } + protected open fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set = + memberIndex().getMethodNames() + protected abstract fun computeNonDeclaredProperties(name: Name, result: MutableCollection) - protected abstract fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set + protected open fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set = + memberIndex().getAllFieldNames() private val properties = c.storageManager.createMemoizedFunction { name: Name -> diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt index ed561736b95..51d2eb268ea 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaStaticClassScope.kt @@ -31,7 +31,8 @@ import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValueOfMethod import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValuesMethod import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.utils.DFS class LazyJavaStaticClassScope( c: LazyJavaResolverContext, @@ -39,27 +40,21 @@ class LazyJavaStaticClassScope( override val ownerDescriptor: LazyJavaClassDescriptor ) : LazyJavaStaticScope(c) { - override fun computeMemberIndex(): MemberIndex { - val delegate = ClassMemberIndex(jClass) { it.isStatic } - return object : MemberIndex by delegate { - override fun getMethodNames(nameFilter: (Name) -> Boolean): Set { - // Should be a super call, but KT-2860 - return delegate.getMethodNames(nameFilter) + - // For SAM-constructors - jClass.innerClasses.map { it.name } + override fun computeMemberIndex() = ClassMemberIndex(jClass) { it.isStatic } + + override fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) = + super.computeFunctionNames(kindFilter, nameFilter).toMutableSet().apply { + addAll(ownerDescriptor.getParentJavaStaticClassScope()?.getFunctionNames().orEmpty()) + if (jClass.isEnum) { + addAll(listOf(DescriptorUtils.ENUM_VALUE_OF, DescriptorUtils.ENUM_VALUES)) } + addAll(jClass.innerClasses.map(JavaClass::name)) } - } - override fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set { - if (jClass.isEnum) { - return super.computeFunctionNames(kindFilter, nameFilter) + listOf(DescriptorUtils.ENUM_VALUE_OF, DescriptorUtils.ENUM_VALUES) + override fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) = + super.computePropertyNames(kindFilter, nameFilter).toMutableSet().apply { + flatMapJavaStaticSupertypesScopes(ownerDescriptor, this) { it.getVariableNames() } } - return super.computeFunctionNames(kindFilter, nameFilter) - } - - override fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set = - memberIndex().getAllFieldNames() override fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set = emptySet() @@ -85,7 +80,9 @@ class LazyJavaStaticClassScope( } override fun computeNonDeclaredProperties(name: Name, result: MutableCollection) { - val propertiesFromSupertypes = getStaticPropertiesFromJavaSupertypes(name, ownerDescriptor) + val propertiesFromSupertypes = flatMapJavaStaticSupertypesScopes(ownerDescriptor, mutableSetOf()) { + it.getContributedVariables(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS) + } if (result.isNotEmpty()) { result.addAll(resolveOverridesForStaticMembers( @@ -106,19 +103,34 @@ class LazyJavaStaticClassScope( return staticScope.getContributedFunctions(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS).toSet() } - private fun getStaticPropertiesFromJavaSupertypes(name: Name, descriptor: ClassDescriptor): Set { + private fun flatMapJavaStaticSupertypesScopes( + root: ClassDescriptor, + result: MutableSet, + onJavaStaticScope: (MemberScope) -> Collection + ): Set { + DFS.dfs(listOf(root), + { + it.typeConstructor.supertypes.asSequence().mapNotNull { + supertype -> supertype.constructor.declarationDescriptor as? ClassDescriptor + }.asIterable() + }, + object : DFS.AbstractNodeHandler() { + override fun beforeChildren(current: ClassDescriptor): Boolean { + if (current === root) return true + val staticScope = current.staticScope - fun getStaticProperties(supertype: KotlinType): Iterable { - val superTypeDescriptor = supertype.constructor.declarationDescriptor as? ClassDescriptor ?: return emptyList() + if (staticScope is LazyJavaStaticScope) { + result.addAll(onJavaStaticScope(staticScope)) + return false + } + return true + } - val staticScope = superTypeDescriptor.staticScope + override fun result() {} + } + ) - if (staticScope !is LazyJavaStaticClassScope) return getStaticPropertiesFromJavaSupertypes(name, superTypeDescriptor) - - return staticScope.getContributedVariables(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS) - } - - return descriptor.typeConstructor.supertypes.flatMap(::getStaticProperties).toSet() + return result } private val PropertyDescriptor.realOriginal: PropertyDescriptor diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/MemberIndex.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/MemberIndex.kt index ee87924e619..3f079632132 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/MemberIndex.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/MemberIndex.kt @@ -21,13 +21,11 @@ import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaField import org.jetbrains.kotlin.load.java.structure.JavaMember import org.jetbrains.kotlin.load.java.structure.JavaMethod -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import java.util.* interface MemberIndex { fun findMethodsByName(name: Name): Collection - fun getMethodNames(nameFilter: (Name) -> Boolean): Set + fun getMethodNames(): Set fun findFieldByName(name: Name): JavaField? fun getAllFieldNames(): Set @@ -35,22 +33,12 @@ interface MemberIndex { object EMPTY_MEMBER_INDEX : MemberIndex { override fun findMethodsByName(name: Name) = listOf() - override fun getMethodNames(nameFilter: (Name) -> Boolean) = emptySet() + override fun getMethodNames() = emptySet() override fun findFieldByName(name: Name): JavaField? = null override fun getAllFieldNames() = emptySet() } -private val ADDITIONAL_MEMBER_NAMES_MAP = mapOf( - FqName("java.util.List") to listOf(Name.identifier("removeAt")), - FqName("java.lang.CharSequence") to listOf(Name.identifier("get")), - FqName("java.util.Map") to listOf(Name.identifier("keys"), Name.identifier("entries")), - FqName("java.lang.Number") to listOf( - Name.identifier("toByte"), Name.identifier("toShort"), Name.identifier("toInt"), Name.identifier("toLong"), - Name.identifier("toFloat"), Name.identifier("toDouble") - ) -) - open class ClassMemberIndex(val jClass: JavaClass, val memberFilter: (JavaMember) -> Boolean) : MemberIndex { private val methodFilter = { m: JavaMethod -> @@ -61,39 +49,9 @@ open class ClassMemberIndex(val jClass: JavaClass, val memberFilter: (JavaMember private val fields = jClass.fields.asSequence().filter(memberFilter).associateBy { m -> m.name } override fun findMethodsByName(name: Name): Collection = methods[name] ?: listOf() - override fun getMethodNames(nameFilter: (Name) -> Boolean): Set = - jClass.getAllMemberNames(methodFilter) { methods } + override fun getMethodNames(): Set = jClass.methods.asSequence().filter(methodFilter).mapTo(mutableSetOf(), JavaMethod::name) override fun findFieldByName(name: Name): JavaField? = fields[name] - override fun getAllFieldNames(): Set = jClass.getAllMemberNames(memberFilter) { fields } + override fun getAllFieldNames(): Set = jClass.fields.asSequence().filter(memberFilter).mapTo(mutableSetOf(), JavaField::name) } -private fun JavaClass.getNonDeclaredMethodNames(): List { - return ADDITIONAL_MEMBER_NAMES_MAP[this.fqName].orEmpty() -} - -private fun JavaClass.getAllMemberNames(filter: (M) -> Boolean, getMembers: JavaClass.() -> Collection): Set { - val result = HashSet() - val visitedSuperClasses = HashSet() - - fun JavaClass.visit(): Unit { - if (!visitedSuperClasses.add(this)) return - - for (member in getMembers()) { - if (filter(member)) { - result.add(member.name) - } - } - - for (supertype in supertypes) { - val classifier = supertype.classifier - if (classifier is JavaClass) { - result.addAll(classifier.getNonDeclaredMethodNames()) - classifier.visit() - } - } - } - - this.visit() - return result -}