From a6e153312c77cf2b64fe6afcf05dcf62e5470a5a Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Mon, 29 May 2017 15:24:23 +0300 Subject: [PATCH] Prevent early deleting of not-null assertions Before val to var conversion applied, smart-cast can cause dropping not-null assertion, which will be required when val will become var --- .../kotlin/idea/j2k/J2kPostProcessings.kt | 15 +++++--- .../nullability/LocalValReassignment.java | 35 +++++++++++++++++++ .../nullability/LocalValReassignment.kt | 32 +++++++++++++++++ ...otlinConverterForWebDemoTestGenerated.java | 6 ++++ ...otlinConverterSingleFileTestGenerated.java | 6 ++++ 5 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 j2k/testData/fileOrElement/nullability/LocalValReassignment.java create mode 100644 j2k/testData/fileOrElement/nullability/LocalValReassignment.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt index 406378918e9..a01f22deb4d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt +++ b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt @@ -47,6 +47,7 @@ import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.utils.mapToIndex import java.util.* @@ -114,11 +115,6 @@ object J2KPostProcessingRegistrar { fix.invoke() } - registerDiagnosticBasedProcessing(Errors.UNNECESSARY_NOT_NULL_ASSERTION) { element, _ -> - val exclExclExpr = element.parent as KtUnaryExpression - exclExclExpr.replace(exclExclExpr.baseExpression!!) - } - registerDiagnosticBasedProcessingFactory( Errors.VAL_REASSIGNMENT, Errors.CAPTURED_VAL_INITIALIZATION, Errors.CAPTURED_MEMBER_VAL_INITIALIZATION ) { @@ -136,6 +132,15 @@ object J2KPostProcessingRegistrar { } } + registerDiagnosticBasedProcessing(Errors.UNNECESSARY_NOT_NULL_ASSERTION) { element, _ -> + val exclExclExpr = element.parent as KtUnaryExpression + val baseExpression = exclExclExpr.baseExpression!! + val context = baseExpression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS) + if (context.diagnostics.forElement(element).any { it.factory == Errors.UNNECESSARY_NOT_NULL_ASSERTION }) { + exclExclExpr.replace(baseExpression) + } + } + processingsToPriorityMap.putAll(_processings.mapToIndex()) } diff --git a/j2k/testData/fileOrElement/nullability/LocalValReassignment.java b/j2k/testData/fileOrElement/nullability/LocalValReassignment.java new file mode 100644 index 00000000000..5968820d74e --- /dev/null +++ b/j2k/testData/fileOrElement/nullability/LocalValReassignment.java @@ -0,0 +1,35 @@ +import org.jetbrains.annotations.*; + +class A { + + /* rare nullable, handle with caution */ + public String nullableString() { + if (Math.random() > 0.999) { + return "a string"; + } + return null; + } + + public void takesNotNullString(@NotNull String s) { + System.out.println(s.substring(1)); + } + + public void aVoid() { + String aString; + if (nullableString() != null) { + aString = nullableString(); + if (aString != null) { + for (int i = 0; i < 10; i++) { + takesNotNullString(aString); // Bang-bang here + aString = nullableString(); + } + } + else { + aString = "aaa"; + } + } + else { + aString = "bbbb"; + } + } +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/nullability/LocalValReassignment.kt b/j2k/testData/fileOrElement/nullability/LocalValReassignment.kt new file mode 100644 index 00000000000..77e4065450d --- /dev/null +++ b/j2k/testData/fileOrElement/nullability/LocalValReassignment.kt @@ -0,0 +1,32 @@ +import org.jetbrains.annotations.* + +internal class A { + + /* rare nullable, handle with caution */ + fun nullableString(): String? { + return if (Math.random() > 0.999) { + "a string" + } else null + } + + fun takesNotNullString(s: String) { + println(s.substring(1)) + } + + fun aVoid() { + var aString: String? + if (nullableString() != null) { + aString = nullableString() + if (aString != null) { + for (i in 0..9) { + takesNotNullString(aString!!) // Bang-bang here + aString = nullableString() + } + } else { + aString = "aaa" + } + } else { + aString = "bbbb" + } + } +} \ No newline at end of file diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java index af7d46456d7..7be78d054dc 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -3779,6 +3779,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("LocalValReassignment.java") + public void testLocalValReassignment() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/nullability/LocalValReassignment.java"); + doTest(fileName); + } + @TestMetadata("MethodInvokedWithNullArg.java") public void testMethodInvokedWithNullArg() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/nullability/MethodInvokedWithNullArg.java"); diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index 2215c2f37ee..e1fd2c969c6 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -3779,6 +3779,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("LocalValReassignment.java") + public void testLocalValReassignment() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/nullability/LocalValReassignment.java"); + doTest(fileName); + } + @TestMetadata("MethodInvokedWithNullArg.java") public void testMethodInvokedWithNullArg() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/nullability/MethodInvokedWithNullArg.java");