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 val importCache = ImportCache()
|
||||||
|
|
||||||
private enum class Weight {
|
private enum class Weight {
|
||||||
kotlinDefaultImport
|
|
||||||
thisFile
|
thisFile
|
||||||
|
kotlinDefaultImport
|
||||||
preciseImport
|
preciseImport
|
||||||
allUnderImport
|
allUnderImport
|
||||||
`default`
|
`default`
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion
|
package org.jetbrains.kotlin.idea.completion
|
||||||
|
|
||||||
import com.intellij.lang.ASTNode
|
|
||||||
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.di.InjectorForMacros
|
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.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
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.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.resolve.validation.SymbolUsageValidator
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
@@ -81,6 +77,14 @@ class ArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?, val functi
|
|||||||
= function.hashCode()
|
= 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(
|
class ExpectedInfos(
|
||||||
val bindingContext: BindingContext,
|
val bindingContext: BindingContext,
|
||||||
@@ -351,14 +355,14 @@ class ExpectedInfos(
|
|||||||
return functionReturnValueExpectedInfo(descriptor).toList()
|
return functionReturnValueExpectedInfo(descriptor).toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor): ExpectedInfo? {
|
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor): ReturnValueExpectedInfo? {
|
||||||
return when (descriptor) {
|
return when (descriptor) {
|
||||||
is SimpleFunctionDescriptor -> ExpectedInfo(descriptor.getReturnType() ?: return null, descriptor.getName().asString(), null)
|
is SimpleFunctionDescriptor -> ReturnValueExpectedInfo(descriptor.getReturnType() ?: return null, descriptor)
|
||||||
|
|
||||||
is PropertyGetterDescriptor -> {
|
is PropertyGetterDescriptor -> {
|
||||||
if (descriptor !is PropertyGetterDescriptor) return null
|
if (descriptor !is PropertyGetterDescriptor) return null
|
||||||
val property = descriptor.getCorrespondingProperty()
|
val property = descriptor.getCorrespondingProperty()
|
||||||
ExpectedInfo(property.getType(), property.getName().asString(), null)
|
ReturnValueExpectedInfo(property.getType(), property)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
+6
-6
@@ -52,13 +52,13 @@ object KeywordValues {
|
|||||||
val booleanInfoClassifier = { info: ExpectedInfo ->
|
val booleanInfoClassifier = { info: ExpectedInfo ->
|
||||||
if (info.type == KotlinBuiltIns.getInstance().getBooleanType()) ExpectedInfoClassification.matches(TypeSubstitutor.EMPTY) else ExpectedInfoClassification.notMatches
|
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("true").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.TRUE) }
|
||||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier, { LookupElementBuilder.create("false").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.FALSE) })
|
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier) { LookupElementBuilder.create("false").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.FALSE) }
|
||||||
}
|
}
|
||||||
|
|
||||||
collection.addLookupElements(null,
|
val classifier = { info: ExpectedInfo -> if (info.type.isMarkedNullable()) ExpectedInfoClassification.matches(TypeSubstitutor.EMPTY) else ExpectedInfoClassification.notMatches }
|
||||||
expectedInfos,
|
collection.addLookupElements(null, expectedInfos, classifier) {
|
||||||
{ info -> if (info.type.isMarkedNullable()) ExpectedInfoClassification.matches(TypeSubstitutor.EMPTY) else ExpectedInfoClassification.notMatches },
|
LookupElementBuilder.create("null").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.NULL)
|
||||||
{ LookupElementBuilder.create("null").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.NULL) })
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -62,6 +62,7 @@ class SmartCompletion(
|
|||||||
val lookupElementFactory: LookupElementFactory
|
val lookupElementFactory: LookupElementFactory
|
||||||
) {
|
) {
|
||||||
private val project = expression.getProject()
|
private val project = expression.getProject()
|
||||||
|
private val receiver = if (expression is JetSimpleNameExpression) expression.getReceiverExpression() else null
|
||||||
|
|
||||||
public class Result(
|
public class Result(
|
||||||
val declarationFilter: ((DeclarationDescriptor) -> Collection<LookupElement>)?,
|
val declarationFilter: ((DeclarationDescriptor) -> Collection<LookupElement>)?,
|
||||||
@@ -110,7 +111,6 @@ class SmartCompletion(
|
|||||||
val asTypePositionResult = buildForAsTypePosition()
|
val asTypePositionResult = buildForAsTypePosition()
|
||||||
if (asTypePositionResult != null) return asTypePositionResult
|
if (asTypePositionResult != null) return asTypePositionResult
|
||||||
|
|
||||||
val receiver = if (expression is JetSimpleNameExpression) expression.getReceiverExpression() else null
|
|
||||||
val expressionWithType = if (receiver != null) {
|
val expressionWithType = if (receiver != null) {
|
||||||
expression.getParent() as? JetExpression ?: return null
|
expression.getParent() as? JetExpression ?: return null
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ class SmartCompletion(
|
|||||||
val types = descriptor.fuzzyTypes(smartCastTypes)
|
val types = descriptor.fuzzyTypes(smartCastTypes)
|
||||||
val infoClassifier = { expectedInfo: ExpectedInfo -> types.classifyExpectedInfo(expectedInfo) }
|
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)
|
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.caches.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.completion.*
|
import org.jetbrains.kotlin.idea.completion.*
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
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.idea.util.*
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
import org.jetbrains.kotlin.psi.JetValueArgument
|
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.resolve.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
@@ -115,9 +115,12 @@ fun LookupElement.withOptions(options: ItemOptions): LookupElement {
|
|||||||
return 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 lookupElement = addTail(mergeTails(matchedExpectedInfos.map { it.tail }))
|
||||||
val similarity = calcNameSimilarity(lookupElement.getLookupString(), matchedExpectedInfos)
|
val similarity = calcNameSimilarity(lookupElement.getLookupString(), nameSimilarityExpectedInfos)
|
||||||
if (similarity != 0) {
|
if (similarity != 0) {
|
||||||
lookupElement.putUserData(NAME_SIMILARITY_KEY, similarity)
|
lookupElement.putUserData(NAME_SIMILARITY_KEY, similarity)
|
||||||
}
|
}
|
||||||
@@ -155,6 +158,7 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
|||||||
descriptor: TDescriptor,
|
descriptor: TDescriptor,
|
||||||
expectedInfos: Collection<ExpectedInfo>,
|
expectedInfos: Collection<ExpectedInfo>,
|
||||||
infoClassifier: (ExpectedInfo) -> ExpectedInfoClassification,
|
infoClassifier: (ExpectedInfo) -> ExpectedInfoClassification,
|
||||||
|
noNameSimilarityForReturnItself: Boolean = false,
|
||||||
lookupElementFactory: (TDescriptor) -> LookupElement?
|
lookupElementFactory: (TDescriptor) -> LookupElement?
|
||||||
) {
|
) {
|
||||||
class ItemData(val descriptor: TDescriptor, val itemOptions: ItemOptions) {
|
class ItemData(val descriptor: TDescriptor, val itemOptions: ItemOptions) {
|
||||||
@@ -181,7 +185,12 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
|||||||
for ((itemData, infos) in matchedInfos) {
|
for ((itemData, infos) in matchedInfos) {
|
||||||
val lookupElement = itemData.createLookupElement()
|
val lookupElement = itemData.createLookupElement()
|
||||||
if (lookupElement != null) {
|
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: p
|
||||||
// ORDER: {...}
|
// ORDER: {...}
|
||||||
// ORDER: { String -> ... }
|
// ORDER: { String -> ... }
|
||||||
// ORDER: ::error
|
|
||||||
// ORDER: ::x
|
// ORDER: ::x
|
||||||
|
// ORDER: ::error
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
val fooBar = ""
|
val vFooBar = ""
|
||||||
|
|
||||||
fun foo(s: String): String = <caret>
|
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 {
|
fun foo(s: String): String {
|
||||||
return <caret>
|
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);
|
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")
|
@TestMetadata("SmartPriority.kt")
|
||||||
public void testSmartPriority() throws Exception {
|
public void testSmartPriority() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/smart/SmartPriority.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/smart/SmartPriority.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user