From 5bff98c1644615fc23853296d74ac452880e779e Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 15 Apr 2014 12:57:56 +0400 Subject: [PATCH] Smart completion: minor code refactoring --- .../jet/plugin/completion/SmartCompletion.kt | 111 ++++++++++-------- ...tionReference.kt => FunctionReference1.kt} | 0 ...e.kt.after => FunctionReference1.kt.after} | 0 .../handlers/smart/FunctionReference2.kt | 9 ++ .../smart/FunctionReference2.kt.after | 9 ++ .../SmartCompletionHandlerTestGenerated.java | 11 +- 6 files changed, 85 insertions(+), 55 deletions(-) rename idea/testData/completion/handlers/smart/{FunctionReference.kt => FunctionReference1.kt} (100%) rename idea/testData/completion/handlers/smart/{FunctionReference.kt.after => FunctionReference1.kt.after} (100%) create mode 100644 idea/testData/completion/handlers/smart/FunctionReference2.kt create mode 100644 idea/testData/completion/handlers/smart/FunctionReference2.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt b/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt index 8f04712205c..6eba2c63acf 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt @@ -76,56 +76,20 @@ class SmartCompletion(val expression: JetSimpleNameExpression, val itemsToSkip = calcItemsToSkip(expressionWithType) + val functionExpectedTypes = expectedTypes.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it.`type`) } + for (descriptor in referenceVariants) { if (itemsToSkip.contains(descriptor)) continue - run { - val matchedExpectedTypes = expectedTypes.filter { expectedType -> - typesOf(descriptor).any { descriptorType -> isSubtypeOf(descriptorType, expectedType.`type`) } - } - if (matchedExpectedTypes.isNotEmpty()) { - val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor) - result.add(addTailToLookupElement(lookupElement, matchedExpectedTypes)) - } + val matchedExpectedTypes = expectedTypes.filter { expectedType -> + typesOf(descriptor).any { descriptorType -> isSubtypeOf(descriptorType, expectedType.`type`) } + } + if (matchedExpectedTypes.isNotEmpty()) { + val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor) + result.add(addTailToLookupElement(lookupElement, matchedExpectedTypes)) } - val functionExpectedTypes = expectedTypes.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it.`type`) } - if (functionExpectedTypes.isNotEmpty()) { - fun functionReferenceLookupElement(descriptor: FunctionDescriptor): LookupElement? { - val functionType = functionType(descriptor) - if (functionType == null) return null - - val matchedExpectedTypes = functionExpectedTypes.filter { isSubtypeOf(functionType, it.`type`) } - if (matchedExpectedTypes.isEmpty()) return null - val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor) - val text = "::" + (if (descriptor is ConstructorDescriptor) descriptor.getContainingDeclaration().getName() else descriptor.getName()) - val lookupElementDecorated = object: LookupElementDecorator(lookupElement) { - override fun getLookupString() = text - - override fun renderElement(presentation: LookupElementPresentation) { - super.renderElement(presentation) - presentation.setItemText(text) - presentation.setTypeText("") - } - - override fun handleInsert(context: InsertionContext) { - } - } - - return addTailToLookupElement(lookupElementDecorated, matchedExpectedTypes) - } - - if (descriptor is SimpleFunctionDescriptor) { - functionReferenceLookupElement(descriptor)?.let { result.add(it) } - } - else if (descriptor is ClassDescriptor && descriptor.getModality() != Modality.ABSTRACT) { - val constructors = descriptor.getConstructors().filter(visibilityFilter) - if (constructors.size == 1) { - //TODO: this code is to be changed if overloads to start work after :: - functionReferenceLookupElement(constructors.single())?.let { result.add(it) } - } - } - } + toFunctionReferenceLookupElement(descriptor, functionExpectedTypes)?.let { result.add(it) } } if (receiver == null) { @@ -221,6 +185,49 @@ class SmartCompletion(val expression: JetSimpleNameExpression, return listOf() } + private fun toFunctionReferenceLookupElement(descriptor: DeclarationDescriptor, + functionExpectedTypes: Collection): LookupElement? { + if (functionExpectedTypes.isEmpty()) return null + + fun toLookupElement(descriptor: FunctionDescriptor): LookupElement? { + val functionType = functionType(descriptor) + if (functionType == null) return null + + val matchedExpectedTypes = functionExpectedTypes.filter { isSubtypeOf(functionType, it.`type`) } + if (matchedExpectedTypes.isEmpty()) return null + + val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor) + val text = "::" + (if (descriptor is ConstructorDescriptor) descriptor.getContainingDeclaration().getName() else descriptor.getName()) + val lookupElementDecorated = object: LookupElementDecorator(lookupElement) { + override fun getLookupString() = text + + override fun renderElement(presentation: LookupElementPresentation) { + super.renderElement(presentation) + presentation.setItemText(text) + presentation.setTypeText("") + } + + override fun handleInsert(context: InsertionContext) { + } + } + + return addTailToLookupElement(lookupElementDecorated, matchedExpectedTypes) + } + + if (descriptor is SimpleFunctionDescriptor) { + return toLookupElement(descriptor) + } + else if (descriptor is ClassDescriptor && descriptor.getModality() != Modality.ABSTRACT) { + val constructors = descriptor.getConstructors().filter(visibilityFilter) + if (constructors.size == 1) { + //TODO: this code is to be changed if overloads to start work after :: + return toLookupElement(constructors.single()) + } + } + + return null + } + private fun MutableCollection.addTypeInstantiationItems(expectedTypes: Collection) { val expectedTypesGrouped: Map> = expectedTypes.groupBy { TypeUtils.makeNotNullable(it.`type`) } for ((jetType, types) in expectedTypesGrouped) { @@ -353,16 +360,16 @@ class SmartCompletion(val expression: JetSimpleNameExpression, else -> null } return ((((expression?.getParent() as? JetValueArgument) - ?.getParent() as? JetValueArgumentList) - ?.getParent() as? JetCallExpression) - ?.getCalleeExpression() as? JetSimpleNameExpression) - ?.getReferencedName() + ?.getParent() as? JetValueArgumentList) + ?.getParent() as? JetCallExpression) + ?.getCalleeExpression() as? JetSimpleNameExpression) + ?.getReferencedName() } private fun dataFlowToDescriptorTypes(expression: JetExpression, receiver: JetExpression?): (DeclarationDescriptor) -> Iterable { val dataFlowInfo = bindingContext[BindingContext.EXPRESSION_DATA_FLOW_INFO, expression] val (variableToTypes: Map>, notNullVariables: Set) - = processDataFlowInfo(dataFlowInfo, receiver) + = processDataFlowInfo(dataFlowInfo, receiver) fun typesOf(descriptor: DeclarationDescriptor): Iterable { if (descriptor is CallableDescriptor) { @@ -583,8 +590,8 @@ class SmartCompletion(val expression: JetSimpleNameExpression, } } - private fun addTailToLookupElement(lookupElement: LookupElement, expectedTypes: Collection): LookupElement - = addTailToLookupElement(lookupElement, mergeTails(expectedTypes.map { it.tail })) + private fun addTailToLookupElement(lookupElement: LookupElement, matchedExpectedTypes: Collection): LookupElement + = addTailToLookupElement(lookupElement, mergeTails(matchedExpectedTypes.map { it.tail })) private fun functionType(function: FunctionDescriptor): JetType? { return KotlinBuiltIns.getInstance().getKFunctionType(function.getAnnotations(), diff --git a/idea/testData/completion/handlers/smart/FunctionReference.kt b/idea/testData/completion/handlers/smart/FunctionReference1.kt similarity index 100% rename from idea/testData/completion/handlers/smart/FunctionReference.kt rename to idea/testData/completion/handlers/smart/FunctionReference1.kt diff --git a/idea/testData/completion/handlers/smart/FunctionReference.kt.after b/idea/testData/completion/handlers/smart/FunctionReference1.kt.after similarity index 100% rename from idea/testData/completion/handlers/smart/FunctionReference.kt.after rename to idea/testData/completion/handlers/smart/FunctionReference1.kt.after diff --git a/idea/testData/completion/handlers/smart/FunctionReference2.kt b/idea/testData/completion/handlers/smart/FunctionReference2.kt new file mode 100644 index 00000000000..3461032fd34 --- /dev/null +++ b/idea/testData/completion/handlers/smart/FunctionReference2.kt @@ -0,0 +1,9 @@ +fun foo(p: () -> Unit, i: Int){} + +fun bar() { + foo() +} + +fun f(){} + +// ELEMENT: ::f \ No newline at end of file diff --git a/idea/testData/completion/handlers/smart/FunctionReference2.kt.after b/idea/testData/completion/handlers/smart/FunctionReference2.kt.after new file mode 100644 index 00000000000..57ff4a2d62f --- /dev/null +++ b/idea/testData/completion/handlers/smart/FunctionReference2.kt.after @@ -0,0 +1,9 @@ +fun foo(p: () -> Unit, i: Int){} + +fun bar() { + foo(::f, ) +} + +fun f(){} + +// ELEMENT: ::f \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java index 7b4592ea2b0..8799c3a8c37 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java @@ -161,9 +161,14 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest("idea/testData/completion/handlers/smart/EnumMember.kt"); } - @TestMetadata("FunctionReference.kt") - public void testFunctionReference() throws Exception { - doTest("idea/testData/completion/handlers/smart/FunctionReference.kt"); + @TestMetadata("FunctionReference1.kt") + public void testFunctionReference1() throws Exception { + doTest("idea/testData/completion/handlers/smart/FunctionReference1.kt"); + } + + @TestMetadata("FunctionReference2.kt") + public void testFunctionReference2() throws Exception { + doTest("idea/testData/completion/handlers/smart/FunctionReference2.kt"); } @TestMetadata("JavaEnumMemberInsertsImport.kt")