KT-12798 DSL-friendly completion
#KT-12798 Fixed
This commit is contained in:
@@ -124,7 +124,7 @@ fun LookupElementPresentation.prependTailText(text: String, grayed: Boolean) {
|
||||
tails.forEach { appendTailText(it.text, it.isGrayed) }
|
||||
}
|
||||
|
||||
enum class CallableWeight {
|
||||
enum class CallableWeightEnum {
|
||||
local, // local non-extension
|
||||
thisClassMember,
|
||||
baseClassMember,
|
||||
@@ -135,6 +135,14 @@ enum class CallableWeight {
|
||||
receiverCastRequired
|
||||
}
|
||||
|
||||
class CallableWeight(val enum: CallableWeightEnum, val receiverIndex: Int?) {
|
||||
companion object {
|
||||
val local = CallableWeight(CallableWeightEnum.local, null)
|
||||
val globalOrStatic = CallableWeight(CallableWeightEnum.globalOrStatic, null)
|
||||
val receiverCastRequired = CallableWeight(CallableWeightEnum.receiverCastRequired, null)
|
||||
}
|
||||
}
|
||||
|
||||
val CALLABLE_WEIGHT_KEY = Key<CallableWeight>("CALLABLE_WEIGHT_KEY")
|
||||
|
||||
fun InsertionContext.isAfterDot(): Boolean {
|
||||
|
||||
+40
-23
@@ -104,7 +104,7 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
// special "[]" item for get-operator
|
||||
if (callType == CallType.DOT && descriptor is FunctionDescriptor && descriptor.isOperator() && descriptor.name == OperatorNameConventions.GET) {
|
||||
if (callType == CallType.DOT && descriptor is FunctionDescriptor && descriptor.isOperator && descriptor.name == OperatorNameConventions.GET) {
|
||||
val baseLookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||
val lookupElement = object : LookupElementDecorator<LookupElement>(baseLookupElement) {
|
||||
override fun getLookupString() = "[]"
|
||||
@@ -261,9 +261,9 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
private fun LookupElement.boldIfImmediate(weight: CallableWeight?): LookupElement {
|
||||
val style = when (weight) {
|
||||
CallableWeight.thisClassMember, CallableWeight.thisTypeExtension -> Style.BOLD
|
||||
CallableWeight.receiverCastRequired -> Style.GRAYED
|
||||
val style = when (weight?.enum) {
|
||||
CallableWeightEnum.thisClassMember, CallableWeightEnum.thisTypeExtension -> Style.BOLD
|
||||
CallableWeightEnum.receiverCastRequired -> Style.GRAYED
|
||||
else -> Style.NORMAL
|
||||
}
|
||||
return if (style != Style.NORMAL) {
|
||||
@@ -310,12 +310,15 @@ class LookupElementFactory(
|
||||
|
||||
if (descriptor.overriddenDescriptors.isNotEmpty()) {
|
||||
// Optimization: when one of direct overridden fits, then nothing can fit better
|
||||
descriptor.overriddenDescriptors.mapNotNull {
|
||||
it.callableWeightBasedOnReceiver(receiverTypes, onReceiverTypeMismatch = null)
|
||||
}.min()?.let { return it }
|
||||
descriptor.overriddenDescriptors
|
||||
.mapNotNull { it.callableWeightBasedOnReceiver(receiverTypes, onReceiverTypeMismatch = null) }
|
||||
.minBy { it.enum }
|
||||
?.let { return it }
|
||||
|
||||
val overridden = descriptor.overriddenTreeUniqueAsSequence(useOriginal = false)
|
||||
return overridden.map { callableWeightBasic(it, receiverTypes)!! }.min()!!
|
||||
return overridden
|
||||
.map { callableWeightBasic(it, receiverTypes)!! }
|
||||
.minBy { it.enum }!!
|
||||
}
|
||||
|
||||
return callableWeightBasic(descriptor, receiverTypes)
|
||||
@@ -334,24 +337,38 @@ class LookupElementFactory(
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
onReceiverTypeMismatch: CallableWeight?
|
||||
): CallableWeight? {
|
||||
val receiverParameter = extensionReceiverParameter ?: dispatchReceiverParameter
|
||||
if (receiverParameter != null) {
|
||||
return if (receiverTypes.any { TypeUtils.equalTypes(it, receiverParameter.type) }) {
|
||||
when {
|
||||
isExtensionForTypeParameter() -> CallableWeight.typeParameterExtension
|
||||
isExtension -> CallableWeight.thisTypeExtension
|
||||
else -> CallableWeight.thisClassMember
|
||||
}
|
||||
}
|
||||
else if (receiverTypes.any { it.isSubtypeOf(receiverParameter.type) }) {
|
||||
if (isExtension) CallableWeight.baseTypeExtension else CallableWeight.baseClassMember
|
||||
}
|
||||
else {
|
||||
onReceiverTypeMismatch
|
||||
val receiverParameter = extensionReceiverParameter
|
||||
?: dispatchReceiverParameter
|
||||
?: return null
|
||||
|
||||
for ((receiverIndex, receiverType) in receiverTypes.withIndex()) {
|
||||
val weight = callableWeightForReceiverType(receiverType, receiverParameter.type)
|
||||
if (weight != null) {
|
||||
// if descriptor is matching all receivers then use null as receiverIndex - otherwise e.g. all members of Any would have too high priority
|
||||
val receiverIndexToUse = if (receiverIndex == 0 && receiverTypes.drop(1).all { callableWeightForReceiverType(it, receiverParameter.type) != null })
|
||||
null
|
||||
else
|
||||
receiverIndex
|
||||
return CallableWeight(weight, receiverIndexToUse)
|
||||
}
|
||||
}
|
||||
return onReceiverTypeMismatch
|
||||
}
|
||||
|
||||
return null
|
||||
private fun CallableDescriptor.callableWeightForReceiverType(receiverType: KotlinType, receiverParameterType: KotlinType): CallableWeightEnum? {
|
||||
if (TypeUtils.equalTypes(receiverType, receiverParameterType)) {
|
||||
return when {
|
||||
isExtensionForTypeParameter() -> CallableWeightEnum.typeParameterExtension
|
||||
isExtension -> CallableWeightEnum.thisTypeExtension
|
||||
else -> CallableWeightEnum.thisClassMember
|
||||
}
|
||||
}
|
||||
else if (receiverType.isSubtypeOf(receiverParameterType)) {
|
||||
return if (isExtension) CallableWeightEnum.baseTypeExtension else CallableWeightEnum.baseClassMember
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun CallableDescriptor.isExtensionForTypeParameter(): Boolean {
|
||||
|
||||
@@ -138,7 +138,55 @@ object KindWeigher : LookupElementWeigher("kotlin.kind") {
|
||||
}
|
||||
|
||||
object CallableWeigher : LookupElementWeigher("kotlin.callableWeight") {
|
||||
override fun weigh(element: LookupElement) = element.getUserData(CALLABLE_WEIGHT_KEY)
|
||||
private enum class Weight1 {
|
||||
local,
|
||||
memberOrExtension,
|
||||
globalOrStatic,
|
||||
typeParameterExtension,
|
||||
receiverCastRequired
|
||||
}
|
||||
|
||||
private enum class Weight2 {
|
||||
thisClassMember,
|
||||
baseClassMember,
|
||||
thisTypeExtension,
|
||||
baseTypeExtension,
|
||||
other
|
||||
}
|
||||
|
||||
private class CompoundWeight(val weight1: Weight1, val receiverIndex: Int, val weight2: Weight2) : Comparable<CompoundWeight> {
|
||||
override fun compareTo(other: CompoundWeight): Int {
|
||||
if (weight1 != other.weight1) return weight1.compareTo(other.weight1)
|
||||
if (receiverIndex != other.receiverIndex) return receiverIndex.compareTo(other.receiverIndex)
|
||||
return weight2.compareTo(other.weight2)
|
||||
}
|
||||
}
|
||||
|
||||
override fun weigh(element: LookupElement): Comparable<*>? {
|
||||
val weight = element.getUserData(CALLABLE_WEIGHT_KEY) ?: return null
|
||||
val w1 = when (weight.enum) {
|
||||
CallableWeightEnum.local -> Weight1.local
|
||||
|
||||
CallableWeightEnum.thisClassMember,
|
||||
CallableWeightEnum.baseClassMember,
|
||||
CallableWeightEnum.thisTypeExtension,
|
||||
CallableWeightEnum.baseTypeExtension -> Weight1.memberOrExtension
|
||||
|
||||
CallableWeightEnum.globalOrStatic -> Weight1.globalOrStatic
|
||||
|
||||
CallableWeightEnum.typeParameterExtension -> Weight1.typeParameterExtension
|
||||
|
||||
CallableWeightEnum.receiverCastRequired -> Weight1.receiverCastRequired
|
||||
}
|
||||
val w2 = when (weight.enum) {
|
||||
CallableWeightEnum.thisClassMember -> Weight2.thisClassMember
|
||||
CallableWeightEnum.baseClassMember -> Weight2.baseClassMember
|
||||
CallableWeightEnum.thisTypeExtension -> Weight2.thisTypeExtension
|
||||
CallableWeightEnum.baseTypeExtension -> Weight2.baseTypeExtension
|
||||
else -> Weight2.other
|
||||
}
|
||||
return CompoundWeight(w1, weight.receiverIndex ?: Int.MAX_VALUE, w2)
|
||||
}
|
||||
}
|
||||
|
||||
object VariableOrFunctionWeigher : LookupElementWeigher("kotlin.variableOrFunction"){
|
||||
|
||||
+20
-2
@@ -1,3 +1,5 @@
|
||||
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
fun aaGlobalFun(){}
|
||||
val aaGlobalProp = 1
|
||||
|
||||
@@ -10,14 +12,23 @@ class Derived : Base() {
|
||||
fun aaDerivedFun(){}
|
||||
val aaDerivedProp = 1
|
||||
|
||||
fun foo() {
|
||||
fun foo(y: Y) {
|
||||
val aaLocalVal = 1
|
||||
fun aaLocalFun(){}
|
||||
|
||||
aa<caret>
|
||||
with (y) {
|
||||
aa<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface X {
|
||||
fun aaX()
|
||||
}
|
||||
interface Y : X {
|
||||
fun aaY()
|
||||
}
|
||||
|
||||
fun Any.aaAnyExtensionFun(){}
|
||||
fun Derived.aaExtensionFun(){}
|
||||
|
||||
@@ -26,8 +37,15 @@ val Derived.aaExtensionProp: Int get() = 1
|
||||
|
||||
fun <T> T.aaTypeParamExt(){}
|
||||
|
||||
fun X.aaXExt(){}
|
||||
fun Y.aaYExt(){}
|
||||
|
||||
// ORDER: aaLocalVal
|
||||
// ORDER: aaLocalFun
|
||||
// ORDER: aaY
|
||||
// ORDER: aaX
|
||||
// ORDER: aaYExt
|
||||
// ORDER: aaXExt
|
||||
// ORDER: aaDerivedProp
|
||||
// ORDER: aaDerivedFun
|
||||
// ORDER: aaBaseProp
|
||||
|
||||
Reference in New Issue
Block a user