Graying members from smart cast receiver types that require explicit receiver cast
+ changed immediate member criteria (override member is not counted as immediate anymore) + fixed a bug in graying members
This commit is contained in:
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
@@ -142,8 +143,14 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
if (receiversData != null) {
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfo(expression)
|
||||
|
||||
var receiverTypes = receiversData.receivers.flatMap {
|
||||
SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(it, bindingContext, moduleDescriptor, dataFlowInfo)
|
||||
var receiverTypes = receiversData.receivers.flatMap { receiverValue ->
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
|
||||
if (dataFlowValue.isPredictable) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed
|
||||
SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, moduleDescriptor, dataFlowInfo)
|
||||
}
|
||||
else {
|
||||
listOf(receiverValue.type)
|
||||
}
|
||||
}
|
||||
|
||||
if (receiversData.callType == CallType.SAFE) {
|
||||
|
||||
@@ -134,8 +134,8 @@ enum class CallableWeight {
|
||||
baseClassMember,
|
||||
thisTypeExtension,
|
||||
baseTypeExtension,
|
||||
global, // global non-extension
|
||||
notApplicableReceiverNullable
|
||||
globalOrStatic, // global non-extension
|
||||
receiverCastRequired
|
||||
}
|
||||
|
||||
val CALLABLE_WEIGHT_KEY = Key<CallableWeight>("CALLABLE_WEIGHT_KEY")
|
||||
|
||||
+18
-35
@@ -36,12 +36,12 @@ import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||
import org.jetbrains.kotlin.types.typeUtil.nullability
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
|
||||
public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObject {
|
||||
override val psiElement: PsiElement? get() = null
|
||||
@@ -87,7 +87,7 @@ public class LookupElementFactory(
|
||||
private fun LookupElement.boldIfImmediate(weight: CallableWeight?): LookupElement {
|
||||
val style = when (weight) {
|
||||
CallableWeight.thisClassMember, CallableWeight.thisTypeExtension -> Style.BOLD
|
||||
CallableWeight.notApplicableReceiverNullable -> Style.GRAYED
|
||||
CallableWeight.receiverCastRequired -> Style.GRAYED
|
||||
else -> Style.NORMAL
|
||||
}
|
||||
return if (style != Style.NORMAL) {
|
||||
@@ -327,41 +327,24 @@ public class LookupElementFactory(
|
||||
private fun callableWeight(descriptor: DeclarationDescriptor): CallableWeight? {
|
||||
if (descriptor !is CallableDescriptor) return null
|
||||
|
||||
val isReceiverNullable = receiverTypes.isNotEmpty() && receiverTypes.all { it.nullability() == TypeNullability.NULLABLE }
|
||||
val receiverParameter = descriptor.getExtensionReceiverParameter()
|
||||
|
||||
if (receiverParameter != null) {
|
||||
val receiverParamType = receiverParameter.getType()
|
||||
return if (isReceiverNullable && receiverParamType.nullability() == TypeNullability.NOT_NULL)
|
||||
CallableWeight.notApplicableReceiverNullable
|
||||
else if (receiverTypes.any { TypeUtils.equalTypes(it, receiverParamType) })
|
||||
CallableWeight.thisTypeExtension
|
||||
else
|
||||
CallableWeight.baseTypeExtension
|
||||
val overridden = descriptor.overriddenDescriptors
|
||||
if (overridden.isNotEmpty()) {
|
||||
return overridden.map { callableWeight(it)!! }.min()!!
|
||||
}
|
||||
else {
|
||||
if (isReceiverNullable) {
|
||||
return CallableWeight.notApplicableReceiverNullable
|
||||
}
|
||||
else {
|
||||
if (descriptor !is CallableMemberDescriptor) {
|
||||
return CallableWeight.local
|
||||
}
|
||||
|
||||
val container = descriptor.getContainingDeclaration()
|
||||
return when (container) {
|
||||
is PackageFragmentDescriptor -> CallableWeight.global
|
||||
val receiverParameter = descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter
|
||||
if (receiverParameter != null) {
|
||||
return if (receiverTypes.any { TypeUtils.equalTypes(it, receiverParameter.type) })
|
||||
if (descriptor.isExtension) CallableWeight.thisTypeExtension else CallableWeight.thisClassMember
|
||||
else if (receiverTypes.any { it.isSubtypeOf(receiverParameter.type) })
|
||||
if (descriptor.isExtension) CallableWeight.baseTypeExtension else CallableWeight.baseClassMember
|
||||
else
|
||||
CallableWeight.receiverCastRequired
|
||||
}
|
||||
|
||||
is ClassifierDescriptor -> {
|
||||
if (descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION)
|
||||
CallableWeight.thisClassMember
|
||||
else
|
||||
CallableWeight.baseClassMember
|
||||
}
|
||||
|
||||
else -> CallableWeight.local
|
||||
}
|
||||
}
|
||||
return when (descriptor.containingDeclaration) {
|
||||
is PackageFragmentDescriptor, is ClassifierDescriptor -> CallableWeight.globalOrStatic
|
||||
else -> CallableWeight.local
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,4 +13,4 @@ fun foo(o: Any?) {
|
||||
// EXIST: { lookupString: "forNullableAny", attributes: "" }
|
||||
// EXIST: { lookupString: "forString", attributes: "bold" }
|
||||
// EXIST: { lookupString: "forAny", attributes: "" }
|
||||
// EXIST: { lookupString: "compareTo", attributes: "bold" }
|
||||
// EXIST: { lookupString: "compareTo", attributes: "" }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fun String.forString(){}
|
||||
|
||||
fun globalFun(){}
|
||||
|
||||
fun String?.foo() {
|
||||
<caret>
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "globalFun", attributes: "" }
|
||||
// EXIST: { lookupString: "compareTo", attributes: "grayed" }
|
||||
// EXIST: { lookupString: "forString", attributes: "grayed" }
|
||||
@@ -0,0 +1,15 @@
|
||||
fun String.forString(){}
|
||||
fun Any.forAny(){}
|
||||
|
||||
fun <T> T.forT() {}
|
||||
|
||||
fun f(pair: Pair<out Any, out Any>) {
|
||||
if (pair.first !is String) return
|
||||
pair.first.<caret>
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "length", attributes: "grayed" }
|
||||
// EXIST: { lookupString: "hashCode", attributes: "bold" }
|
||||
// EXIST: { lookupString: "forString", attributes: "grayed" }
|
||||
// EXIST: { lookupString: "forAny", attributes: "bold" }
|
||||
// EXIST: { lookupString: "forT", attributes: "bold" }
|
||||
@@ -11,4 +11,4 @@ fun foo(s: String?) {
|
||||
// EXIST: { lookupString: "forNullableAny", attributes: "" }
|
||||
// EXIST: { lookupString: "forString", attributes: "bold" }
|
||||
// EXIST: { lookupString: "forAny", attributes: "" }
|
||||
// EXIST: { lookupString: "compareTo", attributes: "bold" }
|
||||
// EXIST: { lookupString: "compareTo", attributes: "" }
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ fun foo(d: Derived) {
|
||||
d.<caret>
|
||||
}
|
||||
|
||||
// EXIST: { itemText: "fromTrait", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromTrait", attributes: "" }
|
||||
// EXIST: { itemText: "fromDerived", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromBase", attributes: "" }
|
||||
// EXIST: { itemText: "hashCode", attributes: "" }
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ fun foo(o: Any) {
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: { itemText: "fromTrait", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromTrait", attributes: "" }
|
||||
// EXIST: { itemText: "fromDerived", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromBase", attributes: "" }
|
||||
// EXIST: { itemText: "hashCode", attributes: "" }
|
||||
|
||||
+1
-1
@@ -11,6 +11,6 @@ fun foo(b: B) {
|
||||
b.<caret>
|
||||
}
|
||||
|
||||
// EXIST: { itemText: "foo1", attributes: "bold" }
|
||||
// EXIST: { itemText: "foo1", attributes: "" }
|
||||
// EXIST: { itemText: "foo2", attributes: "" }
|
||||
// EXIST: { itemText: "equals", attributes: "" }
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ class Derived : Base() {
|
||||
}
|
||||
|
||||
// EXIST: { itemText: "foo", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromTrait", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromTrait", attributes: "" }
|
||||
// EXIST: { itemText: "fromDerived", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromBase", attributes: "" }
|
||||
// EXIST: { itemText: "hashCode", attributes: "" }
|
||||
|
||||
+1
-1
@@ -11,4 +11,4 @@ class C {
|
||||
// EXIST: { itemText: "extFunForString", attributes: "bold" }
|
||||
// EXIST: { itemText: "extFunForAny", attributes: "" }
|
||||
// EXIST: { itemText: "extFunForStringNullable", attributes: "bold" }
|
||||
// EXIST: { itemText: "charAt", attributes: "bold" }
|
||||
// EXIST: { itemText: "charAt", attributes: "" }
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ fun foo(d: Derived): String {
|
||||
return d.<caret>
|
||||
}
|
||||
|
||||
// EXIST: { itemText: "fromTrait", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromTrait", attributes: "" }
|
||||
// EXIST: { itemText: "fromDerived", attributes: "bold" }
|
||||
// EXIST: { itemText: "fromBase", attributes: "" }
|
||||
// EXIST: { itemText: "toString", attributes: "" }
|
||||
|
||||
+12
@@ -325,6 +325,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InExtensionForNullable.kt")
|
||||
public void testInExtensionForNullable() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InExtensionForNullable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFileWithMultiDeclaration.kt")
|
||||
public void testInFileWithMultiDeclaration() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InFileWithMultiDeclaration.kt");
|
||||
@@ -715,6 +721,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NonPredictableSmartCast.kt")
|
||||
public void testNonPredictableSmartCast() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NonPredictableSmartCast.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ObjectInTypePosition.kt")
|
||||
public void testObjectInTypePosition() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ObjectInTypePosition.kt");
|
||||
|
||||
+12
@@ -325,6 +325,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InExtensionForNullable.kt")
|
||||
public void testInExtensionForNullable() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InExtensionForNullable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFileWithMultiDeclaration.kt")
|
||||
public void testInFileWithMultiDeclaration() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InFileWithMultiDeclaration.kt");
|
||||
@@ -715,6 +721,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NonPredictableSmartCast.kt")
|
||||
public void testNonPredictableSmartCast() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NonPredictableSmartCast.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ObjectInTypePosition.kt")
|
||||
public void testObjectInTypePosition() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ObjectInTypePosition.kt");
|
||||
|
||||
Reference in New Issue
Block a user