Initial implementation of KT-8209 Support static member completion without writing the class name
This commit is contained in:
@@ -29,10 +29,10 @@ import java.util.*
|
|||||||
class KtClassBody : KtElementImplStub<KotlinPlaceHolderStub<KtClassBody>>, KtDeclarationContainer {
|
class KtClassBody : KtElementImplStub<KotlinPlaceHolderStub<KtClassBody>>, KtDeclarationContainer {
|
||||||
constructor(node: ASTNode) : super(node)
|
constructor(node: ASTNode) : super(node)
|
||||||
|
|
||||||
override fun getParent() = parentByStub
|
|
||||||
|
|
||||||
constructor(stub: KotlinPlaceHolderStub<KtClassBody>) : super(stub, CLASS_BODY)
|
constructor(stub: KotlinPlaceHolderStub<KtClassBody>) : super(stub, CLASS_BODY)
|
||||||
|
|
||||||
|
override fun getParent() = parentByStub
|
||||||
|
|
||||||
override fun getDeclarations() = Arrays.asList(*getStubOrPsiChildren(DECLARATION_TYPES, KtDeclaration.ARRAY_FACTORY))
|
override fun getDeclarations() = Arrays.asList(*getStubOrPsiChildren(DECLARATION_TYPES, KtDeclaration.ARRAY_FACTORY))
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D) = visitor.visitClassBody(this, data)
|
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D) = visitor.visitClassBody(this, data)
|
||||||
|
|||||||
+8
-4
@@ -196,7 +196,7 @@ class BasicCompletionSession(
|
|||||||
|
|
||||||
packageNames.forEach { collector.addElement(basicLookupElementFactory.createLookupElementForPackage(it)) }
|
packageNames.forEach { collector.addElement(basicLookupElementFactory.createLookupElementForPackage(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
flushToResultSet()
|
flushToResultSet()
|
||||||
|
|
||||||
NamedArgumentCompletion.complete(collector, expectedInfos)
|
NamedArgumentCompletion.complete(collector, expectedInfos)
|
||||||
@@ -227,6 +227,10 @@ class BasicCompletionSession(
|
|||||||
flushToResultSet()
|
flushToResultSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configuration.completeStaticMembers && callTypeAndReceiver is CallTypeAndReceiver.DEFAULT && prefix.isNotEmpty()) {
|
||||||
|
StaticMembersCompletion(collector, prefixMatcher, indicesHelper(false), lookupElementFactory).complete()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,13 +414,13 @@ class BasicCompletionSession(
|
|||||||
lookupElement
|
lookupElement
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterNameAndTypeCompletion.addFromParametersInFile(position, resolutionFacade, isVisibleFilter)
|
parameterNameAndTypeCompletion.addFromParametersInFile(position, resolutionFacade, isVisibleFilterCheckAlways)
|
||||||
flushToResultSet()
|
flushToResultSet()
|
||||||
|
|
||||||
parameterNameAndTypeCompletion.addFromImportedClasses(position, bindingContext, isVisibleFilter)
|
parameterNameAndTypeCompletion.addFromImportedClasses(position, bindingContext, isVisibleFilterCheckAlways)
|
||||||
flushToResultSet()
|
flushToResultSet()
|
||||||
|
|
||||||
parameterNameAndTypeCompletion.addFromAllClasses(parameters, indicesHelper)
|
parameterNameAndTypeCompletion.addFromAllClasses(parameters, indicesHelper(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-12
@@ -57,19 +57,23 @@ class CompletionSessionConfiguration(
|
|||||||
val completeNonImportedDeclarations: Boolean,
|
val completeNonImportedDeclarations: Boolean,
|
||||||
val completeNonAccessibleDeclarations: Boolean,
|
val completeNonAccessibleDeclarations: Boolean,
|
||||||
val filterOutJavaGettersAndSetters: Boolean,
|
val filterOutJavaGettersAndSetters: Boolean,
|
||||||
val completeJavaClassesNotToBeUsed: Boolean
|
val completeJavaClassesNotToBeUsed: Boolean,
|
||||||
|
val completeStaticMembers: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
fun CompletionSessionConfiguration(parameters: CompletionParameters) = CompletionSessionConfiguration(
|
fun CompletionSessionConfiguration(parameters: CompletionParameters) = CompletionSessionConfiguration(
|
||||||
completeNonImportedDeclarations = parameters.invocationCount >= 2,
|
completeNonImportedDeclarations = parameters.invocationCount >= 2,
|
||||||
completeNonAccessibleDeclarations = parameters.invocationCount >= 2,
|
completeNonAccessibleDeclarations = parameters.invocationCount >= 2,
|
||||||
filterOutJavaGettersAndSetters = 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,
|
abstract class CompletionSession(
|
||||||
protected val parameters: CompletionParameters,
|
protected val configuration: CompletionSessionConfiguration,
|
||||||
resultSet: CompletionResultSet) {
|
protected val parameters: CompletionParameters,
|
||||||
|
resultSet: CompletionResultSet
|
||||||
|
) {
|
||||||
protected val position = parameters.getPosition()
|
protected val position = parameters.getPosition()
|
||||||
private val file = position.getContainingFile() as KtFile
|
private val file = position.getContainingFile() as KtFile
|
||||||
protected val resolutionFacade = file.getResolutionFacade()
|
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
|
private fun ((Name) -> Boolean).or(otherFilter: (Name) -> Boolean): (Name) -> Boolean
|
||||||
= { this(it) || otherFilter(it) }
|
= { 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)
|
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()
|
override fun contains(file: VirtualFile) = super.contains(file) && file != parameters.getOriginalFile().getVirtualFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val indicesHelper: KotlinIndicesHelper
|
protected fun indicesHelper(mayIncludeInaccessible: Boolean): KotlinIndicesHelper {
|
||||||
get() = KotlinIndicesHelper(resolutionFacade, searchScope, isVisibleFilter, true)
|
val filter = if (mayIncludeInaccessible) isVisibleFilter else isVisibleFilterCheckAlways
|
||||||
|
return KotlinIndicesHelper(resolutionFacade, searchScope, filter, visibilityFilterMayIncludeAccessible = mayIncludeInaccessible)
|
||||||
|
}
|
||||||
|
|
||||||
protected val toFromOriginalFileMapper: ToFromOriginalFileMapper
|
protected val toFromOriginalFileMapper: ToFromOriginalFileMapper
|
||||||
= ToFromOriginalFileMapper(parameters.originalFile as KtFile, position.containingFile as KtFile, parameters.offset)
|
= ToFromOriginalFileMapper(parameters.originalFile as KtFile, position.containingFile as KtFile, parameters.offset)
|
||||||
@@ -178,7 +185,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
get() = 0
|
get() = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean {
|
private fun isVisibleDescriptor(descriptor: DeclarationDescriptor, completeNonAccessible: Boolean): Boolean {
|
||||||
if (!configuration.completeJavaClassesNotToBeUsed && descriptor is ClassDescriptor) {
|
if (!configuration.completeJavaClassesNotToBeUsed && descriptor is ClassDescriptor) {
|
||||||
val classification = descriptor.importableFqName?.let { importableFqNameClassifier.classify(it, isPackage = false) }
|
val classification = descriptor.importableFqName?.let { importableFqNameClassifier.classify(it, isPackage = false) }
|
||||||
if (classification == ImportableFqNameClassifier.Classification.notToBeUsedInKotlin) return false
|
if (classification == ImportableFqNameClassifier.Classification.notToBeUsedInKotlin) return false
|
||||||
@@ -189,7 +196,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
if (descriptor is DeclarationDescriptorWithVisibility) {
|
if (descriptor is DeclarationDescriptorWithVisibility) {
|
||||||
val visible = descriptor.isVisible(inDescriptor, bindingContext, nameExpression)
|
val visible = descriptor.isVisible(inDescriptor, bindingContext, nameExpression)
|
||||||
if (visible) return true
|
if (visible) return true
|
||||||
return configuration.completeNonAccessibleDeclarations && !descriptor.isFromLibrary()
|
return completeNonAccessible && !descriptor.isFromLibrary()
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -309,6 +316,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
var notImportedExtensions: Collection<CallableDescriptor> = emptyList()
|
var notImportedExtensions: Collection<CallableDescriptor> = emptyList()
|
||||||
if (callTypeAndReceiver.shouldCompleteCallableExtensions()) {
|
if (callTypeAndReceiver.shouldCompleteCallableExtensions()) {
|
||||||
val nameFilter: (String) -> Boolean = { prefixMatcher.prefixMatches(it) }
|
val nameFilter: (String) -> Boolean = { prefixMatcher.prefixMatches(it) }
|
||||||
|
val indicesHelper = indicesHelper(true)
|
||||||
val extensions = if (runtimeReceiver != null)
|
val extensions = if (runtimeReceiver != null)
|
||||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiver.type), nameFilter)
|
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiver.type), nameFilter)
|
||||||
else
|
else
|
||||||
@@ -384,7 +392,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun getTopLevelCallables(): Collection<DeclarationDescriptor> {
|
protected fun getTopLevelCallables(): Collection<DeclarationDescriptor> {
|
||||||
return indicesHelper.getTopLevelCallables({ prefixMatcher.prefixMatches(it) })
|
return indicesHelper(true).getTopLevelCallables({ prefixMatcher.prefixMatches(it) })
|
||||||
.filterShadowedNonImported()
|
.filterShadowedNonImported()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +407,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean) {
|
protected fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean) {
|
||||||
AllClassesCompletion(parameters, indicesHelper, prefixMatcher, resolutionFacade, kindFilter)
|
AllClassesCompletion(parameters, indicesHelper(true), prefixMatcher, resolutionFacade, kindFilter)
|
||||||
.collect(
|
.collect(
|
||||||
{ descriptor -> collector.addElement(basicLookupElementFactory.createLookupElement(descriptor), notImported = true) },
|
{ descriptor -> collector.addElement(basicLookupElementFactory.createLookupElement(descriptor), notImported = true) },
|
||||||
{ javaClass -> collector.addElement(basicLookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) }
|
{ javaClass -> collector.addElement(basicLookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) }
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ import com.intellij.patterns.ElementPattern
|
|||||||
import com.intellij.patterns.StandardPatterns
|
import com.intellij.patterns.StandardPatterns
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler
|
import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
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.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||||
@@ -69,7 +69,8 @@ enum class ItemPriority {
|
|||||||
DEFAULT,
|
DEFAULT,
|
||||||
IMPLEMENT,
|
IMPLEMENT,
|
||||||
OVERRIDE,
|
OVERRIDE,
|
||||||
NAMED_PARAMETER
|
NAMED_PARAMETER,
|
||||||
|
STATIC_MEMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
val ITEM_PRIORITY_KEY = Key<ItemPriority>("ITEM_PRIORITY_KEY")
|
val ITEM_PRIORITY_KEY = Key<ItemPriority>("ITEM_PRIORITY_KEY")
|
||||||
@@ -152,7 +153,7 @@ fun InsertionContext.isAfterDot(): Boolean {
|
|||||||
val chars = getDocument().getCharsSequence()
|
val chars = getDocument().getCharsSequence()
|
||||||
while (offset > 0) {
|
while (offset > 0) {
|
||||||
offset--
|
offset--
|
||||||
val c = chars.charAt(offset)
|
val c = chars[offset]
|
||||||
if (!Character.isWhitespace(c)) {
|
if (!Character.isWhitespace(c)) {
|
||||||
return c == '.'
|
return c == '.'
|
||||||
}
|
}
|
||||||
@@ -335,7 +336,7 @@ private open class BaseTypeLookupElement(type: KotlinType, baseLookupElement: Lo
|
|||||||
|
|
||||||
override fun handleInsert(context: InsertionContext) {
|
override fun handleInsert(context: InsertionContext) {
|
||||||
context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), fullText)
|
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())
|
shortenReferences(context, context.getStartOffset(), context.getTailOffset())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,3 +351,49 @@ fun <T> ElementPattern<T>.andNot(rhs: ElementPattern<T>) = StandardPatterns.and(
|
|||||||
fun <T> ElementPattern<T>.or(rhs: ElementPattern<T>) = StandardPatterns.or(this, rhs)
|
fun <T> ElementPattern<T>.or(rhs: ElementPattern<T>) = StandardPatterns.or(this, rhs)
|
||||||
|
|
||||||
fun singleCharPattern(char: Char) = StandardPatterns.character().equalTo(char)
|
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<LookupElement>(this) {
|
||||||
|
override fun getAllLookupStrings(): Set<String> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+4
-2
@@ -257,13 +257,15 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val somethingAdded = session.complete()
|
val somethingAdded = session.complete()
|
||||||
if (!somethingAdded && parameters.getInvocationCount() < 2) {
|
if (!somethingAdded && parameters.invocationCount < 2) {
|
||||||
// Rerun completion if nothing was found
|
// Rerun completion if nothing was found
|
||||||
val newConfiguration = CompletionSessionConfiguration(
|
val newConfiguration = CompletionSessionConfiguration(
|
||||||
completeNonImportedDeclarations = true,
|
completeNonImportedDeclarations = true,
|
||||||
completeNonAccessibleDeclarations = false,
|
completeNonAccessibleDeclarations = false,
|
||||||
filterOutJavaGettersAndSetters = false,
|
filterOutJavaGettersAndSetters = false,
|
||||||
completeJavaClassesNotToBeUsed = false)
|
completeJavaClassesNotToBeUsed = false,
|
||||||
|
completeStaticMembers = parameters.invocationCount > 0
|
||||||
|
)
|
||||||
BasicCompletionSession(newConfiguration, parameters, result).complete()
|
BasicCompletionSession(newConfiguration, parameters, result).complete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+60
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-48
@@ -16,24 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion.smart
|
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.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.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.completion.ExpectedInfo
|
import org.jetbrains.kotlin.idea.completion.ExpectedInfo
|
||||||
import org.jetbrains.kotlin.idea.completion.LookupElementFactory
|
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.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.core.isVisible
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
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.fuzzyReturnType
|
||||||
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
@@ -107,45 +100,10 @@ class StaticMembers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createLookupElements(memberDescriptor: DeclarationDescriptor, classDescriptor: ClassDescriptor): Collection<LookupElement> {
|
private fun createLookupElements(memberDescriptor: DeclarationDescriptor, classDescriptor: ClassDescriptor): Collection<LookupElement> {
|
||||||
val lookupElements = lookupElementFactory.createLookupElementsInSmartCompletion(memberDescriptor, bindingContext, useReceiverTypes = false)
|
return lookupElementFactory.createLookupElementsInSmartCompletion(memberDescriptor, bindingContext, useReceiverTypes = false)
|
||||||
val qualifierPresentation = classDescriptor.getName().asString()
|
.map {
|
||||||
val qualifierText = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classDescriptor)
|
it.decorateAsStaticMember(memberDescriptor, classDescriptor, classNameAsLookupString = true)
|
||||||
|
.assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER)
|
||||||
return lookupElements.map {
|
|
||||||
object: LookupElementDecorator<LookupElement>(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()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun foo() {
|
||||||
|
SOU<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun foo() {
|
||||||
|
invoke<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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" }
|
||||||
+19
@@ -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() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package first
|
||||||
|
|
||||||
|
fun testFun() {
|
||||||
|
funFromO<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo() {
|
||||||
|
invoke<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// INVOCATION_COUNT: 2
|
||||||
|
// ELEMENT_TEXT: "SwingUtilities.invokeLater"
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
import javax.swing.SwingUtilities
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
SwingUtilities.invokeLater(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// INVOCATION_COUNT: 2
|
||||||
|
// ELEMENT_TEXT: "SwingUtilities.invokeLater"
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo() {
|
||||||
|
fromLit<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// INVOCATION_COUNT: 2
|
||||||
|
// ELEMENT_TEXT: "Regex.fromLiteral"
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
import kotlin.text.Regex
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
Regex.fromLiteral(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// INVOCATION_COUNT: 2
|
||||||
|
// ELEMENT_TEXT: "Regex.fromLiteral"
|
||||||
+21
@@ -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")
|
@TestMetadata("idea/idea-completion/testData/basic/common/substitutedSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+21
@@ -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")
|
@TestMetadata("idea/idea-completion/testData/basic/common/substitutedSignature")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+6
@@ -281,6 +281,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ObjectMembers")
|
||||||
|
public void testObjectMembers() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/ObjectMembers/");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ParameterNameAndTypeNestedClasses")
|
@TestMetadata("ParameterNameAndTypeNestedClasses")
|
||||||
public void testParameterNameAndTypeNestedClasses() throws Exception {
|
public void testParameterNameAndTypeNestedClasses() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/ParameterNameAndTypeNestedClasses/");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/ParameterNameAndTypeNestedClasses/");
|
||||||
|
|||||||
+21
@@ -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")
|
@TestMetadata("idea/idea-completion/testData/handlers/basic/stringTemplate")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -17,10 +17,16 @@
|
|||||||
package org.jetbrains.kotlin.idea.core
|
package org.jetbrains.kotlin.idea.core
|
||||||
|
|
||||||
import com.intellij.codeInsight.CodeInsightSettings
|
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.GlobalSearchScope
|
||||||
import com.intellij.psi.search.PsiShortNamesCache
|
import com.intellij.psi.search.PsiShortNamesCache
|
||||||
import com.intellij.psi.stubs.StringStubIndexExtension
|
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.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.caches.resolve.resolveImportReference
|
||||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
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.CallTypeAndReceiver
|
||||||
import org.jetbrains.kotlin.idea.util.receiverTypes
|
import org.jetbrains.kotlin.idea.util.receiverTypes
|
||||||
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
|
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
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.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.isAnnotatedAsHidden
|
import org.jetbrains.kotlin.resolve.isAnnotatedAsHidden
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
|
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||||
@@ -46,7 +54,8 @@ public class KotlinIndicesHelper(
|
|||||||
private val resolutionFacade: ResolutionFacade,
|
private val resolutionFacade: ResolutionFacade,
|
||||||
private val scope: GlobalSearchScope,
|
private val scope: GlobalSearchScope,
|
||||||
visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||||
applyExcludeSettings: Boolean
|
applyExcludeSettings: Boolean = true,
|
||||||
|
private val visibilityFilterMayIncludeAccessible: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val moduleDescriptor = resolutionFacade.moduleDescriptor
|
private val moduleDescriptor = resolutionFacade.moduleDescriptor
|
||||||
@@ -60,20 +69,15 @@ public class KotlinIndicesHelper(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun getTopLevelCallablesByName(name: String): Collection<CallableDescriptor> {
|
public fun getTopLevelCallablesByName(name: String): Collection<CallableDescriptor> {
|
||||||
val declarations = HashSet<KtNamedDeclaration>()
|
val declarations = HashSet<KtCallableDeclaration>()
|
||||||
declarations.addTopLevelNonExtensionCallablesByName(KotlinFunctionShortNameIndex.getInstance(), name)
|
declarations.addTopLevelNonExtensionCallablesByName(KotlinFunctionShortNameIndex.getInstance(), name)
|
||||||
declarations.addTopLevelNonExtensionCallablesByName(KotlinPropertyShortNameIndex.getInstance(), name)
|
declarations.addTopLevelNonExtensionCallablesByName(KotlinPropertyShortNameIndex.getInstance(), name)
|
||||||
return declarations.flatMap {
|
return declarations
|
||||||
if (it.getContainingJetFile().isCompiled()) { //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations
|
.flatMap { it.resolveToDescriptorsWithHack() }
|
||||||
resolutionFacade.resolveImportReference(moduleDescriptor, it.getFqName()!!).filterIsInstance<CallableDescriptor>()
|
.filter { it.extensionReceiverParameter == null && descriptorFilter(it) }
|
||||||
}
|
|
||||||
else {
|
|
||||||
(resolutionFacade.resolveToDescriptor(it) as? CallableDescriptor).singletonOrEmptyList()
|
|
||||||
}
|
|
||||||
}.filter { it.getExtensionReceiverParameter() == null && descriptorFilter(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableSet<KtNamedDeclaration>.addTopLevelNonExtensionCallablesByName(
|
private fun MutableSet<KtCallableDeclaration>.addTopLevelNonExtensionCallablesByName(
|
||||||
index: StringStubIndexExtension<out KtCallableDeclaration>,
|
index: StringStubIndexExtension<out KtCallableDeclaration>,
|
||||||
name: String
|
name: String
|
||||||
) {
|
) {
|
||||||
@@ -84,7 +88,10 @@ public class KotlinIndicesHelper(
|
|||||||
return (KotlinTopLevelFunctionFqnNameIndex.getInstance().getAllKeys(project).asSequence() +
|
return (KotlinTopLevelFunctionFqnNameIndex.getInstance().getAllKeys(project).asSequence() +
|
||||||
KotlinTopLevelPropertyFqnNameIndex.getInstance().getAllKeys(project).asSequence())
|
KotlinTopLevelPropertyFqnNameIndex.getInstance().getAllKeys(project).asSequence())
|
||||||
.map { FqName(it) }
|
.map { FqName(it) }
|
||||||
.filter { nameFilter(it.shortName().asString()) }
|
.filter {
|
||||||
|
ProgressManager.checkCanceled()
|
||||||
|
nameFilter(it.shortName().asString())
|
||||||
|
}
|
||||||
.toSet()
|
.toSet()
|
||||||
.flatMap { findTopLevelCallables(it).filter(descriptorFilter) }
|
.flatMap { findTopLevelCallables(it).filter(descriptorFilter) }
|
||||||
}
|
}
|
||||||
@@ -115,8 +122,9 @@ public class KotlinIndicesHelper(
|
|||||||
val declarations = index.getAllKeys(project)
|
val declarations = index.getAllKeys(project)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter {
|
.filter {
|
||||||
|
ProgressManager.checkCanceled()
|
||||||
KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames
|
KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames
|
||||||
&& nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it))
|
&& nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it))
|
||||||
}
|
}
|
||||||
.flatMap { index.get(it, project, scope).asSequence() }
|
.flatMap { index.get(it, project, scope).asSequence() }
|
||||||
|
|
||||||
@@ -140,24 +148,12 @@ public class KotlinIndicesHelper(
|
|||||||
val result = LinkedHashSet<CallableDescriptor>()
|
val result = LinkedHashSet<CallableDescriptor>()
|
||||||
|
|
||||||
fun processDescriptor(descriptor: CallableDescriptor) {
|
fun processDescriptor(descriptor: CallableDescriptor) {
|
||||||
if (descriptorFilter(descriptor)) {
|
if (descriptor.extensionReceiverParameter != null && descriptorFilter(descriptor)) {
|
||||||
result.addAll(descriptor.substituteExtensionIfCallable(receiverTypes, callType))
|
result.addAll(descriptor.substituteExtensionIfCallable(receiverTypes, callType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (declaration in declarations) {
|
declarations.forEach { it.resolveToDescriptorsWithHack().forEach(::processDescriptor) }
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -172,7 +168,10 @@ public class KotlinIndicesHelper(
|
|||||||
public fun getKotlinClasses(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
public fun getKotlinClasses(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
||||||
return KotlinFullClassNameIndex.getInstance().getAllKeys(project).asSequence()
|
return KotlinFullClassNameIndex.getInstance().getAllKeys(project).asSequence()
|
||||||
.map { FqName(it) }
|
.map { FqName(it) }
|
||||||
.filter { nameFilter(it.shortName().asString()) }
|
.filter {
|
||||||
|
ProgressManager.checkCanceled()
|
||||||
|
nameFilter(it.shortName().asString())
|
||||||
|
}
|
||||||
.toList()
|
.toList()
|
||||||
.flatMap { getClassDescriptorsByFQName(it, kindFilter) }
|
.flatMap { getClassDescriptorsByFQName(it, kindFilter) }
|
||||||
}
|
}
|
||||||
@@ -190,6 +189,73 @@ public class KotlinIndicesHelper(
|
|||||||
.filter(descriptorFilter)
|
.filter(descriptorFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun getObjectMembers(descriptorKindFilter: DescriptorKindFilter, nameFilter: (String) -> Boolean): Collection<CallableDescriptor> {
|
||||||
|
val result = LinkedHashSet<CallableDescriptor>()
|
||||||
|
|
||||||
|
fun addFromIndex(index: StringStubIndexExtension<out KtCallableDeclaration>) {
|
||||||
|
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<CallableDescriptor> {
|
||||||
|
val result = LinkedHashSet<CallableDescriptor>()
|
||||||
|
|
||||||
|
val idFilter = IdFilter.getProjectIdFilter(resolutionFacade.project, false)
|
||||||
|
val shortNamesCache = PsiShortNamesCache.getInstance(project)
|
||||||
|
|
||||||
|
val methodNamesProcessor = Processor<String> { 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<String> { 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<CallableDescriptor> {
|
private fun findTopLevelCallables(fqName: FqName): Collection<CallableDescriptor> {
|
||||||
return resolutionFacade.resolveImportReference(moduleDescriptor, fqName)
|
return resolutionFacade.resolveImportReference(moduleDescriptor, fqName)
|
||||||
.filterIsInstance<CallableDescriptor>()
|
.filterIsInstance<CallableDescriptor>()
|
||||||
@@ -202,5 +268,14 @@ public class KotlinIndicesHelper(
|
|||||||
return CodeInsightSettings.getInstance().EXCLUDED_PACKAGES
|
return CodeInsightSettings.getInstance().EXCLUDED_PACKAGES
|
||||||
.any { excluded -> fqName == excluded || (fqName.startsWith(excluded) && fqName[excluded.length()] == '.') }
|
.any { excluded -> fqName == excluded || (fqName.startsWith(excluded) && fqName[excluded.length()] == '.') }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KtCallableDeclaration.resolveToDescriptorsWithHack(): Collection<CallableDescriptor> {
|
||||||
|
if (getContainingJetFile().isCompiled()) { //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations
|
||||||
|
return resolutionFacade.resolveImportReference(moduleDescriptor, fqName!!).filterIsInstance<CallableDescriptor>()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (resolutionFacade.resolveToDescriptor(this) as? CallableDescriptor).singletonOrEmptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ internal abstract class AutoImportFixBase<T: KtExpression>(expression: T) :
|
|||||||
|
|
||||||
val result = ArrayList<DeclarationDescriptor>()
|
val result = ArrayList<DeclarationDescriptor>()
|
||||||
|
|
||||||
val indicesHelper = KotlinIndicesHelper(element.getResolutionFacade(), searchScope, ::isVisible, true)
|
val indicesHelper = KotlinIndicesHelper(element.getResolutionFacade(), searchScope, ::isVisible)
|
||||||
|
|
||||||
val expression = element
|
val expression = element
|
||||||
if (expression is KtSimpleNameExpression) {
|
if (expression is KtSimpleNameExpression) {
|
||||||
|
|||||||
Reference in New Issue
Block a user