From 88bdf88bbbe7faab8dd5ee72f38cdc5fc8b4efd7 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 25 Mar 2016 17:14:52 +0300 Subject: [PATCH] "Delegates" members in smart completion after "by" #KT-6231 Fixed --- .../idea/completion/smart/SmartCompletion.kt | 2 +- .../idea/completion/smart/StaticMembers.kt | 38 +++++++++++++------ .../kotlin/idea/completion/smart/Utils.kt | 1 + .../common/fromSmart/PropertyDelegate.kt | 9 +++++ .../smart/propertyDelegate/ExplicitValType.kt | 11 +++++- .../smart/propertyDelegate/ExplicitVarType.kt | 3 ++ .../testData/smart/propertyDelegate/Order.kt | 16 ++++++++ .../smart/propertyDelegate/ValInClass.kt | 3 ++ .../smart/propertyDelegate/VarInClass.kt | 5 +++ .../test/JSBasicCompletionTestGenerated.java | 6 +++ .../test/JvmBasicCompletionTestGenerated.java | 6 +++ .../test/JvmSmartCompletionTestGenerated.java | 6 +++ .../kotlin/idea/core/ExpectedInfos.kt | 5 ++- 13 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/fromSmart/PropertyDelegate.kt create mode 100644 idea/idea-completion/testData/smart/propertyDelegate/Order.kt 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 4a707138a5f..afa651ce1b8 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 @@ -209,7 +209,7 @@ class SmartCompletion( .addTo(items, inheritanceSearchers, expectedInfos) if (expression is KtSimpleNameExpression) { - StaticMembers(bindingContext, lookupElementFactory, resolutionFacade) + StaticMembers(bindingContext, lookupElementFactory, resolutionFacade, moduleDescriptor) .addToCollection(items, expectedInfos, expression, descriptorsToSkip) } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt index 32114799996..ad38cd72fd1 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt @@ -18,13 +18,16 @@ package org.jetbrains.kotlin.idea.completion.smart import com.intellij.codeInsight.lookup.LookupElement 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.decorateAsStaticMember 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.multipleFuzzyTypes import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.fuzzyReturnType +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -36,23 +39,33 @@ import java.util.* class StaticMembers( private val bindingContext: BindingContext, private val lookupElementFactory: LookupElementFactory, - private val resolutionFacade: ResolutionFacade + private val resolutionFacade: ResolutionFacade, + private val moduleDescriptor: ModuleDescriptor ) { - fun addToCollection(collection: MutableCollection, - expectedInfos: Collection, - context: KtSimpleNameExpression, - enumEntriesToSkip: Set) { + fun addToCollection( + collection: MutableCollection, + expectedInfos: Collection, + context: KtSimpleNameExpression, + enumEntriesToSkip: Set + ) { val expectedInfosByClass = HashMap>() for (expectedInfo in expectedInfos) { for (fuzzyType in expectedInfo.multipleFuzzyTypes) { val classDescriptor = fuzzyType.type.constructor.declarationDescriptor as? ClassDescriptor ?: continue 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) { 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, expectedInfos: Collection, context: KtSimpleNameExpression, - enumEntriesToSkip: Set) { - + enumEntriesToSkip: Set, + priority: SmartCompletionItemPriority + ) { fun processMember(descriptor: DeclarationDescriptor) { if (descriptor is DeclarationDescriptorWithVisibility && !descriptor.isVisible(context, null, bindingContext, resolutionFacade)) return @@ -79,7 +93,7 @@ class StaticMembers( return } - collection.addLookupElements(descriptor, expectedInfos, matcher) { createLookupElements(it) } + collection.addLookupElements(descriptor, expectedInfos, matcher) { createLookupElements(it, priority) } } classDescriptor.staticScope.getContributedDescriptors().forEach(::processMember) @@ -92,17 +106,17 @@ class StaticMembers( } 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.forEach(::processMember) } - private fun createLookupElements(memberDescriptor: DeclarationDescriptor): Collection { + private fun createLookupElements(memberDescriptor: DeclarationDescriptor, priority: SmartCompletionItemPriority): Collection { return lookupElementFactory.createStandardLookupElementsForDescriptor(memberDescriptor, useReceiverTypes = false) .map { it.decorateAsStaticMember(memberDescriptor, classNameAsLookupString = true)!! - .assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER) + .assignSmartCompletionPriority(priority) } } } 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 c7ebadf1ab2..47b00b50d10 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 @@ -259,6 +259,7 @@ enum class SmartCompletionItemPriority { FALSE, CLASS_LITERAL, THIS, + DELEGATES_STATIC_MEMBER, DEFAULT, NULLABLE, INSTANTIATION, diff --git a/idea/idea-completion/testData/basic/common/fromSmart/PropertyDelegate.kt b/idea/idea-completion/testData/basic/common/fromSmart/PropertyDelegate.kt new file mode 100644 index 00000000000..00622198c54 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/fromSmart/PropertyDelegate.kt @@ -0,0 +1,9 @@ +class X + +class C { + val property by D +} + +// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ExplicitValType.kt b/idea/idea-completion/testData/smart/propertyDelegate/ExplicitValType.kt index 8553fb2f8d8..2038f5c73f6 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/ExplicitValType.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/ExplicitValType.kt @@ -27,9 +27,18 @@ class C { } // EXIST: lazy +// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } + // EXIST: createX1 // EXIST: createX2 // ABSENT: createX3 // EXIST: createY1 // ABSENT: createY2 -/*TODO: add constructors*/ + +// EXIST: X1 +// EXIST: X2 +// ABSENT: X3 +// EXIST: Y1 +// ABSENT: Y2 diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ExplicitVarType.kt b/idea/idea-completion/testData/smart/propertyDelegate/ExplicitVarType.kt index 5754ea56102..b83e4be750b 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/ExplicitVarType.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/ExplicitVarType.kt @@ -24,6 +24,9 @@ class C { } // ABSENT: lazy +// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: CharSequence, crossinline onChange: (KProperty<*>, CharSequence, CharSequence) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } // ABSENT: createX1 // EXIST: createX2 // ABSENT: createX3 diff --git a/idea/idea-completion/testData/smart/propertyDelegate/Order.kt b/idea/idea-completion/testData/smart/propertyDelegate/Order.kt new file mode 100644 index 00000000000..3b3ab10b892 --- /dev/null +++ b/idea/idea-completion/testData/smart/propertyDelegate/Order.kt @@ -0,0 +1,16 @@ +import kotlin.reflect.KProperty + +class X { + operator fun getValue(thisRef: C, property: KProperty<*>): String = "" +} + +class C { + val property by +} + +// WITH_ORDER +// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: lazy +// EXIST: X diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ValInClass.kt b/idea/idea-completion/testData/smart/propertyDelegate/ValInClass.kt index ef6274ee868..c8c11bcbecc 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/ValInClass.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/ValInClass.kt @@ -34,6 +34,9 @@ class C { } // EXIST: lazy +// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } // EXIST: createX1 // ABSENT: createX2 diff --git a/idea/idea-completion/testData/smart/propertyDelegate/VarInClass.kt b/idea/idea-completion/testData/smart/propertyDelegate/VarInClass.kt index e619a048fa8..ee8f513e2fb 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/VarInClass.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/VarInClass.kt @@ -42,11 +42,16 @@ class C { } // ABSENT: lazy +// EXIST: { itemText: "Delegates.notNull", tailText:"() (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.observable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Unit) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } +// EXIST: { itemText: "Delegates.vetoable", tailText:"(initialValue: T, crossinline onChange: (KProperty<*>, T, T) -> Boolean) (kotlin.properties)", typeText: "ReadWriteProperty", attributes:"" } + // EXIST: createX1 // ABSENT: createX2 // ABSENT: createX3 // EXIST: createX4 // ABSENT: createX5 + // EXIST: X1 // ABSENT: X2 // ABSENT: X3 diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index f588c8effc2..72080b44760 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -1437,6 +1437,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes 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") public void testWhenByEnum() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/WhenByEnum.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index 51fb431b7cf..6209aaa12a7 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -1437,6 +1437,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT 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") public void testWhenByEnum() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/WhenByEnum.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java index f769792b64b..9163841c229 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java @@ -1504,6 +1504,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT 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") public void testValInClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/ValInClass.kt"); diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt index 60a4f6bfde1..5230d4016ca 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt @@ -148,6 +148,8 @@ class WhenEntryAdditionalData(val whenWithSubject: Boolean) : ExpectedInfo.Addit object IfConditionAdditionalData : ExpectedInfo.AdditionalData +object PropertyDelegateAdditionalData : ExpectedInfo.AdditionalData + class ExpectedInfos( private val bindingContext: BindingContext, private val resolutionFacade: ResolutionFacade, @@ -662,8 +664,7 @@ class ExpectedInfos( result } } - return listOf(ExpectedInfo(byTypeFilter, null, null)) - //TODO: special items for "Delegates...." + return listOf(ExpectedInfo(byTypeFilter, null, null, additionalData = PropertyDelegateAdditionalData)) } private fun getFromBindingContext(expressionWithType: KtExpression): Collection? {