Optimize getSingleAbstractMethodOrNull
Searching for the single abstract method leads to computing whole member scopes of given intrefaces, especially when they contain a lot of methods (i.e. they're definitely not SAMs) On the other side this method is very hot because it's called for each Java interface used as a type for some value parameter (for building SAM adapters) The idea is to apply some heuristics to understand using only JavaMethod and supertypes that this interface is definitely not a SAM
This commit is contained in:
+6
@@ -23,4 +23,10 @@ import org.jetbrains.kotlin.types.SimpleType;
|
||||
public interface JavaClassDescriptor extends ClassDescriptor {
|
||||
@Nullable
|
||||
SimpleType getFunctionTypeForSamInterface();
|
||||
|
||||
/**
|
||||
* May return false even in case when the class is not SAM interface, but returns true only if it's definitely not a SAM.
|
||||
* But it should work much faster than the exact check.
|
||||
*/
|
||||
boolean isDefinitelyNotSamInterface();
|
||||
}
|
||||
|
||||
+25
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.*
|
||||
|
||||
class LazyJavaClassDescriptor(
|
||||
@@ -59,6 +60,11 @@ class LazyJavaClassDescriptor(
|
||||
outerContext.components.sourceElementFactory.source(jClass),
|
||||
/* isExternal = */ false), JavaClassDescriptor {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private val PUBLIC_METHOD_NAMES_IN_OBJECT = setOf("equals", "hashCode", "getClass", "wait", "notify", "notifyAll", "toString")
|
||||
}
|
||||
|
||||
private val c: LazyJavaResolverContext = outerContext.child(this, jClass)
|
||||
|
||||
init {
|
||||
@@ -133,6 +139,25 @@ class LazyJavaClassDescriptor(
|
||||
|
||||
override fun getFunctionTypeForSamInterface(): SimpleType? = c.components.samConversionResolver.resolveFunctionTypeIfSamInterface(this)
|
||||
|
||||
override fun isDefinitelyNotSamInterface(): Boolean {
|
||||
if (kind != ClassKind.INTERFACE) return true
|
||||
|
||||
val candidates = jClass.methods.filter { it.isAbstract && it.typeParameters.isEmpty() }
|
||||
// From the definition of function interfaces in the Java specification (pt. 9.8):
|
||||
// "methods that are members of I that do not have the same signature as any public instance method of the class Object"
|
||||
// It means that if an interface declares `int hashCode()` then the method won't be taken into account when
|
||||
// checking if the interface is SAM.
|
||||
// We make here a conservative check just filtering out methods by name.
|
||||
// If we ignore a method with wrong signature (different from one in Object) it's not very bad,
|
||||
// we'll just say that the interface MAY BE a SAM when it's not and then more detailed check will be applied.
|
||||
if (candidates.count { it.name.identifier !in PUBLIC_METHOD_NAMES_IN_OBJECT } > 1) return true
|
||||
|
||||
// Check if any of the super-interfaces contain too many methods to be a SAM
|
||||
return typeConstructor().supertypes.any {
|
||||
it.constructor.declarationDescriptor.safeAs<LazyJavaClassDescriptor>()?.isDefinitelyNotSamInterface == true
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSealedSubclasses(): Collection<ClassDescriptor> = emptyList()
|
||||
|
||||
override fun toString() = "Lazy Java class ${this.fqNameUnsafe}"
|
||||
|
||||
Reference in New Issue
Block a user