mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
ShadowedDeclarationsFilter: check for equivalence
If there are multiple copies of the same library on the classpath, then ShadowedDeclarationsFilter becomes very slow because it encounters many equal-signature declarations and thus has to resolve a lot of calls in order to pick among them. Having multiple copies of the same library on the classpath is somewhat common in real-world projects. It occurs in the JetBrains/intellij-kotlin project, for example. In that project, ShadowedDeclarationsFilter ends up resolving thousands of calls, accounting for around 80% of completion time when there are many completion results (see KT-44276). We can optimize ShadowedDeclarationsFilter by checking whether the descriptors in an equal-signature group are structurally equivalent. If they are, we can just pick one rather than running resolve. Testing on a small project with Kotlin stdlib duplicated on the classpath, this change reduces overhead in ShadowedDeclarationsFilter from 1200 ms to 20 ms when running completion on the prefix 'a'. End-to-end completion time is cut in half. Test: JvmBasicCompletionTestGenerated.Common.Shadowing
This commit is contained in:
committed by
Nikita Bobko
parent
decfcd28d2
commit
e2109c3f8f
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
@@ -87,6 +88,12 @@ class ShadowedDeclarationsFilter(
|
||||
return listOf(first)
|
||||
}
|
||||
|
||||
// Optimization: if the descriptors are structurally equivalent then there is no need to run resolve.
|
||||
// This can happen when the classpath contains multiple copies of the same library.
|
||||
if (descriptors.all { DescriptorEquivalenceForOverrides.areEquivalent(first, it, allowCopiesFromTheSameDeclaration = true) }) {
|
||||
return listOf(first)
|
||||
}
|
||||
|
||||
val isFunction = first is FunctionDescriptor
|
||||
val name = when (first) {
|
||||
is ConstructorDescriptor -> first.constructedClass.name
|
||||
|
||||
Reference in New Issue
Block a user