From ca437e51c4cc37bc6085252ab7d25c918082871b Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 2 Nov 2015 18:07:30 +0300 Subject: [PATCH] Initial implementation of KT-8209 Support static member completion without writing the class name --- .../org/jetbrains/kotlin/psi/KtClassBody.kt | 4 +- .../idea/completion/BasicCompletionSession.kt | 12 +- .../idea/completion/CompletionSession.kt | 32 +++-- .../kotlin/idea/completion/CompletionUtils.kt | 57 +++++++- .../completion/KotlinCompletionContributor.kt | 6 +- .../completion/StaticMembersCompletion.kt | 60 ++++++++ .../idea/completion/smart/StaticMembers.kt | 54 +------ .../common/staticMembers/JavaStaticFields.kt | 8 ++ .../common/staticMembers/JavaStaticMethods.kt | 8 ++ .../ObjectMembers/ObjectMembers.dependency.kt | 19 +++ .../multifile/ObjectMembers/ObjectMembers.kt | 11 ++ .../basic/staticMembers/JavaStaticMethod.kt | 6 + .../staticMembers/JavaStaticMethod.kt.after | 8 ++ .../basic/staticMembers/classObjectMethod.kt | 6 + .../staticMembers/classObjectMethod.kt.after | 8 ++ .../test/JSBasicCompletionTestGenerated.java | 21 +++ .../test/JvmBasicCompletionTestGenerated.java | 21 +++ ...tiFileJvmBasicCompletionTestGenerated.java | 6 + .../BasicCompletionHandlerTestGenerated.java | 21 +++ .../kotlin/idea/core/KotlinIndicesHelper.kt | 133 ++++++++++++++---- .../kotlin/idea/quickfix/AutoImportFix.kt | 2 +- 21 files changed, 400 insertions(+), 103 deletions(-) create mode 100644 idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt create mode 100644 idea/idea-completion/testData/basic/common/staticMembers/JavaStaticFields.kt create mode 100644 idea/idea-completion/testData/basic/common/staticMembers/JavaStaticMethods.kt create mode 100644 idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.dependency.kt create mode 100644 idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.kt create mode 100644 idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt create mode 100644 idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt create mode 100644 idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtClassBody.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtClassBody.kt index 40537193358..72b6d2f1f6a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtClassBody.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtClassBody.kt @@ -29,10 +29,10 @@ import java.util.* class KtClassBody : KtElementImplStub>, KtDeclarationContainer { constructor(node: ASTNode) : super(node) - override fun getParent() = parentByStub - constructor(stub: KotlinPlaceHolderStub) : super(stub, CLASS_BODY) + override fun getParent() = parentByStub + override fun getDeclarations() = Arrays.asList(*getStubOrPsiChildren(DECLARATION_TYPES, KtDeclaration.ARRAY_FACTORY)) override fun accept(visitor: KtVisitor, data: D) = visitor.visitClassBody(this, data) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index 221ef07b3b3..c4d50651d5d 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -196,7 +196,7 @@ class BasicCompletionSession( packageNames.forEach { collector.addElement(basicLookupElementFactory.createLookupElementForPackage(it)) } } - + flushToResultSet() NamedArgumentCompletion.complete(collector, expectedInfos) @@ -227,6 +227,10 @@ class BasicCompletionSession( flushToResultSet() } } + + if (configuration.completeStaticMembers && callTypeAndReceiver is CallTypeAndReceiver.DEFAULT && prefix.isNotEmpty()) { + StaticMembersCompletion(collector, prefixMatcher, indicesHelper(false), lookupElementFactory).complete() + } } } @@ -410,13 +414,13 @@ class BasicCompletionSession( lookupElement } - parameterNameAndTypeCompletion.addFromParametersInFile(position, resolutionFacade, isVisibleFilter) + parameterNameAndTypeCompletion.addFromParametersInFile(position, resolutionFacade, isVisibleFilterCheckAlways) flushToResultSet() - parameterNameAndTypeCompletion.addFromImportedClasses(position, bindingContext, isVisibleFilter) + parameterNameAndTypeCompletion.addFromImportedClasses(position, bindingContext, isVisibleFilterCheckAlways) flushToResultSet() - parameterNameAndTypeCompletion.addFromAllClasses(parameters, indicesHelper) + parameterNameAndTypeCompletion.addFromAllClasses(parameters, indicesHelper(false)) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index d0ebb525a1e..020e5536ffe 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -57,19 +57,23 @@ class CompletionSessionConfiguration( val completeNonImportedDeclarations: Boolean, val completeNonAccessibleDeclarations: Boolean, val filterOutJavaGettersAndSetters: Boolean, - val completeJavaClassesNotToBeUsed: Boolean + val completeJavaClassesNotToBeUsed: Boolean, + val completeStaticMembers: Boolean ) fun CompletionSessionConfiguration(parameters: CompletionParameters) = CompletionSessionConfiguration( completeNonImportedDeclarations = parameters.invocationCount >= 2, completeNonAccessibleDeclarations = parameters.invocationCount >= 2, filterOutJavaGettersAndSetters = parameters.invocationCount < 2, - completeJavaClassesNotToBeUsed = parameters.invocationCount >= 2 + completeJavaClassesNotToBeUsed = parameters.invocationCount >= 2, + completeStaticMembers = parameters.invocationCount >= 2 ) -abstract class CompletionSession(protected val configuration: CompletionSessionConfiguration, - protected val parameters: CompletionParameters, - resultSet: CompletionResultSet) { +abstract class CompletionSession( + protected val configuration: CompletionSessionConfiguration, + protected val parameters: CompletionParameters, + resultSet: CompletionResultSet +) { protected val position = parameters.getPosition() private val file = position.getContainingFile() as KtFile protected val resolutionFacade = file.getResolutionFacade() @@ -124,7 +128,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC private fun ((Name) -> Boolean).or(otherFilter: (Name) -> Boolean): (Name) -> Boolean = { this(it) || otherFilter(it) } - protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it) } + protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = configuration.completeNonAccessibleDeclarations) } + protected val isVisibleFilterCheckAlways: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = false) } protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, resolutionFacade, moduleDescriptor, isVisibleFilter) @@ -151,8 +156,10 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC override fun contains(file: VirtualFile) = super.contains(file) && file != parameters.getOriginalFile().getVirtualFile() } - protected val indicesHelper: KotlinIndicesHelper - get() = KotlinIndicesHelper(resolutionFacade, searchScope, isVisibleFilter, true) + protected fun indicesHelper(mayIncludeInaccessible: Boolean): KotlinIndicesHelper { + val filter = if (mayIncludeInaccessible) isVisibleFilter else isVisibleFilterCheckAlways + return KotlinIndicesHelper(resolutionFacade, searchScope, filter, visibilityFilterMayIncludeAccessible = mayIncludeInaccessible) + } protected val toFromOriginalFileMapper: ToFromOriginalFileMapper = ToFromOriginalFileMapper(parameters.originalFile as KtFile, position.containingFile as KtFile, parameters.offset) @@ -178,7 +185,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC get() = 0 } - private fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean { + private fun isVisibleDescriptor(descriptor: DeclarationDescriptor, completeNonAccessible: Boolean): Boolean { if (!configuration.completeJavaClassesNotToBeUsed && descriptor is ClassDescriptor) { val classification = descriptor.importableFqName?.let { importableFqNameClassifier.classify(it, isPackage = false) } if (classification == ImportableFqNameClassifier.Classification.notToBeUsedInKotlin) return false @@ -189,7 +196,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC if (descriptor is DeclarationDescriptorWithVisibility) { val visible = descriptor.isVisible(inDescriptor, bindingContext, nameExpression) if (visible) return true - return configuration.completeNonAccessibleDeclarations && !descriptor.isFromLibrary() + return completeNonAccessible && !descriptor.isFromLibrary() } return true @@ -309,6 +316,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC var notImportedExtensions: Collection = emptyList() if (callTypeAndReceiver.shouldCompleteCallableExtensions()) { val nameFilter: (String) -> Boolean = { prefixMatcher.prefixMatches(it) } + val indicesHelper = indicesHelper(true) val extensions = if (runtimeReceiver != null) indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiver.type), nameFilter) else @@ -384,7 +392,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC } protected fun getTopLevelCallables(): Collection { - return indicesHelper.getTopLevelCallables({ prefixMatcher.prefixMatches(it) }) + return indicesHelper(true).getTopLevelCallables({ prefixMatcher.prefixMatches(it) }) .filterShadowedNonImported() } @@ -399,7 +407,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC } protected fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean) { - AllClassesCompletion(parameters, indicesHelper, prefixMatcher, resolutionFacade, kindFilter) + AllClassesCompletion(parameters, indicesHelper(true), prefixMatcher, resolutionFacade, kindFilter) .collect( { descriptor -> collector.addElement(basicLookupElementFactory.createLookupElement(descriptor), notImported = true) }, { javaClass -> collector.addElement(basicLookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index e973faf9ec1..444d8c1435b 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -27,8 +27,7 @@ import com.intellij.patterns.ElementPattern import com.intellij.patterns.StandardPatterns import com.intellij.psi.PsiDocumentManager import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler @@ -40,6 +39,7 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.TypeNullability @@ -69,7 +69,8 @@ enum class ItemPriority { DEFAULT, IMPLEMENT, OVERRIDE, - NAMED_PARAMETER + NAMED_PARAMETER, + STATIC_MEMBER } val ITEM_PRIORITY_KEY = Key("ITEM_PRIORITY_KEY") @@ -152,7 +153,7 @@ fun InsertionContext.isAfterDot(): Boolean { val chars = getDocument().getCharsSequence() while (offset > 0) { offset-- - val c = chars.charAt(offset) + val c = chars[offset] if (!Character.isWhitespace(c)) { return c == '.' } @@ -335,7 +336,7 @@ private open class BaseTypeLookupElement(type: KotlinType, baseLookupElement: Lo override fun handleInsert(context: InsertionContext) { context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), fullText) - context.setTailOffset(context.getStartOffset() + fullText.length()) + context.setTailOffset(context.getStartOffset() + fullText.length) shortenReferences(context, context.getStartOffset(), context.getTailOffset()) } } @@ -350,3 +351,49 @@ fun ElementPattern.andNot(rhs: ElementPattern) = StandardPatterns.and( fun ElementPattern.or(rhs: ElementPattern) = StandardPatterns.or(this, rhs) fun singleCharPattern(char: Char) = StandardPatterns.character().equalTo(char) + +fun LookupElement.decorateAsStaticMember( + memberDescriptor: DeclarationDescriptor, + classDescriptor: ClassDescriptor, + classNameAsLookupString: Boolean +): LookupElement { + val qualifierPresentation = classDescriptor.getName().asString() + val qualifierText = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classDescriptor) + + return object: LookupElementDecorator(this) { + override fun getAllLookupStrings(): Set { + return if (classNameAsLookupString) setOf(delegate.lookupString, qualifierPresentation) else super.getAllLookupStrings() + } + + override fun renderElement(presentation: LookupElementPresentation) { + delegate.renderElement(presentation) + + presentation.itemText = qualifierPresentation + "." + presentation.itemText + + val tailText = " (" + DescriptorUtils.getFqName(classDescriptor.containingDeclaration) + ")" + if (memberDescriptor is FunctionDescriptor) { + presentation.appendTailText(tailText, true) + } + else { + presentation.setTailText(tailText, true) + } + + if (presentation.typeText.isNullOrEmpty()) { + presentation.typeText = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(classDescriptor.defaultType) + } + } + + override fun handleInsert(context: InsertionContext) { + val prefix = qualifierText + "." + + val offset = context.startOffset + context.document.insertString(offset, prefix) + context.offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, offset + prefix.length) + + shortenReferences(context, offset, offset + prefix.length) + PsiDocumentManager.getInstance(context.project).doPostponedOperationsAndUnblockDocument(context.document) + + super.handleInsert(context) + } + } +} diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt index 06b7146b44c..1be1b1c965b 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt @@ -257,13 +257,15 @@ public class KotlinCompletionContributor : CompletionContributor() { } val somethingAdded = session.complete() - if (!somethingAdded && parameters.getInvocationCount() < 2) { + if (!somethingAdded && parameters.invocationCount < 2) { // Rerun completion if nothing was found val newConfiguration = CompletionSessionConfiguration( completeNonImportedDeclarations = true, completeNonAccessibleDeclarations = false, filterOutJavaGettersAndSetters = false, - completeJavaClassesNotToBeUsed = false) + completeJavaClassesNotToBeUsed = false, + completeStaticMembers = parameters.invocationCount > 0 + ) BasicCompletionSession(newConfiguration, parameters, result).complete() } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt new file mode 100644 index 00000000000..35d561b1b45 --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/StaticMembersCompletion.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.completion + +import com.intellij.codeInsight.completion.PrefixMatcher +import com.intellij.codeInsight.lookup.LookupElement +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter + +class StaticMembersCompletion( + private val collector: LookupElementsCollector, + private val prefixMatcher: PrefixMatcher, + private val indicesHelper: KotlinIndicesHelper, + private val lookupElementFactory: LookupElementFactory +) { + //TODO: SAM-adapters + //TODO: different priority&behaviour when static import from the same class exist + //TODO: filter out those that are visible from bases/imports etc + //TODO: filter out those that are accessible from SmartCompletion.additionalItems + fun complete() { + val descriptorKindFilter = DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions + val nameFilter: (String) -> Boolean = { prefixMatcher.prefixMatches(it) } + + for (member in indicesHelper.getJavaStaticMembers(descriptorKindFilter, nameFilter)) { + collector.addElement(createLookupElement(member) ?: continue) + } + + for (member in indicesHelper.getObjectMembers(descriptorKindFilter, nameFilter)) { + collector.addElement(createLookupElement(member) ?: continue) + } + } + + private fun createLookupElement(descriptor: CallableDescriptor): LookupElement? { + var classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return null + if (classDescriptor.isCompanionObject) { + classDescriptor = classDescriptor.containingDeclaration as? ClassDescriptor ?: return null + } + return lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false) + .decorateAsStaticMember(descriptor, classDescriptor, classNameAsLookupString = false) + .assignPriority(ItemPriority.STATIC_MEMBER) + .suppressAutoInsertion() + } +} diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt index dc477b0543c..66d92659640 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt @@ -16,24 +16,17 @@ package org.jetbrains.kotlin.idea.completion.smart -import com.intellij.codeInsight.completion.CompletionInitializationContext -import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupElementDecorator -import com.intellij.codeInsight.lookup.LookupElementPresentation -import com.intellij.psi.PsiDocumentManager import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.completion.ExpectedInfo import org.jetbrains.kotlin.idea.completion.LookupElementFactory +import org.jetbrains.kotlin.idea.completion.decorateAsStaticMember import org.jetbrains.kotlin.idea.completion.fuzzyType -import org.jetbrains.kotlin.idea.completion.shortenReferences -import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.core.isVisible import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.fuzzyReturnType +import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.psi.KtSimpleNameExpression -import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension @@ -107,45 +100,10 @@ class StaticMembers( } private fun createLookupElements(memberDescriptor: DeclarationDescriptor, classDescriptor: ClassDescriptor): Collection { - val lookupElements = lookupElementFactory.createLookupElementsInSmartCompletion(memberDescriptor, bindingContext, useReceiverTypes = false) - val qualifierPresentation = classDescriptor.getName().asString() - val qualifierText = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classDescriptor) - - return lookupElements.map { - object: LookupElementDecorator(it) { - override fun getAllLookupStrings() = setOf(delegate.lookupString, qualifierPresentation) - - override fun renderElement(presentation: LookupElementPresentation) { - getDelegate().renderElement(presentation) - - presentation.setItemText(qualifierPresentation + "." + presentation.getItemText()) - - val tailText = " (" + DescriptorUtils.getFqName(classDescriptor.getContainingDeclaration()) + ")" - if (memberDescriptor is FunctionDescriptor) { - presentation.appendTailText(tailText, true) - } - else { - presentation.setTailText(tailText, true) - } - - if (presentation.getTypeText().isNullOrEmpty()) { - presentation.setTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(classDescriptor.getDefaultType())) - } + return lookupElementFactory.createLookupElementsInSmartCompletion(memberDescriptor, bindingContext, useReceiverTypes = false) + .map { + it.decorateAsStaticMember(memberDescriptor, classDescriptor, classNameAsLookupString = true) + .assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER) } - - override fun handleInsert(context: InsertionContext) { - val prefix = qualifierText + "." - - val offset = context.startOffset - context.document.insertString(offset, prefix) - context.offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, offset + prefix.length) - - shortenReferences(context, offset, offset + prefix.length) - PsiDocumentManager.getInstance(context.project).doPostponedOperationsAndUnblockDocument(context.document) - - super.handleInsert(context) - } - }.assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER) - } } } diff --git a/idea/idea-completion/testData/basic/common/staticMembers/JavaStaticFields.kt b/idea/idea-completion/testData/basic/common/staticMembers/JavaStaticFields.kt new file mode 100644 index 00000000000..98edd67f730 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/staticMembers/JavaStaticFields.kt @@ -0,0 +1,8 @@ +fun foo() { + SOU +} + +// INVOCATION_COUNT: 2 +// EXIST_JAVA_ONLY: { allLookupStrings: "SOUTH, getSOUTH", itemText: "GridBagConstraints.SOUTH", tailText: " (java.awt)", typeText: "Int", attributes: "" } +// EXIST_JAVA_ONLY: { allLookupStrings: "SOUTHWEST, getSOUTHWEST", itemText: "GridBagConstraints.SOUTHWEST", tailText: " (java.awt)", typeText: "Int", attributes: "" } +// ABSENT: serialVersionUID diff --git a/idea/idea-completion/testData/basic/common/staticMembers/JavaStaticMethods.kt b/idea/idea-completion/testData/basic/common/staticMembers/JavaStaticMethods.kt new file mode 100644 index 00000000000..53abdefad7d --- /dev/null +++ b/idea/idea-completion/testData/basic/common/staticMembers/JavaStaticMethods.kt @@ -0,0 +1,8 @@ +fun foo() { + invoke +} + +// INVOCATION_COUNT: 2 +// EXIST_JAVA_ONLY: { allLookupStrings: "invokeLater", itemText: "SwingUtilities.invokeLater", tailText: "(Runnable!) (javax.swing)", typeText: "Unit", attributes: "" } +// EXIST_JAVA_ONLY: { allLookupStrings: "invokeAndWait", itemText: "SwingUtilities.invokeAndWait", tailText: "(Runnable!) (javax.swing)", typeText: "Unit", attributes: "" } +// ABSENT: { itemText: "SwingUtilities.convertScreenLocationToParent" } diff --git a/idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.dependency.kt b/idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.dependency.kt new file mode 100644 index 00000000000..0474c72871a --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.dependency.kt @@ -0,0 +1,19 @@ +package test + +object KotlinObject { + fun funFromObject() { } + private fun privateFun(){} +} + +class KotlinClass { + companion object SomeName { + fun funFromCompanionObject() { } + private fun privateFun(){} + } +} + +class AnotherKotlinClass { + private companion object { + fun funFromPrivateCompanionObject() { } + } +} diff --git a/idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.kt b/idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.kt new file mode 100644 index 00000000000..4290d2fbd73 --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/ObjectMembers/ObjectMembers.kt @@ -0,0 +1,11 @@ +package first + +fun testFun() { + funFromO +} + +// INVOCATION_COUNT: 2 +// EXIST: { allLookupStrings: "funFromObject", itemText: "KotlinObject.funFromObject", tailText: "() (test)", typeText: "Unit", attributes: "" } +// EXIST: { allLookupStrings: "funFromCompanionObject", itemText: "KotlinClass.funFromCompanionObject", tailText: "() (test)", typeText: "Unit", attributes: "" } +// ABSENT: privateFun +// ABSENT: funFromPrivateCompanionObject diff --git a/idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt b/idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt new file mode 100644 index 00000000000..3d74bb7608d --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt @@ -0,0 +1,6 @@ +fun foo() { + invoke +} + +// INVOCATION_COUNT: 2 +// ELEMENT_TEXT: "SwingUtilities.invokeLater" diff --git a/idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt.after b/idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt.after new file mode 100644 index 00000000000..28a783270e3 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt.after @@ -0,0 +1,8 @@ +import javax.swing.SwingUtilities + +fun foo() { + SwingUtilities.invokeLater() +} + +// INVOCATION_COUNT: 2 +// ELEMENT_TEXT: "SwingUtilities.invokeLater" diff --git a/idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt b/idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt new file mode 100644 index 00000000000..0ce1618eb4a --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt @@ -0,0 +1,6 @@ +fun foo() { + fromLit +} + +// INVOCATION_COUNT: 2 +// ELEMENT_TEXT: "Regex.fromLiteral" diff --git a/idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt.after b/idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt.after new file mode 100644 index 00000000000..a0dba170c47 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt.after @@ -0,0 +1,8 @@ +import kotlin.text.Regex + +fun foo() { + Regex.fromLiteral() +} + +// INVOCATION_COUNT: 2 +// ELEMENT_TEXT: "Regex.fromLiteral" diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 6d3d71bbda2..8b1a6b9a633 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -2095,6 +2095,27 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes } } + @TestMetadata("idea/idea-completion/testData/basic/common/staticMembers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class StaticMembers extends AbstractJSBasicCompletionTest { + public void testAllFilesPresentInStaticMembers() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/staticMembers"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("JavaStaticFields.kt") + public void testJavaStaticFields() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/staticMembers/JavaStaticFields.kt"); + doTest(fileName); + } + + @TestMetadata("JavaStaticMethods.kt") + public void testJavaStaticMethods() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/staticMembers/JavaStaticMethods.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/substitutedSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index f8365b1e159..47773537839 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -2095,6 +2095,27 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT } } + @TestMetadata("idea/idea-completion/testData/basic/common/staticMembers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class StaticMembers extends AbstractJvmBasicCompletionTest { + public void testAllFilesPresentInStaticMembers() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/staticMembers"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("JavaStaticFields.kt") + public void testJavaStaticFields() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/staticMembers/JavaStaticFields.kt"); + doTest(fileName); + } + + @TestMetadata("JavaStaticMethods.kt") + public void testJavaStaticMethods() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/staticMembers/JavaStaticMethods.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/substitutedSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java index fb6bfd7a74a..efadc0584a9 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java @@ -281,6 +281,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ doTest(fileName); } + @TestMetadata("ObjectMembers") + public void testObjectMembers() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/ObjectMembers/"); + doTest(fileName); + } + @TestMetadata("ParameterNameAndTypeNestedClasses") public void testParameterNameAndTypeNestedClasses() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/ParameterNameAndTypeNestedClasses/"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java index 3384a3424f5..b121378a943 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java @@ -530,6 +530,27 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion } } + @TestMetadata("idea/idea-completion/testData/handlers/basic/staticMembers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class StaticMembers extends AbstractBasicCompletionHandlerTest { + public void testAllFilesPresentInStaticMembers() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/staticMembers"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("classObjectMethod.kt") + public void testClassObjectMethod() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/staticMembers/classObjectMethod.kt"); + doTest(fileName); + } + + @TestMetadata("JavaStaticMethod.kt") + public void testJavaStaticMethod() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/staticMembers/JavaStaticMethod.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index 3d44aecb318..daaf72bc277 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -17,10 +17,16 @@ package org.jetbrains.kotlin.idea.core import com.intellij.codeInsight.CodeInsightSettings +import com.intellij.openapi.progress.ProgressManager +import com.intellij.psi.PsiModifier import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.PsiShortNamesCache import com.intellij.psi.stubs.StringStubIndexExtension +import com.intellij.util.Processor +import com.intellij.util.indexing.IdFilter import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.caches.resolve.getJavaFieldDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.getJavaMethodDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.resolve.ResolutionFacade @@ -29,14 +35,16 @@ import org.jetbrains.kotlin.idea.util.CallType import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.receiverTypes import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtNamedDeclaration +import org.jetbrains.kotlin.psi.KtObjectDeclaration import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.isAnnotatedAsHidden import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList @@ -46,7 +54,8 @@ public class KotlinIndicesHelper( private val resolutionFacade: ResolutionFacade, private val scope: GlobalSearchScope, visibilityFilter: (DeclarationDescriptor) -> Boolean, - applyExcludeSettings: Boolean + applyExcludeSettings: Boolean = true, + private val visibilityFilterMayIncludeAccessible: Boolean = false ) { private val moduleDescriptor = resolutionFacade.moduleDescriptor @@ -60,20 +69,15 @@ public class KotlinIndicesHelper( } public fun getTopLevelCallablesByName(name: String): Collection { - val declarations = HashSet() + val declarations = HashSet() declarations.addTopLevelNonExtensionCallablesByName(KotlinFunctionShortNameIndex.getInstance(), name) declarations.addTopLevelNonExtensionCallablesByName(KotlinPropertyShortNameIndex.getInstance(), name) - return declarations.flatMap { - if (it.getContainingJetFile().isCompiled()) { //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations - resolutionFacade.resolveImportReference(moduleDescriptor, it.getFqName()!!).filterIsInstance() - } - else { - (resolutionFacade.resolveToDescriptor(it) as? CallableDescriptor).singletonOrEmptyList() - } - }.filter { it.getExtensionReceiverParameter() == null && descriptorFilter(it) } + return declarations + .flatMap { it.resolveToDescriptorsWithHack() } + .filter { it.extensionReceiverParameter == null && descriptorFilter(it) } } - private fun MutableSet.addTopLevelNonExtensionCallablesByName( + private fun MutableSet.addTopLevelNonExtensionCallablesByName( index: StringStubIndexExtension, name: String ) { @@ -84,7 +88,10 @@ public class KotlinIndicesHelper( return (KotlinTopLevelFunctionFqnNameIndex.getInstance().getAllKeys(project).asSequence() + KotlinTopLevelPropertyFqnNameIndex.getInstance().getAllKeys(project).asSequence()) .map { FqName(it) } - .filter { nameFilter(it.shortName().asString()) } + .filter { + ProgressManager.checkCanceled() + nameFilter(it.shortName().asString()) + } .toSet() .flatMap { findTopLevelCallables(it).filter(descriptorFilter) } } @@ -115,8 +122,9 @@ public class KotlinIndicesHelper( val declarations = index.getAllKeys(project) .asSequence() .filter { + ProgressManager.checkCanceled() KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames - && nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it)) + && nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it)) } .flatMap { index.get(it, project, scope).asSequence() } @@ -140,24 +148,12 @@ public class KotlinIndicesHelper( val result = LinkedHashSet() fun processDescriptor(descriptor: CallableDescriptor) { - if (descriptorFilter(descriptor)) { + if (descriptor.extensionReceiverParameter != null && descriptorFilter(descriptor)) { result.addAll(descriptor.substituteExtensionIfCallable(receiverTypes, callType)) } } - for (declaration in declarations) { - if (declaration.getContainingJetFile().isCompiled()) { - //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations - for (descriptor in resolutionFacade.resolveImportReference(moduleDescriptor, declaration.getFqName()!!)) { - if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) { - processDescriptor(descriptor) - } - } - } - else { - processDescriptor(resolutionFacade.resolveToDescriptor(declaration) as CallableDescriptor) - } - } + declarations.forEach { it.resolveToDescriptorsWithHack().forEach(::processDescriptor) } return result } @@ -172,7 +168,10 @@ public class KotlinIndicesHelper( public fun getKotlinClasses(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection { return KotlinFullClassNameIndex.getInstance().getAllKeys(project).asSequence() .map { FqName(it) } - .filter { nameFilter(it.shortName().asString()) } + .filter { + ProgressManager.checkCanceled() + nameFilter(it.shortName().asString()) + } .toList() .flatMap { getClassDescriptorsByFQName(it, kindFilter) } } @@ -190,6 +189,73 @@ public class KotlinIndicesHelper( .filter(descriptorFilter) } + public fun getObjectMembers(descriptorKindFilter: DescriptorKindFilter, nameFilter: (String) -> Boolean): Collection { + val result = LinkedHashSet() + + fun addFromIndex(index: StringStubIndexExtension) { + for (name in index.getAllKeys(project)) { + ProgressManager.checkCanceled() + if (!nameFilter(name)) continue + + for (declaration in index.get(name, project, scope)) { + if (declaration.parent.parent !is KtObjectDeclaration) continue + if (!visibilityFilterMayIncludeAccessible && declaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) continue + declaration.resolveToDescriptorsWithHack().filterTo(result) { descriptorKindFilter.accepts(it) && descriptorFilter(it) } + } + } + } + + if (descriptorKindFilter.kindMask.and(DescriptorKindFilter.FUNCTIONS_MASK) != 0) { + addFromIndex(KotlinFunctionShortNameIndex.getInstance()) + } + if (descriptorKindFilter.kindMask.and(DescriptorKindFilter.VARIABLES_MASK) != 0) { + addFromIndex(KotlinPropertyShortNameIndex.getInstance()) + } + + return result + } + + public fun getJavaStaticMembers(descriptorKindFilter: DescriptorKindFilter, nameFilter: (String) -> Boolean): Collection { + val result = LinkedHashSet() + + val idFilter = IdFilter.getProjectIdFilter(resolutionFacade.project, false) + val shortNamesCache = PsiShortNamesCache.getInstance(project) + + val methodNamesProcessor = Processor { name -> + ProgressManager.checkCanceled() + if (!nameFilter(name)) return@Processor true + + for (method in shortNamesCache.getMethodsByName(name, scope)) { + if (!method.hasModifierProperty(PsiModifier.STATIC)) continue + if (!visibilityFilterMayIncludeAccessible && method.hasModifierProperty(PsiModifier.PRIVATE)) continue + val descriptor = method.getJavaMethodDescriptor() ?: continue + if (descriptorKindFilter.accepts(descriptor) && descriptorFilter(descriptor)) { + result.add(descriptor) + } + } + true + } + shortNamesCache.processAllMethodNames(methodNamesProcessor, scope, idFilter) + + val fieldNamesProcessor = Processor { name -> + ProgressManager.checkCanceled() + if (!nameFilter(name)) return@Processor true + + for (field in shortNamesCache.getFieldsByName(name, scope)) { + if (!field.hasModifierProperty(PsiModifier.STATIC)) continue + if (!visibilityFilterMayIncludeAccessible && field.hasModifierProperty(PsiModifier.PRIVATE)) continue + val descriptor = field.getJavaFieldDescriptor() ?: continue + if (descriptorKindFilter.accepts(descriptor) && descriptorFilter(descriptor)) { + result.add(descriptor) + } + } + true + } + shortNamesCache.processAllFieldNames(fieldNamesProcessor, scope, idFilter) + + return result + } + private fun findTopLevelCallables(fqName: FqName): Collection { return resolutionFacade.resolveImportReference(moduleDescriptor, fqName) .filterIsInstance() @@ -202,5 +268,14 @@ public class KotlinIndicesHelper( return CodeInsightSettings.getInstance().EXCLUDED_PACKAGES .any { excluded -> fqName == excluded || (fqName.startsWith(excluded) && fqName[excluded.length()] == '.') } } + + private fun KtCallableDeclaration.resolveToDescriptorsWithHack(): Collection { + if (getContainingJetFile().isCompiled()) { //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations + return resolutionFacade.resolveImportReference(moduleDescriptor, fqName!!).filterIsInstance() + } + else { + return (resolutionFacade.resolveToDescriptor(this) as? CallableDescriptor).singletonOrEmptyList() + } + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt index 9960b569f37..90638830544 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt @@ -149,7 +149,7 @@ internal abstract class AutoImportFixBase(expression: T) : val result = ArrayList() - val indicesHelper = KotlinIndicesHelper(element.getResolutionFacade(), searchScope, ::isVisible, true) + val indicesHelper = KotlinIndicesHelper(element.getResolutionFacade(), searchScope, ::isVisible) val expression = element if (expression is KtSimpleNameExpression) {