KT-7195 Smart completion after "return ": the function itself should get smaller priority + declarations in the same file to have higher priority than default-imported
#KT-7195 Fixed
This commit is contained in:
@@ -124,8 +124,8 @@ private class JetDeclarationRemotenessWeigher(private val file: JetFile) : Looku
|
||||
private val importCache = ImportCache()
|
||||
|
||||
private enum class Weight {
|
||||
kotlinDefaultImport
|
||||
thisFile
|
||||
kotlinDefaultImport
|
||||
preciseImport
|
||||
allUnderImport
|
||||
`default`
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.lang.ASTNode
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.di.InjectorForMacros
|
||||
@@ -40,10 +39,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -81,6 +77,14 @@ class ArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?, val functi
|
||||
= function.hashCode()
|
||||
}
|
||||
|
||||
class ReturnValueExpectedInfo(type: JetType, val callable: CallableDescriptor) : ExpectedInfo(type, callable.getName().asString(), null) {
|
||||
override fun equals(other: Any?)
|
||||
= other is ReturnValueExpectedInfo && super.equals(other) && callable == other.callable
|
||||
|
||||
override fun hashCode()
|
||||
= callable.hashCode()
|
||||
}
|
||||
|
||||
|
||||
class ExpectedInfos(
|
||||
val bindingContext: BindingContext,
|
||||
@@ -351,14 +355,14 @@ class ExpectedInfos(
|
||||
return functionReturnValueExpectedInfo(descriptor).toList()
|
||||
}
|
||||
|
||||
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor): ExpectedInfo? {
|
||||
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor): ReturnValueExpectedInfo? {
|
||||
return when (descriptor) {
|
||||
is SimpleFunctionDescriptor -> ExpectedInfo(descriptor.getReturnType() ?: return null, descriptor.getName().asString(), null)
|
||||
is SimpleFunctionDescriptor -> ReturnValueExpectedInfo(descriptor.getReturnType() ?: return null, descriptor)
|
||||
|
||||
is PropertyGetterDescriptor -> {
|
||||
if (descriptor !is PropertyGetterDescriptor) return null
|
||||
val property = descriptor.getCorrespondingProperty()
|
||||
ExpectedInfo(property.getType(), property.getName().asString(), null)
|
||||
ReturnValueExpectedInfo(property.getType(), property)
|
||||
}
|
||||
|
||||
else -> null
|
||||
|
||||
+6
-6
@@ -52,13 +52,13 @@ object KeywordValues {
|
||||
val booleanInfoClassifier = { info: ExpectedInfo ->
|
||||
if (info.type == KotlinBuiltIns.getInstance().getBooleanType()) ExpectedInfoClassification.matches(TypeSubstitutor.EMPTY) else ExpectedInfoClassification.notMatches
|
||||
}
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier, { LookupElementBuilder.create("true").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.TRUE) })
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier, { LookupElementBuilder.create("false").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.FALSE) })
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier) { LookupElementBuilder.create("true").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.TRUE) }
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier) { LookupElementBuilder.create("false").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.FALSE) }
|
||||
}
|
||||
|
||||
collection.addLookupElements(null,
|
||||
expectedInfos,
|
||||
{ info -> if (info.type.isMarkedNullable()) ExpectedInfoClassification.matches(TypeSubstitutor.EMPTY) else ExpectedInfoClassification.notMatches },
|
||||
{ LookupElementBuilder.create("null").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.NULL) })
|
||||
val classifier = { info: ExpectedInfo -> if (info.type.isMarkedNullable()) ExpectedInfoClassification.matches(TypeSubstitutor.EMPTY) else ExpectedInfoClassification.notMatches }
|
||||
collection.addLookupElements(null, expectedInfos, classifier) {
|
||||
LookupElementBuilder.create("null").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.NULL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,6 +62,7 @@ class SmartCompletion(
|
||||
val lookupElementFactory: LookupElementFactory
|
||||
) {
|
||||
private val project = expression.getProject()
|
||||
private val receiver = if (expression is JetSimpleNameExpression) expression.getReceiverExpression() else null
|
||||
|
||||
public class Result(
|
||||
val declarationFilter: ((DeclarationDescriptor) -> Collection<LookupElement>)?,
|
||||
@@ -110,7 +111,6 @@ class SmartCompletion(
|
||||
val asTypePositionResult = buildForAsTypePosition()
|
||||
if (asTypePositionResult != null) return asTypePositionResult
|
||||
|
||||
val receiver = if (expression is JetSimpleNameExpression) expression.getReceiverExpression() else null
|
||||
val expressionWithType = if (receiver != null) {
|
||||
expression.getParent() as? JetExpression ?: return null
|
||||
}
|
||||
@@ -148,7 +148,7 @@ class SmartCompletion(
|
||||
val types = descriptor.fuzzyTypes(smartCastTypes)
|
||||
val infoClassifier = { expectedInfo: ExpectedInfo -> types.classifyExpectedInfo(expectedInfo) }
|
||||
|
||||
result.addLookupElements(descriptor, expectedInfos, infoClassifier) { descriptor ->
|
||||
result.addLookupElements(descriptor, expectedInfos, infoClassifier, noNameSimilarityForReturnItself = receiver == null) { descriptor ->
|
||||
lookupElementFactory.createLookupElement(descriptor, resolutionFacade, bindingContext, true)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetValueArgument
|
||||
@@ -35,7 +36,6 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import java.util.HashSet
|
||||
@@ -115,9 +115,12 @@ fun LookupElement.withOptions(options: ItemOptions): LookupElement {
|
||||
return lookupElement
|
||||
}
|
||||
|
||||
fun LookupElement.addTailAndNameSimilarity(matchedExpectedInfos: Collection<ExpectedInfo>): LookupElement {
|
||||
fun LookupElement.addTailAndNameSimilarity(
|
||||
matchedExpectedInfos: Collection<ExpectedInfo>,
|
||||
nameSimilarityExpectedInfos: Collection<ExpectedInfo> = matchedExpectedInfos
|
||||
): LookupElement {
|
||||
val lookupElement = addTail(mergeTails(matchedExpectedInfos.map { it.tail }))
|
||||
val similarity = calcNameSimilarity(lookupElement.getLookupString(), matchedExpectedInfos)
|
||||
val similarity = calcNameSimilarity(lookupElement.getLookupString(), nameSimilarityExpectedInfos)
|
||||
if (similarity != 0) {
|
||||
lookupElement.putUserData(NAME_SIMILARITY_KEY, similarity)
|
||||
}
|
||||
@@ -155,6 +158,7 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
descriptor: TDescriptor,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
infoClassifier: (ExpectedInfo) -> ExpectedInfoClassification,
|
||||
noNameSimilarityForReturnItself: Boolean = false,
|
||||
lookupElementFactory: (TDescriptor) -> LookupElement?
|
||||
) {
|
||||
class ItemData(val descriptor: TDescriptor, val itemOptions: ItemOptions) {
|
||||
@@ -181,7 +185,12 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
for ((itemData, infos) in matchedInfos) {
|
||||
val lookupElement = itemData.createLookupElement()
|
||||
if (lookupElement != null) {
|
||||
add(lookupElement.addTailAndNameSimilarity(infos))
|
||||
val nameSimilarityInfos = if (noNameSimilarityForReturnItself && descriptor is CallableDescriptor) {
|
||||
infos.filter { (it as? ReturnValueExpectedInfo)?.callable != descriptor } // do not calculate name similarity with function itself in its return
|
||||
}
|
||||
else
|
||||
infos
|
||||
add(lookupElement.addTailAndNameSimilarity(infos, nameSimilarityInfos))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,5 +11,5 @@ fun bar(p: (String) -> Boolean) {
|
||||
// ORDER: p
|
||||
// ORDER: {...}
|
||||
// ORDER: { String -> ... }
|
||||
// ORDER: ::error
|
||||
// ORDER: ::x
|
||||
// ORDER: ::error
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
val fooBar = ""
|
||||
val vFooBar = ""
|
||||
|
||||
fun foo(s: String): String = <caret>
|
||||
|
||||
// ORDER: foo, fooBar, s
|
||||
// ORDER: vFooBar, s, foo
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
val fooBar = ""
|
||||
val vFooBar = ""
|
||||
|
||||
fun foo(s: String): String {
|
||||
return <caret>
|
||||
}
|
||||
|
||||
// ORDER: foo, fooBar, s
|
||||
// ORDER: vFooBar, s, foo
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fun<T> calcSomething(s: String, t: T): String {
|
||||
val something = ""
|
||||
return <caret>
|
||||
}
|
||||
|
||||
// ORDER: something
|
||||
// ORDER: s
|
||||
// ORDER: calcSomething
|
||||
@@ -0,0 +1,14 @@
|
||||
class C {
|
||||
val something: String = ""
|
||||
val s: String = ""
|
||||
|
||||
fun calcSomething(c: C?): String {
|
||||
if (c != null) {
|
||||
return c.<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ORDER: calcSomething
|
||||
// ORDER: something
|
||||
// ORDER: s
|
||||
+12
@@ -197,6 +197,18 @@ public class SmartCompletionWeigherTestGenerated extends AbstractSmartCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ReturnValue1.kt")
|
||||
public void testReturnValue1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/smart/ReturnValue1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ReturnValue2.kt")
|
||||
public void testReturnValue2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/smart/ReturnValue2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SmartPriority.kt")
|
||||
public void testSmartPriority() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/smart/SmartPriority.kt");
|
||||
|
||||
Reference in New Issue
Block a user