Fixed keywords after 'this@' completion + fixed implementation of JetExpressionWithLabel.getLabelName()

This commit is contained in:
Valentin Kipyatkov
2015-05-20 11:46:16 +03:00
parent 2a5ca095ee
commit a6f76bbf76
13 changed files with 56 additions and 28 deletions
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import org.jetbrains.kotlin.JetNodeTypes import org.jetbrains.kotlin.JetNodeTypes
import org.jetbrains.kotlin.name.Name
open public class JetExpressionWithLabel(node: ASTNode) : JetExpressionImpl(node) { open public class JetExpressionWithLabel(node: ASTNode) : JetExpressionImpl(node) {
@@ -25,7 +26,8 @@ open public class JetExpressionWithLabel(node: ASTNode) : JetExpressionImpl(node
findChildByType<JetContainerNode>(JetNodeTypes.LABEL_QUALIFIER)?. findChildByType<JetContainerNode>(JetNodeTypes.LABEL_QUALIFIER)?.
findChildByType(JetNodeTypes.LABEL) as? JetSimpleNameExpression findChildByType(JetNodeTypes.LABEL) as? JetSimpleNameExpression
public fun getLabelName(): String? = getTargetLabel()?.getIdentifier()?.getText() public fun getLabelName(): String? = getTargetLabel()?.getReferencedName()
public fun getLabelNameAsName(): Name? = getTargetLabel()?.getReferencedNameAsName()
override fun <R, D> accept(visitor: JetVisitor<R, D>, data: D) = visitor.visitExpressionWithLabel(this, data) override fun <R, D> accept(visitor: JetVisitor<R, D>, data: D) = visitor.visitExpressionWithLabel(this, data)
} }
@@ -429,10 +429,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
ExpressionTypingContext context, ExpressionTypingContext context,
boolean onlyClassReceivers boolean onlyClassReceivers
) { ) {
String labelName = expression.getLabelName(); Name labelName = expression.getLabelNameAsName();
if (labelName != null) { if (labelName != null) {
LabelResolver.LabeledReceiverResolutionResult resolutionResult = LabelResolver.LabeledReceiverResolutionResult resolutionResult =
LabelResolver.INSTANCE.resolveThisOrSuperLabel(expression, context, Name.identifier(labelName)); LabelResolver.INSTANCE.resolveThisOrSuperLabel(expression, context, labelName);
if (resolutionResult.success()) { if (resolutionResult.success()) {
ReceiverParameterDescriptor receiverParameterDescriptor = resolutionResult.getReceiverParameterDescriptor(); ReceiverParameterDescriptor receiverParameterDescriptor = resolutionResult.getReceiverParameterDescriptor();
recordThisOrSuperCallInTraceAndCallExtension(context, receiverParameterDescriptor, expression); recordThisOrSuperCallInTraceAndCallExtension(context, receiverParameterDescriptor, expression);
@@ -57,9 +57,9 @@ public class LabelResolver {
@Nullable @Nullable
private Name getLabelNameIfAny(@NotNull PsiElement element) { private Name getLabelNameIfAny(@NotNull PsiElement element) {
if (element instanceof JetLabeledExpression) { if (element instanceof JetLabeledExpression) {
String labelName = ((JetLabeledExpression) element).getLabelName(); Name labelName = ((JetLabeledExpression) element).getLabelNameAsName();
if (labelName != null) { if (labelName != null) {
return Name.identifier(labelName); return labelName;
} }
} }
if (element instanceof JetFunctionLiteralExpression) { if (element instanceof JetFunctionLiteralExpression) {
@@ -126,10 +126,9 @@ public class LabelResolver {
@NotNull ResolutionContext context @NotNull ResolutionContext context
) { ) {
JetSimpleNameExpression labelElement = expression.getTargetLabel(); JetSimpleNameExpression labelElement = expression.getTargetLabel();
String name = expression.getLabelName(); Name labelName = expression.getLabelNameAsName();
if (labelElement == null || name == null) return null; if (labelElement == null || labelName == null) return null;
Name labelName = Name.identifier(name);
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName); Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
int size = declarationsByLabel.size(); int size = declarationsByLabel.size();
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.name package org.jetbrains.kotlin.name
import org.jetbrains.kotlin.renderer.DescriptorRenderer
public fun FqName.isSubpackageOf(packageName: FqName): Boolean { public fun FqName.isSubpackageOf(packageName: FqName): Boolean {
return when { return when {
this == packageName -> true this == packageName -> true
@@ -76,3 +78,5 @@ public fun isValidJavaFqName(qualifiedName: String?): Boolean {
return state != State.AFTER_DOT return state != State.AFTER_DOT
} }
public fun Name.renderName(): String = DescriptorRenderer.COMPACT.renderName(this)
@@ -16,9 +16,10 @@
package org.jetbrains.kotlin.idea.util package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
public fun JetFunctionLiteral.findLabelAndCall(): Pair<String?, JetCallExpression?> { public fun JetFunctionLiteral.findLabelAndCall(): Pair<Name?, JetCallExpression?> {
val literalParent = (this.getParent() as JetFunctionLiteralExpression).getParent() val literalParent = (this.getParent() as JetFunctionLiteralExpression).getParent()
fun JetValueArgument.callExpression(): JetCallExpression? { fun JetValueArgument.callExpression(): JetCallExpression? {
@@ -29,12 +30,12 @@ public fun JetFunctionLiteral.findLabelAndCall(): Pair<String?, JetCallExpressio
when (literalParent) { when (literalParent) {
is JetLabeledExpression -> { is JetLabeledExpression -> {
val callExpression = (literalParent.getParent() as? JetValueArgument)?.callExpression() val callExpression = (literalParent.getParent() as? JetValueArgument)?.callExpression()
return Pair(literalParent.getLabelName(), callExpression) return Pair(literalParent.getLabelNameAsName(), callExpression)
} }
is JetValueArgument -> { is JetValueArgument -> {
val callExpression = literalParent.callExpression() val callExpression = literalParent.callExpression()
val label = (callExpression?.getCalleeExpression() as? JetSimpleNameExpression)?.getReferencedName() val label = (callExpression?.getCalleeExpression() as? JetSimpleNameExpression)?.getReferencedNameAsName()
return Pair(label, callExpression) return Pair(label, callExpression)
} }
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.renderName
import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetFunctionLiteral import org.jetbrains.kotlin.psi.JetFunctionLiteral
import org.jetbrains.kotlin.psi.JetPsiFactory import org.jetbrains.kotlin.psi.JetPsiFactory
@@ -58,7 +60,7 @@ public fun JetScope.getImplicitReceiversWithInstanceToExpression(): Map<Receiver
for ((index, receiver) in receivers.withIndex()) { for ((index, receiver) in receivers.withIndex()) {
val owner = receiver.getContainingDeclaration() val owner = receiver.getContainingDeclaration()
val (expressionText, isImmediateThis) = if (owner in outerDeclarationsWithInstance) { val (expressionText, isImmediateThis) = if (owner in outerDeclarationsWithInstance) {
val thisWithLabel = thisQualifierName(receiver)?.let { "this@$it" } val thisWithLabel = thisQualifierName(receiver)?.let { "this@${it.renderName()}" }
if (index == 0) if (index == 0)
(thisWithLabel ?: "this") to true (thisWithLabel ?: "this") to true
else else
@@ -83,12 +85,10 @@ public fun JetScope.getImplicitReceiversWithInstanceToExpression(): Map<Receiver
return result return result
} }
private fun thisQualifierName(receiver: ReceiverParameterDescriptor): String? { private fun thisQualifierName(receiver: ReceiverParameterDescriptor): Name? {
val descriptor = receiver.getContainingDeclaration() val descriptor = receiver.getContainingDeclaration()
val name = descriptor.getName() val name = descriptor.getName()
if (!name.isSpecial()) { if (!name.isSpecial()) return name
return name.asString()
}
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? JetFunctionLiteral val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? JetFunctionLiteral
return functionLiteral?.findLabelAndCall()?.first return functionLiteral?.findLabelAndCall()?.first
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.findLabelAndCall import org.jetbrains.kotlin.idea.util.findLabelAndCall
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.renderName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
@@ -209,7 +210,7 @@ fun thisExpressionItems(bindingContext: BindingContext, position: JetExpression,
val thisType = receiver.getType() val thisType = receiver.getType()
val fuzzyType = FuzzyType(thisType, listOf()) val fuzzyType = FuzzyType(thisType, listOf())
fun createLookupElement() = createKeywordWithLabelElement("this", expression.getLabelName()) fun createLookupElement() = createKeywordWithLabelElement("this", expression.getLabelNameAsName())
.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(thisType)) .withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(thisType))
result.add(ThisItemInfo(::createLookupElement, fuzzyType)) result.add(ThisItemInfo(::createLookupElement, fuzzyType))
@@ -249,7 +250,7 @@ private fun returnsUnit(declaration: JetDeclarationWithBody, bindingContext: Bin
return KotlinBuiltIns.isUnit(returnType) return KotlinBuiltIns.isUnit(returnType)
} }
private fun createKeywordWithLabelElement(keyword: String, label: String?, addSpace: Boolean): LookupElement { private fun createKeywordWithLabelElement(keyword: String, label: Name?, addSpace: Boolean): LookupElement {
val element = createKeywordWithLabelElement(keyword, label) val element = createKeywordWithLabelElement(keyword, label)
return if (addSpace) { return if (addSpace) {
object: LookupElementDecorator<LookupElement>(element) { object: LookupElementDecorator<LookupElement>(element) {
@@ -263,12 +264,13 @@ private fun createKeywordWithLabelElement(keyword: String, label: String?, addSp
} }
} }
private fun createKeywordWithLabelElement(keyword: String, label: String?): LookupElementBuilder { private fun createKeywordWithLabelElement(keyword: String, label: Name?): LookupElementBuilder {
var element = LookupElementBuilder.create(KeywordLookupObject, if (label == null) keyword else "$keyword@$label") val labelInCode = label?.renderName()
var element = LookupElementBuilder.create(KeywordLookupObject, if (label == null) keyword else "$keyword@$labelInCode")
element = element.withPresentableText(keyword) element = element.withPresentableText(keyword)
element = element.withBoldness(true) element = element.withBoldness(true)
if (label != null) { if (label != null) {
element = element.withTailText("@$label", false) element = element.withTailText("@$labelInCode", false)
} }
return element return element
} }
@@ -284,7 +286,7 @@ fun breakOrContinueExpressionItems(position: JetElement, breakOrContinue: String
result.add(createKeywordWithLabelElement(breakOrContinue, null)) result.add(createKeywordWithLabelElement(breakOrContinue, null))
} }
val label = (parent.getParent() as? JetLabeledExpression)?.getLabelName() val label = (parent.getParent() as? JetLabeledExpression)?.getLabelNameAsName()
if (label != null) { if (label != null) {
result.add(createKeywordWithLabelElement(breakOrContinue, label)) result.add(createKeywordWithLabelElement(breakOrContinue, label))
} }
@@ -4,5 +4,5 @@ class `this` {
} }
} }
// ELEMENT: "this@this" // ELEMENT: "this@`this`"
@@ -1,8 +1,8 @@
class `this` { class `this` {
fun String.foo(){ fun String.foo(){
val foo: `this` = this@this<caret> val foo: `this` = this@`this`<caret>
} }
} }
// ELEMENT: "this@this" // ELEMENT: "this@`this`"
@@ -9,4 +9,4 @@ fun foo(){
}) })
} }
// ELEMENT: this@fun // ELEMENT: this@`fun`
@@ -4,9 +4,9 @@ fun bar(handler: Int.() -> Unit){}
fun foo(){ fun foo(){
`fun`({ `fun`({
bar({ bar({
val s: String = this@fun<caret> val s: String = this@`fun`<caret>
}) })
}) })
} }
// ELEMENT: this@fun // ELEMENT: this@`fun`
@@ -0,0 +1,14 @@
fun foo() {
`fun` {
`val`({ ret<caret> })
}
}
inline fun `fun`(handler: () -> Unit){}
inline fun `val`(handler: () -> Unit){}
// INVOCATION_COUNT: 1
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return@`fun`", itemText: "return", tailText: "@`fun`", attributes: "bold" }
// EXIST: { lookupString: "return@`val`", itemText: "return", tailText: "@`val`", attributes: "bold" }
// NOTHING_ELSE: true
@@ -401,6 +401,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("ReturnKeywordName.kt")
public void testReturnKeywordName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnKeywordName.kt");
doTest(fileName);
}
@TestMetadata("This.kt") @TestMetadata("This.kt")
public void testThis() throws Exception { public void testThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/This.kt"); String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/This.kt");