Create From Usage: Fix rendering of nullable types

This commit is contained in:
Alexey Sedunov
2014-10-07 18:28:40 +04:00
parent ff082be524
commit 2b43aad4f9
14 changed files with 144 additions and 5 deletions
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
import org.jetbrains.jet.lang.resolve.name.FqName
import kotlin.properties.Delegates
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
import org.jetbrains.jet.plugin.util.makeNotNullable
private fun JetType.contains(inner: JetType): Boolean {
return JetTypeChecker.DEFAULT.equalTypes(this, inner) || getArguments().any { inner in it.getType() }
@@ -51,7 +52,8 @@ private fun JetType.render(typeParameterNameMap: Map<TypeParameterDescriptor, St
val arguments = getArguments().map { it.getType().render(typeParameterNameMap, fq) }
val typeString = getConstructor().getDeclarationDescriptor()!!.render(typeParameterNameMap, fq)
val typeArgumentString = if (arguments.notEmpty) arguments.joinToString(", ", "<", ">") else ""
return "$typeString$typeArgumentString"
val nullifier = if (isNullable()) "?" else ""
return "$typeString$typeArgumentString$nullifier"
}
private fun JetType.renderShort(typeParameterNameMap: Map<TypeParameterDescriptor, String>) = render(typeParameterNameMap, false)
@@ -192,12 +194,15 @@ private fun JetNamedDeclaration.guessType(context: BindingContext): Array<JetTyp
private class JetTypeSubstitution(public val forType: JetType, public val byType: JetType)
private fun JetType.substitute(substitution: JetTypeSubstitution, variance: Variance): JetType {
val nullable = isNullable()
val currentType = makeNotNullable()
if (when (variance) {
Variance.INVARIANT -> JetTypeChecker.DEFAULT.equalTypes(this, substitution.forType)
Variance.IN_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(this, substitution.forType)
Variance.OUT_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(substitution.forType, this)
Variance.INVARIANT -> JetTypeChecker.DEFAULT.equalTypes(currentType, substitution.forType)
Variance.IN_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(currentType, substitution.forType)
Variance.OUT_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(substitution.forType, currentType)
}) {
return substitution.byType
return TypeUtils.makeNullableAsSpecified(substitution.byType, nullable)
}
else {
val newArguments = getArguments().zip(getConstructor().getParameters()).map { pair ->
@@ -0,0 +1,11 @@
// "Create function 'foo' from usage" "true"
class A<T>(val n: T) {
fun foo(arg: T?): A<Int> {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
fun test() {
val a: A<Int> = A(true).foo(false as Boolean?)
}
@@ -0,0 +1,11 @@
// "Create function 'foo' from usage" "true"
class A<T>(val n: T) {
fun foo(arg: T): A<T>? {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
fun test() {
val a: A<Int>? = A(1).foo(2)
}
@@ -0,0 +1,11 @@
// "Create function 'foo' from usage" "true"
class A<T>(val n: T) {
fun foo(arg: T): A<String> {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
fun test() {
val a: A<String> = A(1 as Int?).foo(2)
}
@@ -0,0 +1,7 @@
// "Create function 'foo' from usage" "true"
class A<T>(val n: T)
fun test() {
val a: A<Int> = A(true).<caret>foo(false as Boolean?)
}
@@ -0,0 +1,7 @@
// "Create function 'foo' from usage" "true"
class A<T>(val n: T)
fun test() {
val a: A<Int>? = A(1).<caret>foo(2)
}
@@ -0,0 +1,7 @@
// "Create function 'foo' from usage" "true"
class A<T>(val n: T)
fun test() {
val a: A<String> = A(1 as Int?).<caret>foo(2)
}
@@ -0,0 +1,8 @@
// "Create local variable 'foo'" "true"
// ERROR: Variable 'foo' must be initialized
fun test(): Int? {
val foo: Int?
return foo
}
@@ -0,0 +1,6 @@
// "Create local variable 'foo'" "true"
// ERROR: Variable 'foo' must be initialized
fun test(): Int? {
return <caret>foo
}
@@ -0,0 +1,6 @@
// "Create parameter 'foo'" "true"
fun test(n: Int,
foo: Int?) {
val t: Int? = foo
}
@@ -0,0 +1,5 @@
// "Create parameter 'foo'" "true"
fun test(n: Int) {
val t: Int? = <caret>foo
}
@@ -0,0 +1,11 @@
// "Create property 'foo' from usage" "true"
// ERROR: Property must be initialized or be abstract
class A<T>(val n: T) {
val foo: A<T>?
}
fun test() {
val a: A<Int>? = A(1).foo
}
@@ -0,0 +1,8 @@
// "Create property 'foo' from usage" "true"
// ERROR: Property must be initialized or be abstract
class A<T>(val n: T)
fun test() {
val a: A<Int>? = A(1).<caret>foo
}
@@ -814,6 +814,24 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("beforeFunWithNullableParamType.kt")
public void testFunWithNullableParamType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableParamType.kt");
doTest(fileName);
}
@TestMetadata("beforeFunWithNullableType.kt")
public void testFunWithNullableType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableType.kt");
doTest(fileName);
}
@TestMetadata("beforeFunWithNullableTypeParameter.kt")
public void testFunWithNullableTypeParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableTypeParameter.kt");
doTest(fileName);
}
@TestMetadata("beforeFunWithPackageName.kt")
public void testFunWithPackageName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithPackageName.kt");
@@ -1287,6 +1305,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("beforeNullableType.kt")
public void testNullableType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeNullableType.kt");
doTest(fileName);
}
@TestMetadata("beforeOnTopLevel.kt")
public void testOnTopLevel() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeOnTopLevel.kt");
@@ -1513,6 +1537,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("beforeNullableType.kt")
public void testNullableType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeNullableType.kt");
doTest(fileName);
}
@TestMetadata("beforeQualifiedInFun.kt")
public void testQualifiedInFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeQualifiedInFun.kt");
@@ -1655,6 +1685,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("beforeValWithNullableType.kt")
public void testValWithNullableType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeValWithNullableType.kt");
doTest(fileName);
}
@TestMetadata("beforeVarOnLibType.kt")
public void testVarOnLibType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeVarOnLibType.kt");