"return emptyList()" & "return emptySet()" in completion

This commit is contained in:
Valentin Kipyatkov
2015-09-03 18:09:05 +03:00
parent 6dca9a4558
commit f470fec840
10 changed files with 137 additions and 19 deletions
@@ -169,6 +169,11 @@ public class KotlinBuiltIns {
public final FqNameUnsafe _float = fqNameUnsafe("Float");
public final FqNameUnsafe _double = fqNameUnsafe("Double");
public final FqNameUnsafe _collection = fqNameUnsafe("Collection");
public final FqNameUnsafe _list = fqNameUnsafe("List");
public final FqNameUnsafe _set = fqNameUnsafe("Set");
public final FqNameUnsafe _iterable = fqNameUnsafe("Iterable");
public final FqName data = fqName("data");
public final FqName deprecated = fqName("Deprecated");
public final FqName tailRecursive = fqName("tailrec");
@@ -1006,6 +1011,22 @@ public class KotlinBuiltIns {
return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.string);
}
public static boolean isCollectionOrNullableCollection(@NotNull JetType type) {
return isConstructedFromGivenClass(type, FQ_NAMES._collection);
}
public static boolean isListOrNullableList(@NotNull JetType type) {
return isConstructedFromGivenClass(type, FQ_NAMES._list);
}
public static boolean isSetOrNullableSet(@NotNull JetType type) {
return isConstructedFromGivenClass(type, FQ_NAMES._set);
}
public static boolean isIterableOrNullableIterable(@NotNull JetType type) {
return isConstructedFromGivenClass(type, FQ_NAMES._iterable);
}
public static boolean isKClass(@NotNull ClassDescriptor descriptor) {
return FQ_NAMES.kClass.equals(getFqName(descriptor));
}
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
@@ -184,7 +186,7 @@ fun shouldCompleteThisItems(prefixMatcher: PrefixMatcher): Boolean {
class ThisItemLookupObject(val receiverParameter: ReceiverParameterDescriptor, val labelName: Name?) : KeywordLookupObject()
fun ThisItemLookupObject.createLookupElement() = createKeywordWithLabelElement("this", labelName, lookupObject = this)
fun ThisItemLookupObject.createLookupElement() = createKeywordElement("this", labelName.toTail(), lookupObject = this)
.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(receiverParameter.type))
fun thisExpressionItems(bindingContext: BindingContext, position: JetExpression, prefix: String): Collection<ThisItemLookupObject> {
@@ -211,7 +213,7 @@ fun returnExpressionItems(bindingContext: BindingContext, position: JetElement):
if (parent is JetFunctionLiteral) {
val (label, call) = parent.findLabelAndCall()
if (label != null) {
result.add(createKeywordWithLabelElement("return", label, addSpace = !isUnit))
result.add(createKeywordElementWithSpace("return", tail = label.toTail(), addSpaceAfter = !isUnit))
}
// check if the current function literal is inlined and stop processing outer declarations if it's not
@@ -220,14 +222,23 @@ fun returnExpressionItems(bindingContext: BindingContext, position: JetElement):
}
else {
if (parent.hasBlockBody()) {
result.add(createKeywordWithLabelElement("return", null, addSpace = !isUnit))
result.add(createKeywordElementWithSpace("return", addSpaceAfter = !isUnit))
if (returnType != null && returnType.nullability() == TypeNullability.NULLABLE) {
result.add(createKeywordWithLabelElement("return null", null, addSpace = false))
}
if (returnType != null && KotlinBuiltIns.isBooleanOrNullableBoolean(returnType)) {
result.add(createKeywordWithLabelElement("return true", null, addSpace = false))
result.add(createKeywordWithLabelElement("return false", null, addSpace = false))
if (returnType != null) {
if (returnType.nullability() == TypeNullability.NULLABLE) {
result.add(createKeywordElement("return null"))
}
if (KotlinBuiltIns.isBooleanOrNullableBoolean(returnType)) {
result.add(createKeywordElement("return true"))
result.add(createKeywordElement("return false"))
}
else if (KotlinBuiltIns.isCollectionOrNullableCollection(returnType) || KotlinBuiltIns.isListOrNullableList(returnType) || KotlinBuiltIns.isIterableOrNullableIterable(returnType)) {
result.add(createKeywordElement("return", tail = " emptyList()"))
}
else if (KotlinBuiltIns.isSetOrNullableSet(returnType)) {
result.add(createKeywordElement("return", tail = " emptySet()"))
}
}
}
break
@@ -242,9 +253,16 @@ private fun JetDeclarationWithBody.returnType(bindingContext: BindingContext): J
return callable.getReturnType()
}
private fun createKeywordWithLabelElement(keyword: String, label: Name?, addSpace: Boolean, lookupObject: KeywordLookupObject = KeywordLookupObject()): LookupElement {
val element = createKeywordWithLabelElement(keyword, label, lookupObject)
return if (addSpace) {
private fun Name?.toTail(): String = if (this != null) "@" + render() else ""
private fun createKeywordElementWithSpace(
keyword: String,
tail: String = "",
addSpaceAfter: Boolean = false,
lookupObject: KeywordLookupObject = KeywordLookupObject()
): LookupElement {
val element = createKeywordElement(keyword, tail, lookupObject)
return if (addSpaceAfter) {
object: LookupElementDecorator<LookupElement>(element) {
override fun handleInsert(context: InsertionContext) {
WithTailInsertHandler.spaceTail().handleInsert(context, getDelegate())
@@ -256,13 +274,16 @@ private fun createKeywordWithLabelElement(keyword: String, label: Name?, addSpac
}
}
private fun createKeywordWithLabelElement(keyword: String, label: Name?, lookupObject: KeywordLookupObject = KeywordLookupObject()): LookupElementBuilder {
val labelInCode = label?.render()
var element = LookupElementBuilder.create(lookupObject, if (label == null) keyword else "$keyword@$labelInCode")
private fun createKeywordElement(
keyword: String,
tail: String = "",
lookupObject: KeywordLookupObject = KeywordLookupObject()
): LookupElementBuilder {
var element = LookupElementBuilder.create(lookupObject, keyword + tail)
element = element.withPresentableText(keyword)
element = element.withBoldness(true)
if (label != null) {
element = element.withTailText("@$labelInCode", false)
if (tail.isNotEmpty()) {
element = element.withTailText(tail, false)
}
return element
}
@@ -275,12 +296,12 @@ fun breakOrContinueExpressionItems(position: JetElement, breakOrContinue: String
when (parent) {
is JetLoopExpression -> {
if (result.isEmpty()) {
result.add(createKeywordWithLabelElement(breakOrContinue, null))
result.add(createKeywordElement(breakOrContinue))
}
val label = (parent.getParent() as? JetLabeledExpression)?.getLabelNameAsName()
if (label != null) {
result.add(createKeywordWithLabelElement(breakOrContinue, label))
result.add(createKeywordElement(breakOrContinue, tail = "@$label"))
}
}
@@ -0,0 +1,5 @@
fun foo(): Collection<String> {
ret<caret>
}
// ELEMENT: "return emptyList()"
@@ -0,0 +1,5 @@
fun foo(): Collection<String> {
return emptyList()<caret>
}
// ELEMENT: "return emptyList()"
@@ -0,0 +1,9 @@
fun foo(): Collection<String> {
ret<caret>
}
// INVOCATION_COUNT: 1
// WITH_ORDER
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return emptyList()", itemText: "return", tailText: " emptyList()", attributes: "bold" }
// NOTHING_ELSE
@@ -0,0 +1,9 @@
fun foo(): Iterable<String> {
ret<caret>
}
// INVOCATION_COUNT: 1
// WITH_ORDER
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return emptyList()", itemText: "return", tailText: " emptyList()", attributes: "bold" }
// NOTHING_ELSE
+9
View File
@@ -0,0 +1,9 @@
fun foo(): List<String> {
ret<caret>
}
// INVOCATION_COUNT: 1
// WITH_ORDER
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return emptyList()", itemText: "return", tailText: " emptyList()", attributes: "bold" }
// NOTHING_ELSE
+9
View File
@@ -0,0 +1,9 @@
fun<T> foo(): Set<T> {
ret<caret>
}
// INVOCATION_COUNT: 1
// WITH_ORDER
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return emptySet()", itemText: "return", tailText: " emptySet()", attributes: "bold" }
// NOTHING_ELSE
@@ -407,12 +407,30 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
doTest(fileName);
}
@TestMetadata("ReturnCollection.kt")
public void testReturnCollection() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnCollection.kt");
doTest(fileName);
}
@TestMetadata("ReturnIterable.kt")
public void testReturnIterable() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnIterable.kt");
doTest(fileName);
}
@TestMetadata("ReturnKeywordName.kt")
public void testReturnKeywordName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnKeywordName.kt");
doTest(fileName);
}
@TestMetadata("ReturnList.kt")
public void testReturnList() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnList.kt");
doTest(fileName);
}
@TestMetadata("ReturnNotNull.kt")
public void testReturnNotNull() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnNotNull.kt");
@@ -431,6 +449,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
doTest(fileName);
}
@TestMetadata("ReturnSet.kt")
public void testReturnSet() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnSet.kt");
doTest(fileName);
}
@TestMetadata("This.kt")
public void testThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/This.kt");
@@ -83,6 +83,12 @@ public class KeywordCompletionHandlerTestGenerated extends AbstractKeywordComple
doTest(fileName);
}
@TestMetadata("ReturnEmptyList.kt")
public void testReturnEmptyList() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/keywords/ReturnEmptyList.kt");
doTest(fileName);
}
@TestMetadata("ReturnInEmptyType.kt")
public void testReturnInEmptyType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/keywords/ReturnInEmptyType.kt");