From 2b2ef5a3497afbeab2186ac2d8b9adadce6c0b1e Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 27 Oct 2016 01:33:08 +0300 Subject: [PATCH] Performance optimization: do not invoke DescriptorToSourceUtilsIde.getAnyDeclaration() on creating LookupElement - do it lazily #KT-14606 In Progress --- .../completion/BasicLookupElementFactory.kt | 56 +++++++++++-------- .../completion/DeclarationLookupObjectImpl.kt | 27 +++++---- .../completion/LookupElementsCollector.kt | 6 +- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt index c06b9ef37ca..88ae7b3b58d 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt @@ -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) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt index c60e6b16575..5130f5bab14 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt @@ -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 + } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt index 7437957ce81..05a2665ac22 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt @@ -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(result) { - override fun getPsiElement() = psiElement + override fun getPsiElement() = declarationLookupObject.psiElement } }