Smart completion: this expressions added

This commit is contained in:
Valentin Kipyatkov
2013-11-27 20:15:28 +04:00
parent 29f7318f4f
commit 47d3e2e1bb
11 changed files with 191 additions and 5 deletions
@@ -6,6 +6,26 @@
<item name='com.intellij.codeInsight.lookup.Lookup com.intellij.openapi.editor.Editor getEditor()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder create(com.intellij.psi.PsiNamedElement)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder create(java.lang.Object, java.lang.String)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder create(java.lang.String)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder createWithIcon(com.intellij.psi.PsiNamedElement)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder setTypeText(java.lang.String, boolean)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder withInsertHandler(com.intellij.codeInsight.completion.InsertHandler&lt;com.intellij.codeInsight.lookup.LookupElement&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
@@ -18,6 +38,14 @@
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder withTailText(java.lang.String)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder withTypeText(java.lang.String)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder withTypeText(java.lang.String, boolean)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.codeInsight.lookup.MutableLookupElement com.intellij.codeInsight.lookup.MutableLookupElement&lt;T&gt; setInsertHandler(com.intellij.codeInsight.completion.InsertHandler&lt;? extends com.intellij.codeInsight.lookup.LookupElement&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
@@ -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<LookupElement> {
val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, context)
if (scope == null) return listOf()
val receivers: List<ReceiverParameterDescriptor> = scope.getImplicitReceiversHierarchy()
val result = ArrayList<LookupElement>()
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<VariableDescriptor, Collection<JetType>> = Collections.emptyMap(),
val notNullVariables: Set<VariableDescriptor> = Collections.emptySet()
@@ -195,3 +238,14 @@ private fun <T> MutableCollection<T>.addAll(iterator: Iterator<T>) {
add(item)
}
}
fun<T> accept1(handler: String.(t: T) -> Unit){}
fun accept2(handler: Int.() -> Unit){}
fun foo(){
accept1<String>({
accept2({
val s: String = this@accept1
})
})
}
@@ -0,0 +1,7 @@
class Foo{
fun String.foo(){
val foo : Foo = <caret>
}
}
// EXIST: { lookupString:"this@Foo", typeText:"Foo" }
@@ -0,0 +1,15 @@
open class Foo
fun foo(f: Foo){}
fun bar() {
foo(object: Foo() {
inner class Inner {
fun f() {
val x: Foo = <caret>
}
}
})
}
// EXIST: this@foo
@@ -0,0 +1,9 @@
class Foo{
fun String.foo(){
fun Foo.bar(){
val s: String = <caret>
}
}
}
// EXIST: { lookupString:"this@foo", typeText:"jet.String" }
@@ -0,0 +1,12 @@
fun accept1(handler: String.() -> Unit){}
fun accept2(handler: Int.() -> Unit){}
fun foo(){
accept1({
accept2({
val s: String = <caret>
})
})
}
// EXIST: this@accept1
@@ -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 = <caret>
})
})
}
// EXIST: this@accept1
@@ -0,0 +1,12 @@
fun<T> accept1(handler: String.(t: T) -> Unit){}
fun accept2(handler: Int.() -> Unit){}
fun foo(){
accept1<String>({
accept2({
val s: String = <caret>
})
})
}
// EXIST: this@accept1
+5
View File
@@ -0,0 +1,5 @@
fun String.foo(){
val s : String = <caret>
}
// EXIST: { lookupString:"this", typeText:"jet.String" }
@@ -1,5 +0,0 @@
fun String.foo(){
val s : String = <caret>
}
// EXIST: this
@@ -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");