More accurate deparenthesize (keeping annotations) in some IDE actions

So #KT-19004 Fixed
This commit is contained in:
Mikhail Glukhikh
2017-07-20 14:51:44 +03:00
parent 7fb78a0372
commit e6872c52a3
15 changed files with 132 additions and 9 deletions
@@ -68,14 +68,24 @@ public class KtPsiUtil {
@NotNull @NotNull
public static KtExpression safeDeparenthesize(@NotNull KtExpression expression) { 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; return deparenthesized != null ? deparenthesized : expression;
} }
@Nullable @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) { while (true) {
KtExpression baseExpression = deparenthesizeOnce(expression); KtExpression baseExpression = deparenthesizeOnce(expression, keepAnnotations);
if (baseExpression == expression) return baseExpression; if (baseExpression == expression) return baseExpression;
expression = baseExpression; expression = baseExpression;
@@ -86,7 +96,14 @@ public class KtPsiUtil {
public static KtExpression deparenthesizeOnce( public static KtExpression deparenthesizeOnce(
@Nullable KtExpression expression @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(); return ((KtAnnotatedExpression) expression).getBaseExpression();
} }
else if (expression instanceof KtLabeledExpression) { else if (expression instanceof KtLabeledExpression) {
@@ -58,7 +58,7 @@ class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentInte
override fun applyTo(element: KtBinaryExpression, editor: Editor?) { override fun applyTo(element: KtBinaryExpression, editor: Editor?) {
val topBinary = PsiTreeUtil.getTopmostParentOfType(element, KtBinaryExpression::class.java) ?: element val topBinary = PsiTreeUtil.getTopmostParentOfType(element, KtBinaryExpression::class.java) ?: element
val simplified = toSimplifiedExpression(topBinary) val simplified = toSimplifiedExpression(topBinary)
topBinary.replace(KtPsiUtil.safeDeparenthesize(simplified)) topBinary.replace(KtPsiUtil.safeDeparenthesize(simplified, true))
} }
private fun toSimplifiedExpression(expression: KtExpression): KtExpression { private fun toSimplifiedExpression(expression: KtExpression): KtExpression {
@@ -58,10 +58,10 @@ fun KtBinaryExpression.expressionComparedToNull(): KtExpression? {
} }
fun KtExpression.unwrapBlockOrParenthesis(): KtExpression { fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
val innerExpression = KtPsiUtil.safeDeparenthesize(this) val innerExpression = KtPsiUtil.safeDeparenthesize(this, true)
if (innerExpression is KtBlockExpression) { if (innerExpression is KtBlockExpression) {
val statement = innerExpression.statements.singleOrNull() ?: return this val statement = innerExpression.statements.singleOrNull() ?: return this
return KtPsiUtil.safeDeparenthesize(statement) return KtPsiUtil.safeDeparenthesize(statement, true)
} }
return innerExpression return innerExpression
} }
@@ -50,7 +50,7 @@ class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfixExpress
override fun applyTo(element: KtPostfixExpression, editor: Editor?) { override fun applyTo(element: KtPostfixExpression, editor: Editor?) {
if (editor == null) throw IllegalArgumentException("This intention requires an editor") if (editor == null) throw IllegalArgumentException("This intention requires an editor")
val base = KtPsiUtil.safeDeparenthesize(element.baseExpression!!) val base = KtPsiUtil.safeDeparenthesize(element.baseExpression!!, true)
val expressionText = formatForUseInExceptionArgument(base.text!!) val expressionText = formatForUseInExceptionArgument(base.text!!)
val defaultException = KtPsiFactory(element).createExpression("throw NullPointerException()") val defaultException = KtPsiFactory(element).createExpression("throw NullPointerException()")
@@ -165,7 +165,7 @@ class IfToWhenIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpres
} }
} }
add(KtPsiUtil.safeDeparenthesize(expression)) add(KtPsiUtil.safeDeparenthesize(expression, true))
return this return this
} }
} }
@@ -0,0 +1,13 @@
// WITH_RUNTIME
fun foo(a: Any) {
<caret>if (a == "") {
println(a)
}
else if (a is String) {
println(a)
}
else if (a is List<*>) {
@Suppress("UNCHECKED_CAST")
println(a as List<String>)
}
}
@@ -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<String>)
}
}
@@ -0,0 +1,6 @@
@Target(AnnotationTarget.EXPRESSION)
annotation class Ann
fun foo(arg: String?) {
(@Ann arg)<caret>!!
}
@@ -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")
}
@@ -0,0 +1,15 @@
var b = true
@Target(AnnotationTarget.EXPRESSION)
annotation class Ann
fun println(s: String) {}
fun foo() {
<caret>if (@Ann b) {
println("!")
}
else {
println("")
}
}
@@ -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("")
}
}
@@ -0,0 +1,10 @@
var b = true
@Target(AnnotationTarget.EXPRESSION)
annotation class Ann
fun foo() {
if (@Ann <caret>b == true) {
}
}
@@ -0,0 +1,10 @@
var b = true
@Target(AnnotationTarget.EXPRESSION)
annotation class Ann
fun foo() {
if (@Ann <caret>b) {
}
}
@@ -113,6 +113,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
doTest(fileName); 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") @TestMetadata("withBreak.kt")
public void testWithBreak() throws Exception { public void testWithBreak() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/withBreak.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/cascadeIf/withBreak.kt");
@@ -945,6 +945,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/doubleBangToIfThen/usedInAssignment.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/doubleBangToIfThen/usedInAssignment.kt");
doTest(fileName); 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") @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"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifWhen/ifToWhen/whenWithMultipleConditionTypes.kt");
doTest(fileName); 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") @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"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/simpleWithParentheses2.kt");
doTest(fileName); 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") @TestMetadata("idea/testData/intentions/simplifyNegatedBinaryExpression")