From 47d3e2e1bb8da5d924b23a433823b98bb36257ac Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 27 Nov 2013 20:15:28 +0400 Subject: [PATCH] Smart completion: this expressions added --- .../codeInsight/lookup/annotations.xml | 28 ++++++++++ .../jet/plugin/completion/SmartCompletion.kt | 54 +++++++++++++++++++ .../completion/smart/QualifiedThis.kt | 7 +++ .../smart/QualifiedThisOfAnonymousObject.kt | 15 ++++++ .../smart/QualifiedThisOfExtensionFunction.kt | 9 ++++ .../smart/QualifiedThisOfExtensionLambda1.kt | 12 +++++ .../smart/QualifiedThisOfExtensionLambda2.kt | 14 +++++ .../smart/QualifiedThisOfExtensionLambda3.kt | 12 +++++ idea/testData/completion/smart/This.kt | 5 ++ idea/testData/completion/smart/This.kt.todo | 5 -- .../JetSmartCompletionTestGenerated.java | 35 ++++++++++++ 11 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 idea/testData/completion/smart/QualifiedThis.kt create mode 100644 idea/testData/completion/smart/QualifiedThisOfAnonymousObject.kt create mode 100644 idea/testData/completion/smart/QualifiedThisOfExtensionFunction.kt create mode 100644 idea/testData/completion/smart/QualifiedThisOfExtensionLambda1.kt create mode 100644 idea/testData/completion/smart/QualifiedThisOfExtensionLambda2.kt create mode 100644 idea/testData/completion/smart/QualifiedThisOfExtensionLambda3.kt create mode 100644 idea/testData/completion/smart/This.kt delete mode 100644 idea/testData/completion/smart/This.kt.todo diff --git a/annotations/com/intellij/codeInsight/lookup/annotations.xml b/annotations/com/intellij/codeInsight/lookup/annotations.xml index 07cea5c5724..ad8a832f1e4 100644 --- a/annotations/com/intellij/codeInsight/lookup/annotations.xml +++ b/annotations/com/intellij/codeInsight/lookup/annotations.xml @@ -6,6 +6,26 @@ + + + + + + + + + + + + + + + @@ -18,6 +38,14 @@ name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder withTailText(java.lang.String)'> + + + + + + diff --git a/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt b/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt index 60817a11fc2..dde80688ee4 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt @@ -15,6 +15,10 @@ import com.google.common.collect.SetMultimap import java.util.* import org.jetbrains.jet.lang.resolve.calls.autocasts.* import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration +import org.jetbrains.jet.lang.resolve.name.Name trait SmartCompletionData{ fun accepts(descriptor: DeclarationDescriptor): Boolean @@ -44,6 +48,7 @@ fun buildSmartCompletionData(expression: JetSimpleNameExpression, resolveSession if (receiver == null) { typeInstantiationItems(expectedType, resolveSession, bindingContext).toCollection(additionalElements) + thisItems(expressionWithType, expectedType, bindingContext).toCollection(additionalElements) } val dataFlowInfo = bindingContext.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expressionWithType) @@ -142,6 +147,44 @@ private fun typeInstantiationItems(expectedType: JetType, resolveSession: Cancel return listOf() } +private fun thisItems(context: JetExpression, expectedType: JetType, bindingContext: BindingContext): Iterable { + val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, context) + if (scope == null) return listOf() + + val receivers: List = scope.getImplicitReceiversHierarchy() + val result = ArrayList() + for (i in 0..receivers.size - 1) { + val receiver = receivers[i] + val thisType = receiver.getType() + if (JetTypeChecker.INSTANCE.isSubtypeOf(thisType, expectedType)) { + //TODO: use this code when KT-4258 fixed + //val expressionText = if (i == 0) "this" else "this@" + (thisQualifierName(receiver, bindingContext) ?: continue) + val qualifier = if (i == 0) null else thisQualifierName(receiver, bindingContext) ?: continue + val expressionText = if (qualifier == null) "this" else "this@" + qualifier + result.add(LookupElementBuilder.create(expressionText).withTypeText(DescriptorRenderer.TEXT.renderType(thisType))) + } + } + return result +} + +private fun thisQualifierName(receiver: ReceiverParameterDescriptor, bindingContext: BindingContext): String? { + val descriptor: DeclarationDescriptor = receiver.getContainingDeclaration() + val name: Name = descriptor.getName() + if (!name.isSpecial()) return name.asString() + + val psiElement = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor) + val expression: JetExpression? = when (psiElement) { + is JetFunctionLiteral -> psiElement.getParent() as? JetFunctionLiteralExpression + is JetObjectDeclaration -> psiElement.getParent() as? JetObjectLiteralExpression + else -> null + } + return ((((expression?.getParent() as? JetValueArgument) + ?.getParent() as? JetValueArgumentList) + ?.getParent() as? JetCallExpression) + ?.getCalleeExpression() as? JetSimpleNameExpression) + ?.getReferencedName() +} + private data class ProcessDataFlowInfoResult( val variableToTypes: Map> = Collections.emptyMap(), val notNullVariables: Set = Collections.emptySet() @@ -195,3 +238,14 @@ private fun MutableCollection.addAll(iterator: Iterator) { add(item) } } + +fun accept1(handler: String.(t: T) -> Unit){} +fun accept2(handler: Int.() -> Unit){} + +fun foo(){ + accept1({ + accept2({ + val s: String = this@accept1 + }) + }) +} diff --git a/idea/testData/completion/smart/QualifiedThis.kt b/idea/testData/completion/smart/QualifiedThis.kt new file mode 100644 index 00000000000..08ebd0ce4a5 --- /dev/null +++ b/idea/testData/completion/smart/QualifiedThis.kt @@ -0,0 +1,7 @@ +class Foo{ + fun String.foo(){ + val foo : Foo = + } +} + +// EXIST: { lookupString:"this@Foo", typeText:"Foo" } diff --git a/idea/testData/completion/smart/QualifiedThisOfAnonymousObject.kt b/idea/testData/completion/smart/QualifiedThisOfAnonymousObject.kt new file mode 100644 index 00000000000..1a87fd07af0 --- /dev/null +++ b/idea/testData/completion/smart/QualifiedThisOfAnonymousObject.kt @@ -0,0 +1,15 @@ +open class Foo + +fun foo(f: Foo){} + +fun bar() { + foo(object: Foo() { + inner class Inner { + fun f() { + val x: Foo = + } + } + }) +} + +// EXIST: this@foo diff --git a/idea/testData/completion/smart/QualifiedThisOfExtensionFunction.kt b/idea/testData/completion/smart/QualifiedThisOfExtensionFunction.kt new file mode 100644 index 00000000000..7f2a3808179 --- /dev/null +++ b/idea/testData/completion/smart/QualifiedThisOfExtensionFunction.kt @@ -0,0 +1,9 @@ +class Foo{ + fun String.foo(){ + fun Foo.bar(){ + val s: String = + } + } +} + +// EXIST: { lookupString:"this@foo", typeText:"jet.String" } diff --git a/idea/testData/completion/smart/QualifiedThisOfExtensionLambda1.kt b/idea/testData/completion/smart/QualifiedThisOfExtensionLambda1.kt new file mode 100644 index 00000000000..6c2819fea9f --- /dev/null +++ b/idea/testData/completion/smart/QualifiedThisOfExtensionLambda1.kt @@ -0,0 +1,12 @@ +fun accept1(handler: String.() -> Unit){} +fun accept2(handler: Int.() -> Unit){} + +fun foo(){ + accept1({ + accept2({ + val s: String = + }) + }) +} + +// EXIST: this@accept1 diff --git a/idea/testData/completion/smart/QualifiedThisOfExtensionLambda2.kt b/idea/testData/completion/smart/QualifiedThisOfExtensionLambda2.kt new file mode 100644 index 00000000000..d827e633233 --- /dev/null +++ b/idea/testData/completion/smart/QualifiedThisOfExtensionLambda2.kt @@ -0,0 +1,14 @@ +object X { + fun accept1(handler: String.() -> Unit){} + fun accept2(handler: Int.() -> Unit){} +} + +fun foo(){ + X.accept1({ + X.accept2({ + val s: String = + }) + }) +} + +// EXIST: this@accept1 diff --git a/idea/testData/completion/smart/QualifiedThisOfExtensionLambda3.kt b/idea/testData/completion/smart/QualifiedThisOfExtensionLambda3.kt new file mode 100644 index 00000000000..020fd058d46 --- /dev/null +++ b/idea/testData/completion/smart/QualifiedThisOfExtensionLambda3.kt @@ -0,0 +1,12 @@ +fun accept1(handler: String.(t: T) -> Unit){} +fun accept2(handler: Int.() -> Unit){} + +fun foo(){ + accept1({ + accept2({ + val s: String = + }) + }) +} + +// EXIST: this@accept1 diff --git a/idea/testData/completion/smart/This.kt b/idea/testData/completion/smart/This.kt new file mode 100644 index 00000000000..7670e7c774a --- /dev/null +++ b/idea/testData/completion/smart/This.kt @@ -0,0 +1,5 @@ +fun String.foo(){ + val s : String = +} + +// EXIST: { lookupString:"this", typeText:"jet.String" } diff --git a/idea/testData/completion/smart/This.kt.todo b/idea/testData/completion/smart/This.kt.todo deleted file mode 100644 index af370491d15..00000000000 --- a/idea/testData/completion/smart/This.kt.todo +++ /dev/null @@ -1,5 +0,0 @@ -fun String.foo(){ - val s : String = -} - -// EXIST: this diff --git a/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java index 440fb6d69a5..2c23bf587ba 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java @@ -126,6 +126,41 @@ public class JetSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT doTest("idea/testData/completion/smart/NotSillyAssignment.kt"); } + @TestMetadata("QualifiedThis.kt") + public void testQualifiedThis() throws Exception { + doTest("idea/testData/completion/smart/QualifiedThis.kt"); + } + + @TestMetadata("QualifiedThisOfAnonymousObject.kt") + public void testQualifiedThisOfAnonymousObject() throws Exception { + doTest("idea/testData/completion/smart/QualifiedThisOfAnonymousObject.kt"); + } + + @TestMetadata("QualifiedThisOfExtensionFunction.kt") + public void testQualifiedThisOfExtensionFunction() throws Exception { + doTest("idea/testData/completion/smart/QualifiedThisOfExtensionFunction.kt"); + } + + @TestMetadata("QualifiedThisOfExtensionLambda1.kt") + public void testQualifiedThisOfExtensionLambda1() throws Exception { + doTest("idea/testData/completion/smart/QualifiedThisOfExtensionLambda1.kt"); + } + + @TestMetadata("QualifiedThisOfExtensionLambda2.kt") + public void testQualifiedThisOfExtensionLambda2() throws Exception { + doTest("idea/testData/completion/smart/QualifiedThisOfExtensionLambda2.kt"); + } + + @TestMetadata("QualifiedThisOfExtensionLambda3.kt") + public void testQualifiedThisOfExtensionLambda3() throws Exception { + doTest("idea/testData/completion/smart/QualifiedThisOfExtensionLambda3.kt"); + } + + @TestMetadata("This.kt") + public void testThis() throws Exception { + doTest("idea/testData/completion/smart/This.kt"); + } + @TestMetadata("VariableInitializer.kt") public void testVariableInitializer() throws Exception { doTest("idea/testData/completion/smart/VariableInitializer.kt");