Performance optimization: do not invoke DescriptorToSourceUtilsIde.getAnyDeclaration() on creating LookupElement - do it lazily

#KT-14606 In Progress
This commit is contained in:
Valentin Kipyatkov
2016-10-27 01:33:08 +03:00
parent 8aefc0db7c
commit 2b2ef5a349
3 changed files with 52 additions and 37 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.completion.handlers.BaseDeclarationInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.KotlinClassifierInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.FqName
@@ -55,12 +56,13 @@ class BasicLookupElementFactory(
DescriptorUtils.unwrapFakeOverride(descriptor)
else
descriptor
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, _descriptor)
return createLookupElement(_descriptor, declaration, qualifyNestedClasses, includeClassTypeArguments, parametersAndTypeGrayed)
return createLookupElementUnwrappedDescriptor(_descriptor, qualifyNestedClasses, includeClassTypeArguments, parametersAndTypeGrayed)
}
fun createLookupElementForJavaClass(psiClass: PsiClass, qualifyNestedClasses: Boolean = false, includeClassTypeArguments: Boolean = true): LookupElement {
val lookupObject = object : DeclarationLookupObjectImpl(null, psiClass) {
val lookupObject = object : DeclarationLookupObjectImpl(null) {
override val psiElement: PsiElement?
get() = psiClass
override fun getIcon(flags: Int) = psiClass.getIcon(flags)
}
var element = LookupElementBuilder.create(lookupObject, psiClass.name!!)
@@ -109,20 +111,21 @@ class BasicLookupElementFactory(
return element.withIconFromLookupObject()
}
private fun createLookupElement(
private fun createLookupElementUnwrappedDescriptor(
descriptor: DeclarationDescriptor,
declaration: PsiElement?,
qualifyNestedClasses: Boolean,
includeClassTypeArguments: Boolean,
parametersAndTypeGrayed: Boolean
): LookupElement {
val declarationLazy by lazy { DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) }
if (descriptor is ClassifierDescriptor &&
declaration is PsiClass &&
declaration !is KtLightClass) {
declarationLazy is PsiClass &&
declarationLazy !is KtLightClass) {
// for java classes we create special lookup elements
// because they must be equal to ones created in TypesCompletion
// otherwise we may have duplicates
return createLookupElementForJavaClass(declaration, qualifyNestedClasses, includeClassTypeArguments)
return createLookupElementForJavaClass(declarationLazy, qualifyNestedClasses, includeClassTypeArguments)
}
if (descriptor is PackageViewDescriptor) {
@@ -132,26 +135,33 @@ class BasicLookupElementFactory(
return createLookupElementForPackage(descriptor.fqName)
}
// for constructor use name and icon of containing class
val nameAndIconDescriptor: DeclarationDescriptor
val iconDeclaration: PsiElement?
val lookupObject: DeclarationLookupObject
val name: String
if (descriptor is ConstructorDescriptor) {
nameAndIconDescriptor = descriptor.containingDeclaration
iconDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, nameAndIconDescriptor)
// for constructor use name and icon of containing class
val classifierDescriptor = descriptor.containingDeclaration
lookupObject = object : DeclarationLookupObjectImpl(descriptor) {
override val psiElement by lazy { DescriptorToSourceUtilsIde.getAnyDeclaration(project, classifierDescriptor) }
override fun getIcon(flags: Int) = KotlinDescriptorIconProvider.getIcon(classifierDescriptor, psiElement, flags)
}
name = classifierDescriptor.name.asString()
}
else if (descriptor is SyntheticJavaPropertyDescriptor) {
lookupObject = object : DeclarationLookupObjectImpl(descriptor) {
override val psiElement by lazy { DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor.getMethod) }
override fun getIcon(flags: Int) = KotlinDescriptorIconProvider.getIcon(descriptor, null, flags)
}
name = descriptor.name.asString()
}
else {
nameAndIconDescriptor = descriptor
iconDeclaration = declaration
lookupObject = object : DeclarationLookupObjectImpl(descriptor) {
override val psiElement: PsiElement?
get() = declarationLazy
override fun getIcon(flags: Int) = KotlinDescriptorIconProvider.getIcon(descriptor, psiElement, flags)
}
name = descriptor.name.asString()
}
val name = nameAndIconDescriptor.name.asString()
val psiElement = declaration
?: (descriptor as? SyntheticJavaPropertyDescriptor)
?.getMethod
?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
val lookupObject = object : DeclarationLookupObjectImpl(descriptor, psiElement) {
override fun getIcon(flags: Int) = KotlinDescriptorIconProvider.getIcon(nameAndIconDescriptor, iconDeclaration, flags)
}
var element = LookupElementBuilder.create(lookupObject, name)
val insertHandler = insertHandlerProvider.insertHandler(descriptor)
@@ -16,10 +16,8 @@
package org.jetbrains.kotlin.idea.completion
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiDocCommentOwner
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -34,13 +32,8 @@ import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
* Position will be used for sorting
*/
abstract class DeclarationLookupObjectImpl(
final override val descriptor: DeclarationDescriptor?,
final override val psiElement: PsiElement?
final override val descriptor: DeclarationDescriptor?
): DeclarationLookupObject {
init {
assert(descriptor != null || psiElement != null)
}
override val name: Name?
get() = descriptor?.name ?: (psiElement as? PsiNamedElement)?.name?.let { Name.identifier(it) }
@@ -55,15 +48,27 @@ abstract class DeclarationLookupObjectImpl(
override fun toString() = super.toString() + " " + (descriptor ?: psiElement)
override fun hashCode(): Int {
return if (descriptor != null) descriptor.original.hashCode() else psiElement!!.hashCode()
return if (descriptor != null)
descriptor.original.hashCode()
else
psiElement!!.hashCode()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
val lookupObject = other as DeclarationLookupObjectImpl
return descriptorsEqualWithSubstitution(descriptor, lookupObject.descriptor) && psiElement == lookupObject.psiElement
if (descriptor != null)
return descriptorsEqualWithSubstitution(descriptor, lookupObject.descriptor)
else
return lookupObject.descriptor == null && psiElement == lookupObject.psiElement
}
override val isDeprecated = if (descriptor != null) KotlinBuiltIns.isDeprecated(descriptor) else (psiElement as? PsiDocCommentOwner)?.isDeprecated ?: false
override val isDeprecated: Boolean
get() {
return if (descriptor != null)
KotlinBuiltIns.isDeprecated(descriptor)
else
(psiElement as? PsiDocCommentOwner)?.isDeprecated == true
}
}
@@ -125,10 +125,10 @@ class LookupElementsCollector(
result = postProcessor(result)
}
val psiElement = (result.`object` as? DeclarationLookupObject)?.psiElement
if (psiElement != null) {
val declarationLookupObject = result.`object` as? DeclarationLookupObject
if (declarationLookupObject != null) {
result = object : LookupElementDecorator<LookupElement>(result) {
override fun getPsiElement() = psiElement
override fun getPsiElement() = declarationLookupObject.psiElement
}
}