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:
Valentin Kipyatkov
2015-05-08 13:17:34 +03:00
parent 09f478fc0f
commit 892b2b0f83
11 changed files with 72 additions and 25 deletions
@@ -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
@@ -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)
}
}
}
@@ -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
@@ -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");