"Delegates" members in smart completion after "by"
#KT-6231 Fixed
This commit is contained in:
+1
-1
@@ -209,7 +209,7 @@ class SmartCompletion(
|
|||||||
.addTo(items, inheritanceSearchers, expectedInfos)
|
.addTo(items, inheritanceSearchers, expectedInfos)
|
||||||
|
|
||||||
if (expression is KtSimpleNameExpression) {
|
if (expression is KtSimpleNameExpression) {
|
||||||
StaticMembers(bindingContext, lookupElementFactory, resolutionFacade)
|
StaticMembers(bindingContext, lookupElementFactory, resolutionFacade, moduleDescriptor)
|
||||||
.addToCollection(items, expectedInfos, expression, descriptorsToSkip)
|
.addToCollection(items, expectedInfos, expression, descriptorsToSkip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-12
@@ -18,13 +18,16 @@ package org.jetbrains.kotlin.idea.completion.smart
|
|||||||
|
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
||||||
import org.jetbrains.kotlin.idea.completion.LookupElementFactory
|
import org.jetbrains.kotlin.idea.completion.LookupElementFactory
|
||||||
import org.jetbrains.kotlin.idea.completion.decorateAsStaticMember
|
import org.jetbrains.kotlin.idea.completion.decorateAsStaticMember
|
||||||
import org.jetbrains.kotlin.idea.core.ExpectedInfo
|
import org.jetbrains.kotlin.idea.core.ExpectedInfo
|
||||||
|
import org.jetbrains.kotlin.idea.core.PropertyDelegateAdditionalData
|
||||||
import org.jetbrains.kotlin.idea.core.isVisible
|
import org.jetbrains.kotlin.idea.core.isVisible
|
||||||
import org.jetbrains.kotlin.idea.core.multipleFuzzyTypes
|
import org.jetbrains.kotlin.idea.core.multipleFuzzyTypes
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -36,23 +39,33 @@ import java.util.*
|
|||||||
class StaticMembers(
|
class StaticMembers(
|
||||||
private val bindingContext: BindingContext,
|
private val bindingContext: BindingContext,
|
||||||
private val lookupElementFactory: LookupElementFactory,
|
private val lookupElementFactory: LookupElementFactory,
|
||||||
private val resolutionFacade: ResolutionFacade
|
private val resolutionFacade: ResolutionFacade,
|
||||||
|
private val moduleDescriptor: ModuleDescriptor
|
||||||
) {
|
) {
|
||||||
fun addToCollection(collection: MutableCollection<LookupElement>,
|
fun addToCollection(
|
||||||
expectedInfos: Collection<ExpectedInfo>,
|
collection: MutableCollection<LookupElement>,
|
||||||
context: KtSimpleNameExpression,
|
expectedInfos: Collection<ExpectedInfo>,
|
||||||
enumEntriesToSkip: Set<DeclarationDescriptor>) {
|
context: KtSimpleNameExpression,
|
||||||
|
enumEntriesToSkip: Set<DeclarationDescriptor>
|
||||||
|
) {
|
||||||
val expectedInfosByClass = HashMap<ClassDescriptor, MutableList<ExpectedInfo>>()
|
val expectedInfosByClass = HashMap<ClassDescriptor, MutableList<ExpectedInfo>>()
|
||||||
for (expectedInfo in expectedInfos) {
|
for (expectedInfo in expectedInfos) {
|
||||||
for (fuzzyType in expectedInfo.multipleFuzzyTypes) {
|
for (fuzzyType in expectedInfo.multipleFuzzyTypes) {
|
||||||
val classDescriptor = fuzzyType.type.constructor.declarationDescriptor as? ClassDescriptor ?: continue
|
val classDescriptor = fuzzyType.type.constructor.declarationDescriptor as? ClassDescriptor ?: continue
|
||||||
expectedInfosByClass.getOrPut(classDescriptor) { ArrayList() }.add(expectedInfo)
|
expectedInfosByClass.getOrPut(classDescriptor) { ArrayList() }.add(expectedInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expectedInfo.additionalData is PropertyDelegateAdditionalData) {
|
||||||
|
val delegatesClass = resolutionFacade.resolveImportReference(moduleDescriptor, FqName("kotlin.properties.Delegates")).singleOrNull()
|
||||||
|
if (delegatesClass is ClassDescriptor) {
|
||||||
|
addToCollection(collection, delegatesClass, listOf(expectedInfo), context, enumEntriesToSkip, SmartCompletionItemPriority.DELEGATES_STATIC_MEMBER)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((classDescriptor, expectedInfosForClass) in expectedInfosByClass) {
|
for ((classDescriptor, expectedInfosForClass) in expectedInfosByClass) {
|
||||||
if (!classDescriptor.name.isSpecial) {
|
if (!classDescriptor.name.isSpecial) {
|
||||||
addToCollection(collection, classDescriptor, expectedInfosForClass, context, enumEntriesToSkip)
|
addToCollection(collection, classDescriptor, expectedInfosForClass, context, enumEntriesToSkip, SmartCompletionItemPriority.STATIC_MEMBER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,8 +75,9 @@ class StaticMembers(
|
|||||||
classDescriptor: ClassDescriptor,
|
classDescriptor: ClassDescriptor,
|
||||||
expectedInfos: Collection<ExpectedInfo>,
|
expectedInfos: Collection<ExpectedInfo>,
|
||||||
context: KtSimpleNameExpression,
|
context: KtSimpleNameExpression,
|
||||||
enumEntriesToSkip: Set<DeclarationDescriptor>) {
|
enumEntriesToSkip: Set<DeclarationDescriptor>,
|
||||||
|
priority: SmartCompletionItemPriority
|
||||||
|
) {
|
||||||
fun processMember(descriptor: DeclarationDescriptor) {
|
fun processMember(descriptor: DeclarationDescriptor) {
|
||||||
if (descriptor is DeclarationDescriptorWithVisibility && !descriptor.isVisible(context, null, bindingContext, resolutionFacade)) return
|
if (descriptor is DeclarationDescriptorWithVisibility && !descriptor.isVisible(context, null, bindingContext, resolutionFacade)) return
|
||||||
|
|
||||||
@@ -79,7 +93,7 @@ class StaticMembers(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
collection.addLookupElements(descriptor, expectedInfos, matcher) { createLookupElements(it) }
|
collection.addLookupElements(descriptor, expectedInfos, matcher) { createLookupElements(it, priority) }
|
||||||
}
|
}
|
||||||
|
|
||||||
classDescriptor.staticScope.getContributedDescriptors().forEach(::processMember)
|
classDescriptor.staticScope.getContributedDescriptors().forEach(::processMember)
|
||||||
@@ -92,17 +106,17 @@ class StaticMembers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var members = classDescriptor.defaultType.memberScope.getContributedDescriptors()
|
var members = classDescriptor.defaultType.memberScope.getContributedDescriptors()
|
||||||
if (classDescriptor.kind != ClassKind.ENUM_CLASS) {
|
if (classDescriptor.kind != ClassKind.ENUM_CLASS && classDescriptor.kind != ClassKind.OBJECT) {
|
||||||
members = members.filter { DescriptorUtils.isNonCompanionObject(it) }
|
members = members.filter { DescriptorUtils.isNonCompanionObject(it) }
|
||||||
}
|
}
|
||||||
members.forEach(::processMember)
|
members.forEach(::processMember)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createLookupElements(memberDescriptor: DeclarationDescriptor): Collection<LookupElement> {
|
private fun createLookupElements(memberDescriptor: DeclarationDescriptor, priority: SmartCompletionItemPriority): Collection<LookupElement> {
|
||||||
return lookupElementFactory.createStandardLookupElementsForDescriptor(memberDescriptor, useReceiverTypes = false)
|
return lookupElementFactory.createStandardLookupElementsForDescriptor(memberDescriptor, useReceiverTypes = false)
|
||||||
.map {
|
.map {
|
||||||
it.decorateAsStaticMember(memberDescriptor, classNameAsLookupString = true)!!
|
it.decorateAsStaticMember(memberDescriptor, classNameAsLookupString = true)!!
|
||||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER)
|
.assignSmartCompletionPriority(priority)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ enum class SmartCompletionItemPriority {
|
|||||||
FALSE,
|
FALSE,
|
||||||
CLASS_LITERAL,
|
CLASS_LITERAL,
|
||||||
THIS,
|
THIS,
|
||||||
|
DELEGATES_STATIC_MEMBER,
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
NULLABLE,
|
NULLABLE,
|
||||||
INSTANTIATION,
|
INSTANTIATION,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class X
|
||||||
|
|
||||||
|
class C {
|
||||||
|
val property by D<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
@@ -27,9 +27,18 @@ class C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXIST: lazy
|
// EXIST: lazy
|
||||||
|
// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty<Any?, CharSequence>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, CharSequence>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, CharSequence>", attributes:"" }
|
||||||
|
|
||||||
// EXIST: createX1
|
// EXIST: createX1
|
||||||
// EXIST: createX2
|
// EXIST: createX2
|
||||||
// ABSENT: createX3
|
// ABSENT: createX3
|
||||||
// EXIST: createY1
|
// EXIST: createY1
|
||||||
// ABSENT: createY2
|
// ABSENT: createY2
|
||||||
/*TODO: add constructors*/
|
|
||||||
|
// EXIST: X1
|
||||||
|
// EXIST: X2
|
||||||
|
// ABSENT: X3
|
||||||
|
// EXIST: Y1
|
||||||
|
// ABSENT: Y2
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ class C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ABSENT: lazy
|
// ABSENT: lazy
|
||||||
|
// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty<Any?, CharSequence>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, CharSequence>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, CharSequence>", attributes:"" }
|
||||||
// ABSENT: createX1
|
// ABSENT: createX1
|
||||||
// EXIST: createX2
|
// EXIST: createX2
|
||||||
// ABSENT: createX3
|
// ABSENT: createX3
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class X {
|
||||||
|
operator fun getValue(thisRef: C, property: KProperty<*>): String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
val property by <caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// WITH_ORDER
|
||||||
|
// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: lazy
|
||||||
|
// EXIST: X
|
||||||
@@ -34,6 +34,9 @@ class C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXIST: lazy
|
// EXIST: lazy
|
||||||
|
// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
|
||||||
// EXIST: createX1
|
// EXIST: createX1
|
||||||
// ABSENT: createX2
|
// ABSENT: createX2
|
||||||
|
|||||||
@@ -42,11 +42,16 @@ class C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ABSENT: lazy
|
// ABSENT: lazy
|
||||||
|
// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty<Any?, T>", attributes:"" }
|
||||||
|
|
||||||
// EXIST: createX1
|
// EXIST: createX1
|
||||||
// ABSENT: createX2
|
// ABSENT: createX2
|
||||||
// ABSENT: createX3
|
// ABSENT: createX3
|
||||||
// EXIST: createX4
|
// EXIST: createX4
|
||||||
// ABSENT: createX5
|
// ABSENT: createX5
|
||||||
|
|
||||||
// EXIST: X1
|
// EXIST: X1
|
||||||
// ABSENT: X2
|
// ABSENT: X2
|
||||||
// ABSENT: X3
|
// ABSENT: X3
|
||||||
|
|||||||
+6
@@ -1437,6 +1437,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("PropertyDelegate.kt")
|
||||||
|
public void testPropertyDelegate() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/PropertyDelegate.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("WhenByEnum.kt")
|
@TestMetadata("WhenByEnum.kt")
|
||||||
public void testWhenByEnum() throws Exception {
|
public void testWhenByEnum() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/WhenByEnum.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/WhenByEnum.kt");
|
||||||
|
|||||||
+6
@@ -1437,6 +1437,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("PropertyDelegate.kt")
|
||||||
|
public void testPropertyDelegate() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/PropertyDelegate.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("WhenByEnum.kt")
|
@TestMetadata("WhenByEnum.kt")
|
||||||
public void testWhenByEnum() throws Exception {
|
public void testWhenByEnum() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/WhenByEnum.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/WhenByEnum.kt");
|
||||||
|
|||||||
+6
@@ -1504,6 +1504,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Order.kt")
|
||||||
|
public void testOrder() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/Order.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ValInClass.kt")
|
@TestMetadata("ValInClass.kt")
|
||||||
public void testValInClass() throws Exception {
|
public void testValInClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/ValInClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/ValInClass.kt");
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ class WhenEntryAdditionalData(val whenWithSubject: Boolean) : ExpectedInfo.Addit
|
|||||||
|
|
||||||
object IfConditionAdditionalData : ExpectedInfo.AdditionalData
|
object IfConditionAdditionalData : ExpectedInfo.AdditionalData
|
||||||
|
|
||||||
|
object PropertyDelegateAdditionalData : ExpectedInfo.AdditionalData
|
||||||
|
|
||||||
class ExpectedInfos(
|
class ExpectedInfos(
|
||||||
private val bindingContext: BindingContext,
|
private val bindingContext: BindingContext,
|
||||||
private val resolutionFacade: ResolutionFacade,
|
private val resolutionFacade: ResolutionFacade,
|
||||||
@@ -662,8 +664,7 @@ class ExpectedInfos(
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return listOf(ExpectedInfo(byTypeFilter, null, null))
|
return listOf(ExpectedInfo(byTypeFilter, null, null, additionalData = PropertyDelegateAdditionalData))
|
||||||
//TODO: special items for "Delegates...."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFromBindingContext(expressionWithType: KtExpression): Collection<ExpectedInfo>? {
|
private fun getFromBindingContext(expressionWithType: KtExpression): Collection<ExpectedInfo>? {
|
||||||
|
|||||||
Reference in New Issue
Block a user