Split LookupElementFactory into 3 classes
This commit is contained in:
+261
@@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* 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.lookup.*
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
|
import org.jetbrains.kotlin.idea.completion.handlers.BaseDeclarationInsertHandler
|
||||||
|
import org.jetbrains.kotlin.idea.completion.handlers.KotlinClassifierInsertHandler
|
||||||
|
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||||
|
import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||||
|
|
||||||
|
class BasicLookupElementFactory(
|
||||||
|
private val project: Project,
|
||||||
|
private val insertHandlerProvider: InsertHandlerProvider
|
||||||
|
) {
|
||||||
|
public fun createLookupElement(
|
||||||
|
descriptor: DeclarationDescriptor,
|
||||||
|
qualifyNestedClasses: Boolean = false,
|
||||||
|
includeClassTypeArguments: Boolean = true
|
||||||
|
): LookupElement {
|
||||||
|
val _descriptor = if (descriptor is CallableMemberDescriptor)
|
||||||
|
DescriptorUtils.unwrapFakeOverride(descriptor)
|
||||||
|
else
|
||||||
|
descriptor
|
||||||
|
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, _descriptor)
|
||||||
|
return createLookupElement(_descriptor, declaration, qualifyNestedClasses, includeClassTypeArguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun createLookupElementForJavaClass(psiClass: PsiClass, qualifyNestedClasses: Boolean = false, includeClassTypeArguments: Boolean = true): LookupElement {
|
||||||
|
val lookupObject = object : DeclarationLookupObjectImpl(null, psiClass) {
|
||||||
|
override fun getIcon(flags: Int) = psiClass.getIcon(flags)
|
||||||
|
}
|
||||||
|
var element = LookupElementBuilder.create(lookupObject, psiClass.getName()!!)
|
||||||
|
.withInsertHandler(KotlinClassifierInsertHandler)
|
||||||
|
|
||||||
|
val typeParams = psiClass.getTypeParameters()
|
||||||
|
if (includeClassTypeArguments && typeParams.isNotEmpty()) {
|
||||||
|
element = element.appendTailText(typeParams.map { it.getName() }.joinToString(", ", "<", ">"), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val qualifiedName = psiClass.getQualifiedName()!!
|
||||||
|
var containerName = qualifiedName.substringBeforeLast('.', FqName.ROOT.toString())
|
||||||
|
|
||||||
|
if (qualifyNestedClasses) {
|
||||||
|
val nestLevel = psiClass.parents.takeWhile { it is PsiClass }.count()
|
||||||
|
if (nestLevel > 0) {
|
||||||
|
var itemText = psiClass.getName()
|
||||||
|
for (i in 1..nestLevel) {
|
||||||
|
val outerClassName = containerName.substringAfterLast('.')
|
||||||
|
element = element.withLookupString(outerClassName)
|
||||||
|
itemText = outerClassName + "." + itemText
|
||||||
|
containerName = containerName.substringBeforeLast('.', FqName.ROOT.toString())
|
||||||
|
}
|
||||||
|
element = element.withPresentableText(itemText!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
element = element.appendTailText(" ($containerName)", true)
|
||||||
|
|
||||||
|
if (lookupObject.isDeprecated) {
|
||||||
|
element = element.withStrikeoutness(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return element.withIconFromLookupObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun createLookupElementForPackage(name: FqName): LookupElement {
|
||||||
|
var element = LookupElementBuilder.create(PackageLookupObject(name), name.shortName().asString())
|
||||||
|
|
||||||
|
element = element.withInsertHandler(BaseDeclarationInsertHandler())
|
||||||
|
|
||||||
|
if (!name.parent().isRoot()) {
|
||||||
|
element = element.appendTailText(" (${name.asString()})", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return element.withIconFromLookupObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createLookupElement(
|
||||||
|
descriptor: DeclarationDescriptor,
|
||||||
|
declaration: PsiElement?,
|
||||||
|
qualifyNestedClasses: Boolean,
|
||||||
|
includeClassTypeArguments: Boolean
|
||||||
|
): LookupElement {
|
||||||
|
if (descriptor is ClassifierDescriptor &&
|
||||||
|
declaration is PsiClass &&
|
||||||
|
declaration !is KotlinLightClass) {
|
||||||
|
// for java classes we create special lookup elements
|
||||||
|
// because they must be equal to ones created in TypesCompletion
|
||||||
|
// otherwise we may have duplicates
|
||||||
|
return createLookupElementForJavaClass(declaration, qualifyNestedClasses, includeClassTypeArguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor is PackageViewDescriptor) {
|
||||||
|
return createLookupElementForPackage(descriptor.fqName)
|
||||||
|
}
|
||||||
|
if (descriptor is PackageFragmentDescriptor) {
|
||||||
|
return createLookupElementForPackage(descriptor.fqName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for constructor use name and icon of containing class
|
||||||
|
val nameAndIconDescriptor: DeclarationDescriptor
|
||||||
|
val iconDeclaration: PsiElement?
|
||||||
|
if (descriptor is ConstructorDescriptor) {
|
||||||
|
nameAndIconDescriptor = descriptor.getContainingDeclaration()
|
||||||
|
iconDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, nameAndIconDescriptor)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nameAndIconDescriptor = descriptor
|
||||||
|
iconDeclaration = declaration
|
||||||
|
}
|
||||||
|
val name = nameAndIconDescriptor.getName().asString()
|
||||||
|
|
||||||
|
val lookupObject = object : DeclarationLookupObjectImpl(descriptor, declaration) {
|
||||||
|
override fun getIcon(flags: Int) = JetDescriptorIconProvider.getIcon(nameAndIconDescriptor, iconDeclaration, flags)
|
||||||
|
}
|
||||||
|
var element = LookupElementBuilder.create(lookupObject, name)
|
||||||
|
|
||||||
|
val insertHandler = insertHandlerProvider.insertHandler(descriptor)
|
||||||
|
element = element.withInsertHandler(insertHandler)
|
||||||
|
|
||||||
|
when (descriptor) {
|
||||||
|
is FunctionDescriptor -> {
|
||||||
|
val returnType = descriptor.getReturnType()
|
||||||
|
element = element.withTypeText(if (returnType != null) DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(returnType) else "")
|
||||||
|
|
||||||
|
val insertsLambda = (insertHandler as KotlinFunctionInsertHandler).lambdaInfo != null
|
||||||
|
if (insertsLambda) {
|
||||||
|
element = element.appendTailText(" {...} ", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
element = element.appendTailText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderFunctionParameters(descriptor), insertsLambda)
|
||||||
|
}
|
||||||
|
|
||||||
|
is VariableDescriptor -> {
|
||||||
|
element = element.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(descriptor.getType()))
|
||||||
|
}
|
||||||
|
|
||||||
|
is ClassDescriptor -> {
|
||||||
|
val typeParams = descriptor.getTypeConstructor().getParameters()
|
||||||
|
if (includeClassTypeArguments && typeParams.isNotEmpty()) {
|
||||||
|
element = element.appendTailText(typeParams.map { it.getName().asString() }.joinToString(", ", "<", ">"), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = descriptor.getContainingDeclaration()
|
||||||
|
|
||||||
|
if (qualifyNestedClasses) {
|
||||||
|
element = element.withPresentableText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderClassifierName(descriptor))
|
||||||
|
|
||||||
|
while (container is ClassDescriptor) {
|
||||||
|
element = element.withLookupString(container.name.asString())
|
||||||
|
container = container.getContainingDeclaration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container is PackageFragmentDescriptor || container is ClassDescriptor) {
|
||||||
|
element = element.appendTailText(" (" + DescriptorUtils.getFqName(container) + ")", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
element = element.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor is CallableDescriptor) {
|
||||||
|
val extensionReceiver = descriptor.original.extensionReceiverParameter
|
||||||
|
when {
|
||||||
|
descriptor is SyntheticJavaPropertyDescriptor -> {
|
||||||
|
var from = descriptor.getMethod.getName().asString() + "()"
|
||||||
|
descriptor.setMethod?.let { from += "/" + it.getName().asString() + "()" }
|
||||||
|
element = element.appendTailText(" (from $from)", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to show them as extensions
|
||||||
|
descriptor is SamAdapterExtensionFunctionDescriptor -> {}
|
||||||
|
|
||||||
|
extensionReceiver != null -> {
|
||||||
|
val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type)
|
||||||
|
element = element.appendTailText(" for $receiverPresentation", true)
|
||||||
|
|
||||||
|
val container = descriptor.getContainingDeclaration()
|
||||||
|
val containerPresentation = if (container is ClassDescriptor)
|
||||||
|
DescriptorUtils.getFqNameFromTopLevelClass(container).toString()
|
||||||
|
else if (container is PackageFragmentDescriptor)
|
||||||
|
container.fqName.toString()
|
||||||
|
else
|
||||||
|
null
|
||||||
|
if (containerPresentation != null) {
|
||||||
|
element = element.appendTailText(" in $containerPresentation", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val container = descriptor.getContainingDeclaration()
|
||||||
|
if (container is PackageFragmentDescriptor) { // we show container only for global functions and properties
|
||||||
|
//TODO: it would be probably better to show it also for static declarations which are not from the current class (imported)
|
||||||
|
element = element.appendTailText(" (${container.fqName})", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor is PropertyDescriptor) {
|
||||||
|
val getterName = JvmAbi.getterName(name)
|
||||||
|
if (getterName != name) {
|
||||||
|
element = element.withLookupString(getterName)
|
||||||
|
}
|
||||||
|
if (descriptor.isVar) {
|
||||||
|
element = element.withLookupString(JvmAbi.setterName(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lookupObject.isDeprecated) {
|
||||||
|
element = element.withStrikeoutness(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insertHandler is KotlinFunctionInsertHandler && insertHandler.lambdaInfo != null) {
|
||||||
|
element.putUserData(KotlinCompletionCharFilter.ACCEPT_OPENING_BRACE, Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
return element.withIconFromLookupObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun LookupElement.withIconFromLookupObject(): LookupElement {
|
||||||
|
// add icon in renderElement only to pass presentation.isReal()
|
||||||
|
return object : LookupElementDecorator<LookupElement>(this) {
|
||||||
|
override fun renderElement(presentation: LookupElementPresentation) {
|
||||||
|
super.renderElement(presentation)
|
||||||
|
presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this@withIconFromLookupObject, presentation.isReal()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -168,7 +168,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LookupElementFactory(resolutionFacade, receiverTypes, factoryContext, inDescriptor, { expectedInfos })
|
LookupElementFactory(resolutionFacade, receiverTypes, factoryContext, inDescriptor, InsertHandlerProvider { expectedInfos })
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
||||||
|
|||||||
+1
-16
@@ -17,20 +17,17 @@
|
|||||||
package org.jetbrains.kotlin.idea.completion
|
package org.jetbrains.kotlin.idea.completion
|
||||||
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.util.Iconable
|
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiDocCommentOwner
|
import com.intellij.psi.PsiDocCommentOwner
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiNamedElement
|
import com.intellij.psi.PsiNamedElement
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
|
||||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||||
import javax.swing.Icon
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores information about resolved descriptor and position of that descriptor.
|
* Stores information about resolved descriptor and position of that descriptor.
|
||||||
@@ -38,8 +35,7 @@ import javax.swing.Icon
|
|||||||
*/
|
*/
|
||||||
public abstract class DeclarationLookupObjectImpl(
|
public abstract class DeclarationLookupObjectImpl(
|
||||||
public final override val descriptor: DeclarationDescriptor?,
|
public final override val descriptor: DeclarationDescriptor?,
|
||||||
public final override val psiElement: PsiElement?,
|
public final override val psiElement: PsiElement?
|
||||||
private val resolutionFacade: ResolutionFacade
|
|
||||||
): DeclarationLookupObject {
|
): DeclarationLookupObject {
|
||||||
init {
|
init {
|
||||||
assert(descriptor != null || psiElement != null)
|
assert(descriptor != null || psiElement != null)
|
||||||
@@ -65,20 +61,9 @@ public abstract class DeclarationLookupObjectImpl(
|
|||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this identityEquals other) return true
|
if (this identityEquals other) return true
|
||||||
if (other == null || javaClass != other.javaClass) return false
|
if (other == null || javaClass != other.javaClass) return false
|
||||||
|
|
||||||
val lookupObject = other as DeclarationLookupObjectImpl
|
val lookupObject = other as DeclarationLookupObjectImpl
|
||||||
|
|
||||||
if (resolutionFacade != lookupObject.resolutionFacade) {
|
|
||||||
LOG.warn("Descriptors from different resolve sessions")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return descriptorsEqualWithSubstitution(descriptor, lookupObject.descriptor) && psiElement == lookupObject.psiElement
|
return descriptorsEqualWithSubstitution(descriptor, lookupObject.descriptor) && psiElement == lookupObject.psiElement
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isDeprecated = if (descriptor != null) KotlinBuiltIns.isDeprecated(descriptor) else (psiElement as? PsiDocCommentOwner)?.isDeprecated() ?: false
|
override val isDeprecated = if (descriptor != null) KotlinBuiltIns.isDeprecated(descriptor) else (psiElement as? PsiDocCommentOwner)?.isDeprecated() ?: false
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val LOG = Logger.getInstance("#" + javaClass<DeclarationLookupObject>().getName())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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.InsertHandler
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.idea.completion.handlers.*
|
||||||
|
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||||
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class InsertHandlerProvider(expectedInfosCalculator: () -> Collection<ExpectedInfo>) {
|
||||||
|
private val expectedInfos by lazy { expectedInfosCalculator() }
|
||||||
|
|
||||||
|
public fun insertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
|
||||||
|
return when (descriptor) {
|
||||||
|
is FunctionDescriptor -> {
|
||||||
|
val needTypeArguments = needTypeArguments(descriptor)
|
||||||
|
val parameters = descriptor.valueParameters
|
||||||
|
when (parameters.size()) {
|
||||||
|
0 -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = false)
|
||||||
|
|
||||||
|
1 -> {
|
||||||
|
val parameterType = parameters.single().getType()
|
||||||
|
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
||||||
|
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
||||||
|
if (parameterCount <= 1) {
|
||||||
|
// otherwise additional item with lambda template is to be added
|
||||||
|
return KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = GenerateLambdaInfo(parameterType, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is PropertyDescriptor -> KotlinPropertyInsertHandler
|
||||||
|
|
||||||
|
is ClassifierDescriptor -> KotlinClassifierInsertHandler
|
||||||
|
|
||||||
|
else -> BaseDeclarationInsertHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun needTypeArguments(function: FunctionDescriptor): Boolean {
|
||||||
|
if (function.typeParameters.isEmpty()) return false
|
||||||
|
|
||||||
|
val originalFunction = function.original
|
||||||
|
val typeParameters = originalFunction.typeParameters
|
||||||
|
|
||||||
|
val potentiallyInferred = HashSet<TypeParameterDescriptor>()
|
||||||
|
|
||||||
|
fun addPotentiallyInferred(type: JetType) {
|
||||||
|
val descriptor = type.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||||
|
if (descriptor != null && descriptor in typeParameters) {
|
||||||
|
potentiallyInferred.add(descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(type) && KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(type).size() <= 1) {
|
||||||
|
// do not rely on inference from input of function type with one or no arguments - use only return type of functional type
|
||||||
|
addPotentiallyInferred(KotlinBuiltIns.getReturnTypeFromFunctionType(type))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (argument in type.arguments) {
|
||||||
|
if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion
|
||||||
|
addPotentiallyInferred(argument.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
originalFunction.extensionReceiverParameter?.type?.let { addPotentiallyInferred(it) }
|
||||||
|
originalFunction.valueParameters.forEach { addPotentiallyInferred(it.type) }
|
||||||
|
|
||||||
|
fun allTypeParametersPotentiallyInferred() = originalFunction.typeParameters.all { it in potentiallyInferred }
|
||||||
|
|
||||||
|
if (allTypeParametersPotentiallyInferred()) return false
|
||||||
|
|
||||||
|
val returnType = originalFunction.returnType
|
||||||
|
// check that there is an expected type and return value from the function can potentially match it
|
||||||
|
if (returnType != null) {
|
||||||
|
addPotentiallyInferred(returnType)
|
||||||
|
|
||||||
|
if (allTypeParametersPotentiallyInferred() && expectedInfos.any { it.fuzzyType?.checkIsSuperTypeOf(originalFunction.fuzzyReturnType()!!) != null }) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-307
@@ -16,30 +16,22 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion
|
package org.jetbrains.kotlin.idea.completion
|
||||||
|
|
||||||
import com.intellij.codeInsight.completion.InsertHandler
|
|
||||||
import com.intellij.codeInsight.completion.InsertionContext
|
import com.intellij.codeInsight.completion.InsertionContext
|
||||||
import com.intellij.codeInsight.lookup.*
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||||
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer
|
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.util.PlatformIcons
|
import com.intellij.util.PlatformIcons
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
import org.jetbrains.kotlin.idea.completion.handlers.GenerateLambdaInfo
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.*
|
import org.jetbrains.kotlin.idea.completion.handlers.buildLambdaPresentation
|
||||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
|
||||||
import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject
|
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.psi.JetProperty
|
import org.jetbrains.kotlin.psi.JetProperty
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -49,23 +41,22 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
|||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
public class LookupElementFactory(
|
class LookupElementFactory(
|
||||||
private val resolutionFacade: ResolutionFacade,
|
private val resolutionFacade: ResolutionFacade,
|
||||||
private val receiverTypes: Collection<JetType>,
|
private val receiverTypes: Collection<JetType>,
|
||||||
private val context: LookupElementFactory.Context,
|
private val context: LookupElementFactory.Context,
|
||||||
private val inDescriptor: DeclarationDescriptor?,
|
private val inDescriptor: DeclarationDescriptor?,
|
||||||
expectedInfosCalculator: () -> Collection<ExpectedInfo>
|
public val insertHandlerProvider: InsertHandlerProvider
|
||||||
) {
|
) {
|
||||||
|
private val basicFactory = BasicLookupElementFactory(resolutionFacade.project, insertHandlerProvider)
|
||||||
|
|
||||||
public enum class Context {
|
public enum class Context {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
STRING_TEMPLATE_AFTER_DOLLAR,
|
STRING_TEMPLATE_AFTER_DOLLAR,
|
||||||
INFIX_CALL
|
INFIX_CALL
|
||||||
}
|
}
|
||||||
|
|
||||||
private val expectedInfos by lazy { expectedInfosCalculator() }
|
|
||||||
|
|
||||||
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||||
val result = SmartList<LookupElement>()
|
val result = SmartList<LookupElement>()
|
||||||
|
|
||||||
@@ -106,7 +97,7 @@ public class LookupElementFactory(
|
|||||||
|
|
||||||
private fun createFunctionCallElementWithExplicitLambdaParameters(descriptor: FunctionDescriptor, parameterType: JetType, useReceiverTypes: Boolean): LookupElement {
|
private fun createFunctionCallElementWithExplicitLambdaParameters(descriptor: FunctionDescriptor, parameterType: JetType, useReceiverTypes: Boolean): LookupElement {
|
||||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||||
val needTypeArguments = (getDefaultInsertHandler(descriptor) as KotlinFunctionInsertHandler).needTypeArguments
|
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler).needTypeArguments
|
||||||
val lambdaInfo = GenerateLambdaInfo(parameterType, true)
|
val lambdaInfo = GenerateLambdaInfo(parameterType, true)
|
||||||
|
|
||||||
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||||
@@ -166,12 +157,7 @@ public class LookupElementFactory(
|
|||||||
qualifyNestedClasses: Boolean = false,
|
qualifyNestedClasses: Boolean = false,
|
||||||
includeClassTypeArguments: Boolean = true
|
includeClassTypeArguments: Boolean = true
|
||||||
): LookupElement {
|
): LookupElement {
|
||||||
val _descriptor = if (descriptor is CallableMemberDescriptor)
|
var element = basicFactory.createLookupElement(descriptor, qualifyNestedClasses, includeClassTypeArguments)
|
||||||
DescriptorUtils.unwrapFakeOverride(descriptor)
|
|
||||||
else
|
|
||||||
descriptor
|
|
||||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(resolutionFacade.project, _descriptor)
|
|
||||||
var element = createLookupElement(_descriptor, declaration, qualifyNestedClasses, includeClassTypeArguments)
|
|
||||||
|
|
||||||
val weight = callableWeight(descriptor)
|
val weight = callableWeight(descriptor)
|
||||||
if (weight != null) {
|
if (weight != null) {
|
||||||
@@ -220,212 +206,6 @@ public class LookupElementFactory(
|
|||||||
GRAYED
|
GRAYED
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun createLookupElementForJavaClass(psiClass: PsiClass, qualifyNestedClasses: Boolean = false, includeClassTypeArguments: Boolean = true): LookupElement {
|
|
||||||
val lookupObject = object : DeclarationLookupObjectImpl(null, psiClass, resolutionFacade) {
|
|
||||||
override fun getIcon(flags: Int) = psiClass.getIcon(flags)
|
|
||||||
}
|
|
||||||
var element = LookupElementBuilder.create(lookupObject, psiClass.getName()!!)
|
|
||||||
.withInsertHandler(KotlinClassifierInsertHandler)
|
|
||||||
|
|
||||||
val typeParams = psiClass.getTypeParameters()
|
|
||||||
if (includeClassTypeArguments && typeParams.isNotEmpty()) {
|
|
||||||
element = element.appendTailText(typeParams.map { it.getName() }.joinToString(", ", "<", ">"), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val qualifiedName = psiClass.getQualifiedName()!!
|
|
||||||
var containerName = qualifiedName.substringBeforeLast('.', FqName.ROOT.toString())
|
|
||||||
|
|
||||||
if (qualifyNestedClasses) {
|
|
||||||
val nestLevel = psiClass.parents.takeWhile { it is PsiClass }.count()
|
|
||||||
if (nestLevel > 0) {
|
|
||||||
var itemText = psiClass.getName()
|
|
||||||
for (i in 1..nestLevel) {
|
|
||||||
val outerClassName = containerName.substringAfterLast('.')
|
|
||||||
element = element.withLookupString(outerClassName)
|
|
||||||
itemText = outerClassName + "." + itemText
|
|
||||||
containerName = containerName.substringBeforeLast('.', FqName.ROOT.toString())
|
|
||||||
}
|
|
||||||
element = element.withPresentableText(itemText!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
element = element.appendTailText(" ($containerName)", true)
|
|
||||||
|
|
||||||
if (lookupObject.isDeprecated) {
|
|
||||||
element = element.withStrikeoutness(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return element.withIconFromLookupObject()
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun createLookupElementForPackage(name: FqName): LookupElement {
|
|
||||||
var element = LookupElementBuilder.create(PackageLookupObject(name), name.shortName().asString())
|
|
||||||
|
|
||||||
element = element.withInsertHandler(BaseDeclarationInsertHandler())
|
|
||||||
|
|
||||||
if (!name.parent().isRoot()) {
|
|
||||||
element = element.appendTailText(" (${name.asString()})", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return element.withIconFromLookupObject()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createLookupElement(
|
|
||||||
descriptor: DeclarationDescriptor,
|
|
||||||
declaration: PsiElement?,
|
|
||||||
qualifyNestedClasses: Boolean,
|
|
||||||
includeClassTypeArguments: Boolean
|
|
||||||
): LookupElement {
|
|
||||||
if (descriptor is ClassifierDescriptor &&
|
|
||||||
declaration is PsiClass &&
|
|
||||||
declaration !is KotlinLightClass) {
|
|
||||||
// for java classes we create special lookup elements
|
|
||||||
// because they must be equal to ones created in TypesCompletion
|
|
||||||
// otherwise we may have duplicates
|
|
||||||
return createLookupElementForJavaClass(declaration, qualifyNestedClasses, includeClassTypeArguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor is PackageViewDescriptor) {
|
|
||||||
return createLookupElementForPackage(descriptor.fqName)
|
|
||||||
}
|
|
||||||
if (descriptor is PackageFragmentDescriptor) {
|
|
||||||
return createLookupElementForPackage(descriptor.fqName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// for constructor use name and icon of containing class
|
|
||||||
val nameAndIconDescriptor: DeclarationDescriptor
|
|
||||||
val iconDeclaration: PsiElement?
|
|
||||||
if (descriptor is ConstructorDescriptor) {
|
|
||||||
nameAndIconDescriptor = descriptor.getContainingDeclaration()
|
|
||||||
iconDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(resolutionFacade.project, nameAndIconDescriptor)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nameAndIconDescriptor = descriptor
|
|
||||||
iconDeclaration = declaration
|
|
||||||
}
|
|
||||||
val name = nameAndIconDescriptor.getName().asString()
|
|
||||||
|
|
||||||
val lookupObject = object : DeclarationLookupObjectImpl(descriptor, declaration, resolutionFacade) {
|
|
||||||
override fun getIcon(flags: Int) = JetDescriptorIconProvider.getIcon(nameAndIconDescriptor, iconDeclaration, flags)
|
|
||||||
}
|
|
||||||
var element = LookupElementBuilder.create(lookupObject, name)
|
|
||||||
|
|
||||||
val insertHandler = getDefaultInsertHandler(descriptor)
|
|
||||||
element = element.withInsertHandler(insertHandler)
|
|
||||||
|
|
||||||
when (descriptor) {
|
|
||||||
is FunctionDescriptor -> {
|
|
||||||
val returnType = descriptor.getReturnType()
|
|
||||||
element = element.withTypeText(if (returnType != null) DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(returnType) else "")
|
|
||||||
|
|
||||||
val insertsLambda = (insertHandler as KotlinFunctionInsertHandler).lambdaInfo != null
|
|
||||||
if (insertsLambda) {
|
|
||||||
element = element.appendTailText(" {...} ", false)
|
|
||||||
}
|
|
||||||
|
|
||||||
element = element.appendTailText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderFunctionParameters(descriptor), insertsLambda)
|
|
||||||
}
|
|
||||||
|
|
||||||
is VariableDescriptor -> {
|
|
||||||
element = element.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(descriptor.getType()))
|
|
||||||
}
|
|
||||||
|
|
||||||
is ClassDescriptor -> {
|
|
||||||
val typeParams = descriptor.getTypeConstructor().getParameters()
|
|
||||||
if (includeClassTypeArguments && typeParams.isNotEmpty()) {
|
|
||||||
element = element.appendTailText(typeParams.map { it.getName().asString() }.joinToString(", ", "<", ">"), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
var container = descriptor.getContainingDeclaration()
|
|
||||||
|
|
||||||
if (qualifyNestedClasses) {
|
|
||||||
element = element.withPresentableText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderClassifierName(descriptor))
|
|
||||||
|
|
||||||
while (container is ClassDescriptor) {
|
|
||||||
element = element.withLookupString(container.name.asString())
|
|
||||||
container = container.getContainingDeclaration()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (container is PackageFragmentDescriptor || container is ClassDescriptor) {
|
|
||||||
element = element.appendTailText(" (" + DescriptorUtils.getFqName(container) + ")", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
element = element.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor is CallableDescriptor) {
|
|
||||||
val extensionReceiver = descriptor.original.extensionReceiverParameter
|
|
||||||
when {
|
|
||||||
descriptor is SyntheticJavaPropertyDescriptor -> {
|
|
||||||
var from = descriptor.getMethod.getName().asString() + "()"
|
|
||||||
descriptor.setMethod?.let { from += "/" + it.getName().asString() + "()" }
|
|
||||||
element = element.appendTailText(" (from $from)", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// no need to show them as extensions
|
|
||||||
descriptor is SamAdapterExtensionFunctionDescriptor -> {}
|
|
||||||
|
|
||||||
extensionReceiver != null -> {
|
|
||||||
val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type)
|
|
||||||
element = element.appendTailText(" for $receiverPresentation", true)
|
|
||||||
|
|
||||||
val container = descriptor.getContainingDeclaration()
|
|
||||||
val containerPresentation = if (container is ClassDescriptor)
|
|
||||||
DescriptorUtils.getFqNameFromTopLevelClass(container).toString()
|
|
||||||
else if (container is PackageFragmentDescriptor)
|
|
||||||
container.fqName.toString()
|
|
||||||
else
|
|
||||||
null
|
|
||||||
if (containerPresentation != null) {
|
|
||||||
element = element.appendTailText(" in $containerPresentation", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
val container = descriptor.getContainingDeclaration()
|
|
||||||
if (container is PackageFragmentDescriptor) { // we show container only for global functions and properties
|
|
||||||
//TODO: it would be probably better to show it also for static declarations which are not from the current class (imported)
|
|
||||||
element = element.appendTailText(" (${container.fqName})", true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor is PropertyDescriptor) {
|
|
||||||
val getterName = JvmAbi.getterName(name)
|
|
||||||
if (getterName != name) {
|
|
||||||
element = element.withLookupString(getterName)
|
|
||||||
}
|
|
||||||
if (descriptor.isVar) {
|
|
||||||
element = element.withLookupString(JvmAbi.setterName(name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lookupObject.isDeprecated) {
|
|
||||||
element = element.withStrikeoutness(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insertHandler is KotlinFunctionInsertHandler && insertHandler.lambdaInfo != null) {
|
|
||||||
element.putUserData(KotlinCompletionCharFilter.ACCEPT_OPENING_BRACE, Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
return element.withIconFromLookupObject()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun LookupElement.withIconFromLookupObject(): LookupElement {
|
|
||||||
// add icon in renderElement only to pass presentation.isReal()
|
|
||||||
return object : LookupElementDecorator<LookupElement>(this) {
|
|
||||||
override fun renderElement(presentation: LookupElementPresentation) {
|
|
||||||
super.renderElement(presentation)
|
|
||||||
presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this@withIconFromLookupObject, presentation.isReal()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun callableWeight(descriptor: DeclarationDescriptor): CallableWeight? {
|
private fun callableWeight(descriptor: DeclarationDescriptor): CallableWeight? {
|
||||||
if (descriptor !is CallableDescriptor) return null
|
if (descriptor !is CallableDescriptor) return null
|
||||||
|
|
||||||
@@ -471,82 +251,11 @@ public class LookupElementFactory(
|
|||||||
return typeParameter.containingDeclaration == original
|
return typeParameter.containingDeclaration == original
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun getDefaultInsertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
|
public fun createLookupElementForJavaClass(psiClass: PsiClass, qualifyNestedClasses: Boolean = false, includeClassTypeArguments: Boolean = true): LookupElement {
|
||||||
return when (descriptor) {
|
return basicFactory.createLookupElementForJavaClass(psiClass, qualifyNestedClasses, includeClassTypeArguments)
|
||||||
is FunctionDescriptor -> {
|
|
||||||
val needTypeArguments = needTypeArguments(descriptor)
|
|
||||||
val parameters = descriptor.valueParameters
|
|
||||||
when (parameters.size()) {
|
|
||||||
0 -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = false)
|
|
||||||
|
|
||||||
1 -> {
|
|
||||||
val parameterType = parameters.single().getType()
|
|
||||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
|
||||||
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
|
||||||
if (parameterCount <= 1) {
|
|
||||||
// otherwise additional item with lambda template is to be added
|
|
||||||
return KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = GenerateLambdaInfo(parameterType, false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is PropertyDescriptor -> KotlinPropertyInsertHandler
|
|
||||||
|
|
||||||
is ClassifierDescriptor -> KotlinClassifierInsertHandler
|
|
||||||
|
|
||||||
else -> BaseDeclarationInsertHandler()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun needTypeArguments(function: FunctionDescriptor): Boolean {
|
public fun createLookupElementForPackage(name: FqName): LookupElement {
|
||||||
if (function.typeParameters.isEmpty()) return false
|
return basicFactory.createLookupElementForPackage(name)
|
||||||
|
|
||||||
val originalFunction = function.original
|
|
||||||
val typeParameters = originalFunction.typeParameters
|
|
||||||
|
|
||||||
val potentiallyInferred = HashSet<TypeParameterDescriptor>()
|
|
||||||
|
|
||||||
fun addPotentiallyInferred(type: JetType) {
|
|
||||||
val descriptor = type.constructor.declarationDescriptor as? TypeParameterDescriptor
|
|
||||||
if (descriptor != null && descriptor in typeParameters) {
|
|
||||||
potentiallyInferred.add(descriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(type) && KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(type).size() <= 1) {
|
|
||||||
// do not rely on inference from input of function type with one or no arguments - use only return type of functional type
|
|
||||||
addPotentiallyInferred(KotlinBuiltIns.getReturnTypeFromFunctionType(type))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (argument in type.arguments) {
|
|
||||||
if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion
|
|
||||||
addPotentiallyInferred(argument.type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
originalFunction.extensionReceiverParameter?.type?.let { addPotentiallyInferred(it) }
|
|
||||||
originalFunction.valueParameters.forEach { addPotentiallyInferred(it.type) }
|
|
||||||
|
|
||||||
fun allTypeParametersPotentiallyInferred() = originalFunction.typeParameters.all { it in potentiallyInferred }
|
|
||||||
|
|
||||||
if (allTypeParametersPotentiallyInferred()) return false
|
|
||||||
|
|
||||||
val returnType = originalFunction.returnType
|
|
||||||
// check that there is an expected type and return value from the function can potentially match it
|
|
||||||
if (returnType != null) {
|
|
||||||
addPotentiallyInferred(returnType)
|
|
||||||
|
|
||||||
if (allTypeParametersPotentiallyInferred() && expectedInfos.any { it.fuzzyType?.checkIsSuperTypeOf(originalFunction.fuzzyReturnType()!!) != null }) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -53,9 +53,9 @@ object PackageDirectiveCompletion {
|
|||||||
val bindingContext = resolutionFacade.analyze(expression)
|
val bindingContext = resolutionFacade.analyze(expression)
|
||||||
|
|
||||||
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter())
|
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter())
|
||||||
val lookupElementFactory = LookupElementFactory(resolutionFacade, emptyList(), LookupElementFactory.Context.NORMAL, null, { emptyList() })
|
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(expectedInfosCalculator = { emptyList() }))
|
||||||
for (variant in variants) {
|
for (variant in variants) {
|
||||||
val lookupElement = lookupElementFactory.createLookupElement(variant, useReceiverTypes = false)
|
val lookupElement = lookupElementFactory.createLookupElement(variant)
|
||||||
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
|
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
|
||||||
result.addElement(lookupElement)
|
result.addElement(lookupElement)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -185,7 +185,7 @@ class TypeInstantiationItems(
|
|||||||
|
|
||||||
val baseInsertHandler = when (visibleConstructors.size()) {
|
val baseInsertHandler = when (visibleConstructors.size()) {
|
||||||
0 -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = false)
|
0 -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = false)
|
||||||
1 -> lookupElementFactory.getDefaultInsertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler
|
1 -> lookupElementFactory.insertHandlerProvider.insertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler
|
||||||
else -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = true)
|
else -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user