diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt index 7a995527dc8..4db9f73535f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt @@ -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` diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt index a2fdc5deda7..bb4edee751a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt @@ -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 diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/KeywordValues.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/KeywordValues.kt index a248bb7bf78..16320ff143b 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/KeywordValues.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/KeywordValues.kt @@ -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) + } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt index 2352a70ddad..f27c38f1d1a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt @@ -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)?, @@ -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) } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt index 099c9db2ab4..2ef61a132d9 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt @@ -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): LookupElement { +fun LookupElement.addTailAndNameSimilarity( + matchedExpectedInfos: Collection, + nameSimilarityExpectedInfos: Collection = 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 MutableCollection.addLoo descriptor: TDescriptor, expectedInfos: Collection, infoClassifier: (ExpectedInfo) -> ExpectedInfoClassification, + noNameSimilarityForReturnItself: Boolean = false, lookupElementFactory: (TDescriptor) -> LookupElement? ) { class ItemData(val descriptor: TDescriptor, val itemOptions: ItemOptions) { @@ -181,7 +185,12 @@ fun MutableCollection.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)) } } } diff --git a/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt b/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt index f165b099643..c9ed6a64cc3 100644 --- a/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt +++ b/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt @@ -11,5 +11,5 @@ fun bar(p: (String) -> Boolean) { // ORDER: p // ORDER: {...} // ORDER: { String -> ... } -// ORDER: ::error // ORDER: ::x +// ORDER: ::error diff --git a/idea/idea-completion/testData/weighers/smart/NameSimilarityForExpressionBody.kt b/idea/idea-completion/testData/weighers/smart/NameSimilarityForExpressionBody.kt index 2ef60e4697b..19d1db5e735 100644 --- a/idea/idea-completion/testData/weighers/smart/NameSimilarityForExpressionBody.kt +++ b/idea/idea-completion/testData/weighers/smart/NameSimilarityForExpressionBody.kt @@ -1,5 +1,5 @@ -val fooBar = "" +val vFooBar = "" fun foo(s: String): String = -// ORDER: foo, fooBar, s +// ORDER: vFooBar, s, foo diff --git a/idea/idea-completion/testData/weighers/smart/NameSimilarityForReturn.kt b/idea/idea-completion/testData/weighers/smart/NameSimilarityForReturn.kt index 4714826dde5..7cc0f82d7ca 100644 --- a/idea/idea-completion/testData/weighers/smart/NameSimilarityForReturn.kt +++ b/idea/idea-completion/testData/weighers/smart/NameSimilarityForReturn.kt @@ -1,7 +1,7 @@ -val fooBar = "" +val vFooBar = "" fun foo(s: String): String { return } -// ORDER: foo, fooBar, s +// ORDER: vFooBar, s, foo diff --git a/idea/idea-completion/testData/weighers/smart/ReturnValue1.kt b/idea/idea-completion/testData/weighers/smart/ReturnValue1.kt new file mode 100644 index 00000000000..8472cfa220c --- /dev/null +++ b/idea/idea-completion/testData/weighers/smart/ReturnValue1.kt @@ -0,0 +1,8 @@ +fun calcSomething(s: String, t: T): String { + val something = "" + return +} + +// ORDER: something +// ORDER: s +// ORDER: calcSomething diff --git a/idea/idea-completion/testData/weighers/smart/ReturnValue2.kt b/idea/idea-completion/testData/weighers/smart/ReturnValue2.kt new file mode 100644 index 00000000000..e08073b57da --- /dev/null +++ b/idea/idea-completion/testData/weighers/smart/ReturnValue2.kt @@ -0,0 +1,14 @@ +class C { + val something: String = "" + val s: String = "" + + fun calcSomething(c: C?): String { + if (c != null) { + return c. + } + } +} + +// ORDER: calcSomething +// ORDER: something +// ORDER: s diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/SmartCompletionWeigherTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/SmartCompletionWeigherTestGenerated.java index e13a64c5e75..0e6f09cddda 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/SmartCompletionWeigherTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/SmartCompletionWeigherTestGenerated.java @@ -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");