From e6872c52a367ff8fd53953a28d36c45126378303 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 20 Jul 2017 14:51:44 +0300 Subject: [PATCH] More accurate deparenthesize (keeping annotations) in some IDE actions So #KT-19004 Fixed --- .../org/jetbrains/kotlin/psi/KtPsiUtil.java | 25 ++++++++++++++++--- .../SimplifyBooleanWithConstantsIntention.kt | 2 +- .../branchedTransformations/IfThenUtils.kt | 4 +-- .../intentions/DoubleBangToIfThenIntention.kt | 2 +- .../intentions/IfToWhenIntention.kt | 2 +- .../cascadeIf/withAnnotation.kt | 13 ++++++++++ .../cascadeIf/withAnnotation.kt.after | 9 +++++++ .../doubleBangToIfThen/withAnnotation.kt | 6 +++++ .../withAnnotation.kt.after | 6 +++++ .../ifWhen/ifToWhen/withAnnotation.kt | 15 +++++++++++ .../ifWhen/ifToWhen/withAnnotation.kt.after | 13 ++++++++++ .../withAnnotation.kt | 10 ++++++++ .../withAnnotation.kt.after | 10 ++++++++ .../LocalInspectionTestGenerated.java | 6 +++++ .../intentions/IntentionTestGenerated.java | 18 +++++++++++++ 15 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt create mode 100644 idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt.after create mode 100644 idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt create mode 100644 idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt.after create mode 100644 idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt create mode 100644 idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java index 92e084ccf35..4fdd15a7109 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java @@ -68,14 +68,24 @@ public class KtPsiUtil { @NotNull public static KtExpression safeDeparenthesize(@NotNull KtExpression expression) { - KtExpression deparenthesized = deparenthesize(expression); + return safeDeparenthesize(expression, false); + } + + @NotNull + public static KtExpression safeDeparenthesize(@NotNull KtExpression expression, boolean keepAnnotations) { + KtExpression deparenthesized = deparenthesize(expression, keepAnnotations); return deparenthesized != null ? deparenthesized : expression; } @Nullable - public static KtExpression deparenthesize(@Nullable KtExpression expression ) { + public static KtExpression deparenthesize(@Nullable KtExpression expression) { + return deparenthesize(expression, false); + } + + @Nullable + public static KtExpression deparenthesize(@Nullable KtExpression expression, boolean keepAnnotations) { while (true) { - KtExpression baseExpression = deparenthesizeOnce(expression); + KtExpression baseExpression = deparenthesizeOnce(expression, keepAnnotations); if (baseExpression == expression) return baseExpression; expression = baseExpression; @@ -86,7 +96,14 @@ public class KtPsiUtil { public static KtExpression deparenthesizeOnce( @Nullable KtExpression expression ) { - if (expression instanceof KtAnnotatedExpression) { + return deparenthesizeOnce(expression, false); + } + + @Nullable + public static KtExpression deparenthesizeOnce( + @Nullable KtExpression expression, boolean keepAnnotations + ) { + if (expression instanceof KtAnnotatedExpression && !keepAnnotations) { return ((KtAnnotatedExpression) expression).getBaseExpression(); } else if (expression instanceof KtLabeledExpression) { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt index 5b83f92b08f..d6094aff21f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt @@ -58,7 +58,7 @@ class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentInte override fun applyTo(element: KtBinaryExpression, editor: Editor?) { val topBinary = PsiTreeUtil.getTopmostParentOfType(element, KtBinaryExpression::class.java) ?: element val simplified = toSimplifiedExpression(topBinary) - topBinary.replace(KtPsiUtil.safeDeparenthesize(simplified)) + topBinary.replace(KtPsiUtil.safeDeparenthesize(simplified, true)) } private fun toSimplifiedExpression(expression: KtExpression): KtExpression { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt index ff1e7fbacf0..2987bdef166 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt @@ -58,10 +58,10 @@ fun KtBinaryExpression.expressionComparedToNull(): KtExpression? { } fun KtExpression.unwrapBlockOrParenthesis(): KtExpression { - val innerExpression = KtPsiUtil.safeDeparenthesize(this) + val innerExpression = KtPsiUtil.safeDeparenthesize(this, true) if (innerExpression is KtBlockExpression) { val statement = innerExpression.statements.singleOrNull() ?: return this - return KtPsiUtil.safeDeparenthesize(statement) + return KtPsiUtil.safeDeparenthesize(statement, true) } return innerExpression } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/DoubleBangToIfThenIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/DoubleBangToIfThenIntention.kt index ed5748d66c0..8469f86befd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/DoubleBangToIfThenIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/DoubleBangToIfThenIntention.kt @@ -50,7 +50,7 @@ class DoubleBangToIfThenIntention : SelfTargetingRangeIntention(KtIfExpres } } - add(KtPsiUtil.safeDeparenthesize(expression)) + add(KtPsiUtil.safeDeparenthesize(expression, true)) return this } } diff --git a/idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt b/idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt new file mode 100644 index 00000000000..7aa64dd6af0 --- /dev/null +++ b/idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt @@ -0,0 +1,13 @@ +// WITH_RUNTIME +fun foo(a: Any) { + if (a == "") { + println(a) + } + else if (a is String) { + println(a) + } + else if (a is List<*>) { + @Suppress("UNCHECKED_CAST") + println(a as List) + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt.after b/idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt.after new file mode 100644 index 00000000000..f74ecfacd6d --- /dev/null +++ b/idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt.after @@ -0,0 +1,9 @@ +// WITH_RUNTIME +fun foo(a: Any) { + when (a) { + "" -> println(a) + is String -> println(a) + is List<*> -> @Suppress("UNCHECKED_CAST") + println(a as List) + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt b/idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt new file mode 100644 index 00000000000..26168747d35 --- /dev/null +++ b/idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt @@ -0,0 +1,6 @@ +@Target(AnnotationTarget.EXPRESSION) +annotation class Ann + +fun foo(arg: String?) { + (@Ann arg)!! +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt.after b/idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt.after new file mode 100644 index 00000000000..e1c5d6c50be --- /dev/null +++ b/idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt.after @@ -0,0 +1,6 @@ +@Target(AnnotationTarget.EXPRESSION) +annotation class Ann + +fun foo(arg: String?) { + if (@Ann arg == null) throw NullPointerException("Expression '@Ann arg' must not be null") +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt b/idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt new file mode 100644 index 00000000000..ec94dd7274d --- /dev/null +++ b/idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt @@ -0,0 +1,15 @@ +var b = true + +@Target(AnnotationTarget.EXPRESSION) +annotation class Ann + +fun println(s: String) {} + +fun foo() { + if (@Ann b) { + println("!") + } + else { + println("") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt.after b/idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt.after new file mode 100644 index 00000000000..ee2765542a7 --- /dev/null +++ b/idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt.after @@ -0,0 +1,13 @@ +var b = true + +@Target(AnnotationTarget.EXPRESSION) +annotation class Ann + +fun println(s: String) {} + +fun foo() { + when { + @Ann b -> println("!") + else -> println("") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt b/idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt new file mode 100644 index 00000000000..670b2a1dd83 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt @@ -0,0 +1,10 @@ +var b = true + +@Target(AnnotationTarget.EXPRESSION) +annotation class Ann + +fun foo() { + if (@Ann b == true) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt.after new file mode 100644 index 00000000000..5690ab098df --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt.after @@ -0,0 +1,10 @@ +var b = true + +@Target(AnnotationTarget.EXPRESSION) +annotation class Ann + +fun foo() { + if (@Ann b) { + + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 8e51c12381e..d1402003074 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -113,6 +113,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { doTest(fileName); } + @TestMetadata("withAnnotation.kt") + public void testWithAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/withAnnotation.kt"); + doTest(fileName); + } + @TestMetadata("withBreak.kt") public void testWithBreak() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/withBreak.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 4ff702312ea..258da7a339b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -945,6 +945,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/doubleBangToIfThen/usedInAssignment.kt"); doTest(fileName); } + + @TestMetadata("withAnnotation.kt") + public void testWithAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/doubleBangToIfThen/withAnnotation.kt"); + doTest(fileName); + } } @TestMetadata("idea/testData/intentions/branched/elvisToIfThen") @@ -1982,6 +1988,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifWhen/ifToWhen/whenWithMultipleConditionTypes.kt"); doTest(fileName); } + + @TestMetadata("withAnnotation.kt") + public void testWithAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifWhen/ifToWhen/withAnnotation.kt"); + doTest(fileName); + } } @TestMetadata("idea/testData/intentions/branched/ifWhen/whenToIf") @@ -14545,6 +14557,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/simpleWithParentheses2.kt"); doTest(fileName); } + + @TestMetadata("withAnnotation.kt") + public void testWithAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/withAnnotation.kt"); + doTest(fileName); + } } @TestMetadata("idea/testData/intentions/simplifyNegatedBinaryExpression")