Optimize computation of member names in Java scopes
Effectively all custom logic was moved from MemberIndex to JavaScope classes, and as member names are being cached there, so it prevents repeating supertypes traversal (see getAllMemberNames extension)
This commit is contained in:
+13
-14
@@ -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<Name>
|
||||
= 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<Set<Name>> = 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<Name> {
|
||||
if (jClass.isAnnotationType) return memberIndex().getMethodNames(nameFilter ?: alwaysTrue())
|
||||
|
||||
return memberIndex().getAllFieldNames() +
|
||||
ownerDescriptor.getTypeConstructor().getSupertypes().flatMapTo(LinkedHashSet<Name>()) { 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -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<PropertyDescriptor> = emptyList()
|
||||
|
||||
override fun computeMemberIndex(): MemberIndex = object : MemberIndex by EMPTY_MEMBER_INDEX {
|
||||
// For SAM-constructors
|
||||
override fun getMethodNames(nameFilter: (Name) -> Boolean): Set<Name> = computeClassNames(DescriptorKindFilter.CLASSIFIERS, nameFilter)
|
||||
}
|
||||
override fun computeMemberIndex(): MemberIndex = EMPTY_MEMBER_INDEX
|
||||
|
||||
override fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> {
|
||||
// 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<SimpleFunctionDescriptor>, name: Name) {
|
||||
|
||||
+5
-4
@@ -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<Name>
|
||||
= memberIndex().getMethodNames(nameFilter ?: alwaysTrue())
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
|
||||
if (name !in getFunctionNames()) return emptyList()
|
||||
return functions(name)
|
||||
}
|
||||
|
||||
protected open fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> =
|
||||
memberIndex().getMethodNames()
|
||||
|
||||
protected abstract fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>)
|
||||
|
||||
protected abstract fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name>
|
||||
protected open fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> =
|
||||
memberIndex().getAllFieldNames()
|
||||
|
||||
private val properties = c.storageManager.createMemoizedFunction {
|
||||
name: Name ->
|
||||
|
||||
+41
-29
@@ -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<Name> {
|
||||
// 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<Name> {
|
||||
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<Name> =
|
||||
memberIndex().getAllFieldNames()
|
||||
|
||||
override fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> = emptySet()
|
||||
|
||||
@@ -85,7 +80,9 @@ class LazyJavaStaticClassScope(
|
||||
}
|
||||
|
||||
override fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
|
||||
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<PropertyDescriptor> {
|
||||
private fun <R> flatMapJavaStaticSupertypesScopes(
|
||||
root: ClassDescriptor,
|
||||
result: MutableSet<R>,
|
||||
onJavaStaticScope: (MemberScope) -> Collection<R>
|
||||
): Set<R> {
|
||||
DFS.dfs(listOf(root),
|
||||
{
|
||||
it.typeConstructor.supertypes.asSequence().mapNotNull {
|
||||
supertype -> supertype.constructor.declarationDescriptor as? ClassDescriptor
|
||||
}.asIterable()
|
||||
},
|
||||
object : DFS.AbstractNodeHandler<ClassDescriptor, Unit>() {
|
||||
override fun beforeChildren(current: ClassDescriptor): Boolean {
|
||||
if (current === root) return true
|
||||
val staticScope = current.staticScope
|
||||
|
||||
fun getStaticProperties(supertype: KotlinType): Iterable<PropertyDescriptor> {
|
||||
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
|
||||
|
||||
+4
-46
@@ -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<JavaMethod>
|
||||
fun getMethodNames(nameFilter: (Name) -> Boolean): Set<Name>
|
||||
fun getMethodNames(): Set<Name>
|
||||
|
||||
fun findFieldByName(name: Name): JavaField?
|
||||
fun getAllFieldNames(): Set<Name>
|
||||
@@ -35,22 +33,12 @@ interface MemberIndex {
|
||||
|
||||
object EMPTY_MEMBER_INDEX : MemberIndex {
|
||||
override fun findMethodsByName(name: Name) = listOf<JavaMethod>()
|
||||
override fun getMethodNames(nameFilter: (Name) -> Boolean) = emptySet<Name>()
|
||||
override fun getMethodNames() = emptySet<Name>()
|
||||
|
||||
override fun findFieldByName(name: Name): JavaField? = null
|
||||
override fun getAllFieldNames() = emptySet<Name>()
|
||||
}
|
||||
|
||||
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<JavaMethod> = methods[name] ?: listOf()
|
||||
override fun getMethodNames(nameFilter: (Name) -> Boolean): Set<Name> =
|
||||
jClass.getAllMemberNames(methodFilter) { methods }
|
||||
override fun getMethodNames(): Set<Name> = jClass.methods.asSequence().filter(methodFilter).mapTo(mutableSetOf(), JavaMethod::name)
|
||||
|
||||
override fun findFieldByName(name: Name): JavaField? = fields[name]
|
||||
override fun getAllFieldNames(): Set<Name> = jClass.getAllMemberNames(memberFilter) { fields }
|
||||
override fun getAllFieldNames(): Set<Name> = jClass.fields.asSequence().filter(memberFilter).mapTo(mutableSetOf(), JavaField::name)
|
||||
}
|
||||
|
||||
private fun JavaClass.getNonDeclaredMethodNames(): List<Name> {
|
||||
return ADDITIONAL_MEMBER_NAMES_MAP[this.fqName].orEmpty()
|
||||
}
|
||||
|
||||
private fun <M : JavaMember> JavaClass.getAllMemberNames(filter: (M) -> Boolean, getMembers: JavaClass.() -> Collection<M>): Set<Name> {
|
||||
val result = HashSet<Name>()
|
||||
val visitedSuperClasses = HashSet<JavaClass>()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user