Smart completion for bound callable references
This commit is contained in:
+1
-1
@@ -144,7 +144,7 @@ class BasicCompletionSession(
|
||||
var sorter = super.createSorter()
|
||||
|
||||
if (smartCompletion != null) {
|
||||
val smartCompletionInBasicWeigher = SmartCompletionInBasicWeigher(smartCompletion, callTypeAndReceiver.callType, resolutionFacade)
|
||||
val smartCompletionInBasicWeigher = SmartCompletionInBasicWeigher(smartCompletion, callTypeAndReceiver, resolutionFacade, bindingContext)
|
||||
sorter = sorter.weighBefore(KindWeigher.toString(),
|
||||
smartCompletionInBasicWeigher,
|
||||
SmartCompletionPriorityWeigher,
|
||||
|
||||
@@ -31,7 +31,9 @@ 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.util.CallType
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.toFuzzyType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
@@ -211,8 +213,9 @@ object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMatching",
|
||||
|
||||
class SmartCompletionInBasicWeigher(
|
||||
private val smartCompletion: SmartCompletion,
|
||||
private val callType: CallType<*>,
|
||||
private val resolutionFacade: ResolutionFacade
|
||||
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val bindingContext: BindingContext
|
||||
) : LookupElementWeigher("kotlin.smartInBasic", true, false) {
|
||||
|
||||
companion object {
|
||||
@@ -259,7 +262,7 @@ class SmartCompletionInBasicWeigher(
|
||||
val (fuzzyTypes, name) = when (o) {
|
||||
is DeclarationLookupObject -> {
|
||||
val descriptor = o.descriptor ?: return NO_MATCH_WEIGHT
|
||||
descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callType, resolutionFacade) to descriptor.name
|
||||
descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callTypeAndReceiver, resolutionFacade, bindingContext) to descriptor.name
|
||||
}
|
||||
|
||||
is ThisItemLookupObject -> smartCastCalculator.types(o.receiverParameter).map { it.toFuzzyType(emptyList()) } to null
|
||||
|
||||
+2
-2
@@ -162,7 +162,7 @@ class SmartCompletion(
|
||||
if (descriptor in descriptorsToSkip) return emptyList()
|
||||
|
||||
val result = SmartList<LookupElement>()
|
||||
val types = descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callTypeAndReceiver.callType, resolutionFacade)
|
||||
val types = descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator, callTypeAndReceiver, resolutionFacade, bindingContext)
|
||||
val infoMatcher = { expectedInfo: ExpectedInfo -> types.matchExpectedInfo(expectedInfo) }
|
||||
|
||||
result.addLookupElements(descriptor, expectedInfos, infoMatcher, noNameSimilarityForReturnItself = callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { descriptor ->
|
||||
@@ -329,7 +329,7 @@ class SmartCompletion(
|
||||
if (callableTypeExpectedInfo.isEmpty()) return
|
||||
|
||||
fun toLookupElement(descriptor: CallableDescriptor): LookupElement? {
|
||||
val callableReferenceType = descriptor.callableReferenceType(resolutionFacade) ?: return null
|
||||
val callableReferenceType = descriptor.callableReferenceType(resolutionFacade, null) ?: return null
|
||||
|
||||
val matchedExpectedInfos = callableTypeExpectedInfo.filter { it.matchingSubstitutor(callableReferenceType) != null }
|
||||
if (matchedExpectedInfos.isEmpty()) return null
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.completion.suppressAutoInsertion
|
||||
import org.jetbrains.kotlin.idea.core.*
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.PossiblyBareType
|
||||
import org.jetbrains.kotlin.resolve.callableReferences.createKCallableTypeForReference
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
@@ -248,14 +249,12 @@ private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factor
|
||||
}
|
||||
}
|
||||
|
||||
fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade): FuzzyType? {
|
||||
fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade, lhs: DoubleColonLHS?): FuzzyType? {
|
||||
if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references
|
||||
|
||||
return createKCallableTypeForReference(
|
||||
this,
|
||||
(dispatchReceiverParameter?.type ?: extensionReceiverParameter?.type)?.let {
|
||||
DoubleColonLHS.Type(it, PossiblyBareType.type(it))
|
||||
},
|
||||
lhs,
|
||||
resolutionFacade.getFrontendService(ReflectionTypes::class.java),
|
||||
resolutionFacade.moduleDescriptor
|
||||
)?.toFuzzyType(emptyList())
|
||||
@@ -290,11 +289,13 @@ fun LookupElement.assignSmartCompletionPriority(priority: SmartCompletionItemPri
|
||||
|
||||
fun DeclarationDescriptor.fuzzyTypesForSmartCompletion(
|
||||
smartCastCalculator: SmartCastCalculator,
|
||||
callType: CallType<*>,
|
||||
resolutionFacade: ResolutionFacade
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
bindingContext: BindingContext
|
||||
): Collection<FuzzyType> {
|
||||
if (callType == CallType.CALLABLE_REFERENCE) {
|
||||
return (this as? CallableDescriptor)?.callableReferenceType(resolutionFacade).singletonOrEmptyList()
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.CALLABLE_REFERENCE) {
|
||||
val lhs = callTypeAndReceiver.receiver?.let { bindingContext[BindingContext.DOUBLE_COLON_LHS, it] }
|
||||
return (this as? CallableDescriptor)?.callableReferenceType(resolutionFacade, lhs).singletonOrEmptyList()
|
||||
}
|
||||
|
||||
if (this is CallableDescriptor) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
class C {
|
||||
fun xf0(s: String){}
|
||||
fun xf1(){}
|
||||
fun xf1(s: String){}
|
||||
fun xf2(i: Int){}
|
||||
}
|
||||
|
||||
fun C.xfe0(s: String){}
|
||||
fun C.xfe1(){}
|
||||
fun C.xfe1(s: String){}
|
||||
fun C.xfe2(i: Int){}
|
||||
|
||||
fun Any.anyF(s: String){}
|
||||
fun String.stringF(s: String){}
|
||||
|
||||
fun foo(p: (String) -> Unit){}
|
||||
|
||||
fun bar(c: C) {
|
||||
foo(c::<caret>)
|
||||
}
|
||||
|
||||
// EXIST: { lookupString:"xf0", itemText:"xf0", tailText: "(s: String)", typeText: "Unit" }
|
||||
// EXIST: { lookupString:"xf1", itemText:"xf1", tailText: "(s: String)", typeText: "Unit" }
|
||||
// EXIST: { lookupString:"xfe0", itemText:"xfe0", tailText: "(s: String) for C in <root>", typeText: "Unit" }
|
||||
// EXIST: { lookupString:"xfe1", itemText:"xfe1", tailText: "(s: String) for C in <root>", typeText: "Unit" }
|
||||
// EXIST: { lookupString:"anyF", itemText:"anyF", tailText: "(s: String) for Any in <root>", typeText: "Unit" }
|
||||
// NOTHING_ELSE
|
||||
@@ -12,4 +12,5 @@ val Any.xTopLevelValOnAny: Int get() = 1
|
||||
val Int.xTopLevelValOnInt: Int get() = 1
|
||||
|
||||
// EXIST: { lookupString:"xTopLevelIntVal", itemText:"xTopLevelIntVal", tailText: " for String in <root>", typeText: "Int" }
|
||||
// EXIST: { lookupString:"xTopLevelValOnAny", itemText:"xTopLevelValOnAny", tailText: " for Any in <root>", typeText: "Int" }
|
||||
// NOTHING_ELSE
|
||||
|
||||
+6
@@ -721,6 +721,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ExpressionQualifier.kt")
|
||||
public void testExpressionQualifier() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/ExpressionQualifier.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NoQualifier1.kt")
|
||||
public void testNoQualifier1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/NoQualifier1.kt");
|
||||
|
||||
Reference in New Issue
Block a user