KT-7756 Completion of "return null", "return true" and "return false"

#KT-7756 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-05-16 19:03:52 +03:00
parent 009baa11fc
commit 603f7ef3c1
11 changed files with 105 additions and 10 deletions
@@ -28,9 +28,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.findLabelAndCall
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
@@ -41,6 +39,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.types.typeUtil.equalTypesOrNulls
@@ -223,11 +222,12 @@ fun returnExpressionItems(bindingContext: BindingContext, position: JetElement):
val result = ArrayList<LookupElement>()
for (parent in position.parentsWithSelf) {
if (parent is JetDeclarationWithBody) {
val returnsUnit = returnsUnit(parent, bindingContext)
val returnType = parent.returnType(bindingContext)
val isUnit = returnType == null || KotlinBuiltIns.isUnit(returnType)
if (parent is JetFunctionLiteral) {
val (label, call) = parent.findLabelAndCall()
if (label != null) {
result.add(createKeywordWithLabelElement("return", label, addSpace = !returnsUnit))
result.add(createKeywordWithLabelElement("return", label, addSpace = !isUnit))
}
// check if the current function literal is inlined and stop processing outer declarations if it's not
@@ -236,7 +236,15 @@ fun returnExpressionItems(bindingContext: BindingContext, position: JetElement):
}
else {
if (parent.hasBlockBody()) {
result.add(createKeywordWithLabelElement("return", null, addSpace = !returnsUnit))
result.add(createKeywordWithLabelElement("return", null, addSpace = !isUnit))
if (returnType != null && returnType.nullability() == TypeNullability.NULLABLE) {
result.add(createKeywordWithLabelElement("return null", null, addSpace = false))
}
if (returnType != null && KotlinBuiltIns.isBoolean(returnType.makeNotNullable())) {
result.add(createKeywordWithLabelElement("return true", null, addSpace = false))
result.add(createKeywordWithLabelElement("return false", null, addSpace = false))
}
}
break
}
@@ -245,10 +253,9 @@ fun returnExpressionItems(bindingContext: BindingContext, position: JetElement):
return result
}
private fun returnsUnit(declaration: JetDeclarationWithBody, bindingContext: BindingContext): Boolean {
val callable = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] as? CallableDescriptor ?: return true
val returnType = callable.getReturnType() ?: return true
return KotlinBuiltIns.isUnit(returnType)
private fun JetDeclarationWithBody.returnType(bindingContext: BindingContext): JetType? {
val callable = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? CallableDescriptor ?: return null
return callable.getReturnType()
}
private fun createKeywordWithLabelElement(keyword: String, label: Name?, addSpace: Boolean): LookupElement {
@@ -0,0 +1,5 @@
fun foo(): String? {
ret<caret>
}
// ELEMENT: "return null"
@@ -0,0 +1,5 @@
fun foo(): String? {
return null<caret>
}
// ELEMENT: "return null"
@@ -0,0 +1,9 @@
fun foo(): Boolean {
ret<caret>
}
// INVOCATION_COUNT: 1
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return true", itemText: "return true", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return false", itemText: "return false", tailText: null, attributes: "bold" }
// NOTHING_ELSE: true
@@ -0,0 +1,8 @@
fun foo(): String {
ret<caret>
}
// INVOCATION_COUNT: 1
// ABSENT: "return null"
// ABSENT: "return true"
// ABSENT: "return false"
+8
View File
@@ -0,0 +1,8 @@
fun foo(): String? {
ret<caret>
}
// INVOCATION_COUNT: 1
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return null", itemText: "return null", tailText: null, attributes: "bold" }
// NOTHING_ELSE: true
@@ -0,0 +1,10 @@
fun foo(): Boolean? {
ret<caret>
}
// INVOCATION_COUNT: 1
// EXIST: { lookupString: "return", itemText: "return", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return null", itemText: "return null", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return true", itemText: "return true", tailText: null, attributes: "bold" }
// EXIST: { lookupString: "return false", itemText: "return false", tailText: null, attributes: "bold" }
// NOTHING_ELSE: true
@@ -0,0 +1,7 @@
fun foo(): Boolean {
ret<caret>
}
// ORDER: return
// ORDER: return false
// ORDER: return true
@@ -401,12 +401,36 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
doTest(fileName);
}
@TestMetadata("ReturnBoolean.kt")
public void testReturnBoolean() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnBoolean.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("ReturnNotNull.kt")
public void testReturnNotNull() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnNotNull.kt");
doTest(fileName);
}
@TestMetadata("ReturnNull.kt")
public void testReturnNull() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnNull.kt");
doTest(fileName);
}
@TestMetadata("ReturnNullableBoolean.kt")
public void testReturnNullableBoolean() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ReturnNullableBoolean.kt");
doTest(fileName);
}
@TestMetadata("This.kt")
public void testThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/This.kt");
@@ -107,6 +107,12 @@ public class KeywordCompletionHandlerTestGenerated extends AbstractKeywordComple
doTest(fileName);
}
@TestMetadata("ReturnNull.kt")
public void testReturnNull() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/keywords/ReturnNull.kt");
doTest(fileName);
}
@TestMetadata("SpaceAfterImport.kt")
public void testSpaceAfterImport() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/keywords/SpaceAfterImport.kt");
@@ -124,4 +124,10 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/PropertiesBeforeKeywords.kt");
doTest(fileName);
}
@TestMetadata("ReturnBoolean.kt")
public void testReturnBoolean() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/ReturnBoolean.kt");
doTest(fileName);
}
}