From 2b43aad4f953c526e8864f0c62db2751d5d1cf26 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 7 Oct 2014 18:28:40 +0400 Subject: [PATCH] Create From Usage: Fix rendering of nullable types --- .../callableBuilder/typeUtils.kt | 15 +++++--- .../call/afterFunWithNullableParamType.kt | 11 ++++++ .../call/afterFunWithNullableType.kt | 11 ++++++ .../call/afterFunWithNullableTypeParameter.kt | 11 ++++++ .../call/beforeFunWithNullableParamType.kt | 7 ++++ .../call/beforeFunWithNullableType.kt | 7 ++++ .../beforeFunWithNullableTypeParameter.kt | 7 ++++ .../localVariable/afterNullableType.kt | 8 +++++ .../localVariable/beforeNullableType.kt | 6 ++++ .../parameter/afterNullableType.kt | 6 ++++ .../parameter/beforeNullableType.kt | 5 +++ .../property/afterValWithNullableType.kt | 11 ++++++ .../property/beforeValWithNullableType.kt | 8 +++++ .../quickfix/QuickFixTestGenerated.java | 36 +++++++++++++++++++ 14 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableParamType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableTypeParameter.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableParamType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableTypeParameter.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterNullableType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeNullableType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/parameter/afterNullableType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeNullableType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/property/afterValWithNullableType.kt create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/property/beforeValWithNullableType.kt diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt index 6748c72252d..6b5b7cef156 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/createFromUsage/callableBuilder/typeUtils.kt @@ -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") else "" - return "$typeString$typeArgumentString" + val nullifier = if (isNullable()) "?" else "" + return "$typeString$typeArgumentString$nullifier" } private fun JetType.renderShort(typeParameterNameMap: Map) = render(typeParameterNameMap, false) @@ -192,12 +194,15 @@ private fun JetNamedDeclaration.guessType(context: BindingContext): Array 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 -> diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableParamType.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableParamType.kt new file mode 100644 index 00000000000..468f06fd91a --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableParamType.kt @@ -0,0 +1,11 @@ +// "Create function 'foo' from usage" "true" + +class A(val n: T) { + fun foo(arg: T?): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test() { + val a: A = A(true).foo(false as Boolean?) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableType.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableType.kt new file mode 100644 index 00000000000..c4585149485 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableType.kt @@ -0,0 +1,11 @@ +// "Create function 'foo' from usage" "true" + +class A(val n: T) { + fun foo(arg: T): A? { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test() { + val a: A? = A(1).foo(2) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableTypeParameter.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableTypeParameter.kt new file mode 100644 index 00000000000..3a02eea1f91 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunWithNullableTypeParameter.kt @@ -0,0 +1,11 @@ +// "Create function 'foo' from usage" "true" + +class A(val n: T) { + fun foo(arg: T): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} + +fun test() { + val a: A = A(1 as Int?).foo(2) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableParamType.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableParamType.kt new file mode 100644 index 00000000000..68b02d49f8d --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableParamType.kt @@ -0,0 +1,7 @@ +// "Create function 'foo' from usage" "true" + +class A(val n: T) + +fun test() { + val a: A = A(true).foo(false as Boolean?) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableType.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableType.kt new file mode 100644 index 00000000000..31b3cbafaca --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableType.kt @@ -0,0 +1,7 @@ +// "Create function 'foo' from usage" "true" + +class A(val n: T) + +fun test() { + val a: A? = A(1).foo(2) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableTypeParameter.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableTypeParameter.kt new file mode 100644 index 00000000000..6e43212f602 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithNullableTypeParameter.kt @@ -0,0 +1,7 @@ +// "Create function 'foo' from usage" "true" + +class A(val n: T) + +fun test() { + val a: A = A(1 as Int?).foo(2) +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterNullableType.kt b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterNullableType.kt new file mode 100644 index 00000000000..309dcdd7288 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/afterNullableType.kt @@ -0,0 +1,8 @@ +// "Create local variable 'foo'" "true" +// ERROR: Variable 'foo' must be initialized + +fun test(): Int? { + val foo: Int? + + return foo +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeNullableType.kt b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeNullableType.kt new file mode 100644 index 00000000000..6b3d56c50cd --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/localVariable/beforeNullableType.kt @@ -0,0 +1,6 @@ +// "Create local variable 'foo'" "true" +// ERROR: Variable 'foo' must be initialized + +fun test(): Int? { + return foo +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/afterNullableType.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/afterNullableType.kt new file mode 100644 index 00000000000..617b1e99cb0 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/afterNullableType.kt @@ -0,0 +1,6 @@ +// "Create parameter 'foo'" "true" + +fun test(n: Int, + foo: Int?) { + val t: Int? = foo +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeNullableType.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeNullableType.kt new file mode 100644 index 00000000000..45c9ed16fc4 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/beforeNullableType.kt @@ -0,0 +1,5 @@ +// "Create parameter 'foo'" "true" + +fun test(n: Int) { + val t: Int? = foo +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterValWithNullableType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterValWithNullableType.kt new file mode 100644 index 00000000000..ad0327cb268 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterValWithNullableType.kt @@ -0,0 +1,11 @@ +// "Create property 'foo' from usage" "true" +// ERROR: Property must be initialized or be abstract + +class A(val n: T) { + val foo: A? + +} + +fun test() { + val a: A? = A(1).foo +} diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/beforeValWithNullableType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/beforeValWithNullableType.kt new file mode 100644 index 00000000000..dc92076e967 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/beforeValWithNullableType.kt @@ -0,0 +1,8 @@ +// "Create property 'foo' from usage" "true" +// ERROR: Property must be initialized or be abstract + +class A(val n: T) + +fun test() { + val a: A? = A(1).foo +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index ed2a64d6d46..400c28644d4 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -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");