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");