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 bf3df45f21a..ff1e7fbacf0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/IfThenUtils.kt @@ -88,9 +88,8 @@ fun KtThrowExpression.throwsNullPointerExceptionWithNoArguments(): Boolean { && thrownExpression.valueArguments.isEmpty() } -fun KtExpression.evaluatesTo(other: KtExpression): Boolean { - return this.unwrapBlockOrParenthesis().text == other.text -} +fun KtExpression.evaluatesTo(other: KtExpression): Boolean = + this.unwrapBlockOrParenthesis().text == other.text fun KtExpression.convertToIfNotNullExpression(conditionLhs: KtExpression, thenClause: KtExpression, elseClause: KtExpression?): KtIfExpression { val condition = KtPsiFactory(this).createExpressionByPattern("$0 != null", conditionLhs) @@ -102,9 +101,8 @@ fun KtExpression.convertToIfNullExpression(conditionLhs: KtExpression, thenClaus return this.convertToIfStatement(condition, thenClause) } -fun KtExpression.convertToIfStatement(condition: KtExpression, thenClause: KtExpression, elseClause: KtExpression? = null): KtIfExpression { - return replaced(KtPsiFactory(this).createIf(condition, thenClause, elseClause)) -} +fun KtExpression.convertToIfStatement(condition: KtExpression, thenClause: KtExpression, elseClause: KtExpression? = null): KtIfExpression = + replaced(KtPsiFactory(this).createIf(condition, thenClause, elseClause)) fun KtIfExpression.introduceValueForCondition(occurrenceInThenClause: KtExpression, editor: Editor?) { val project = this.project @@ -157,14 +155,17 @@ data class IfThenToSelectData( val baseClause: KtExpression?, val negatedClause: KtExpression? ) { + internal fun baseClauseEvaluatesToReceiver() = + baseClause?.evaluatesTo(receiverExpression) == true + internal fun replacedBaseClause(factory: KtPsiFactory): KtExpression { baseClause ?: error("Base clause must be not-null here") val newReceiver = (condition as? KtIsExpression)?.let { factory.createExpressionByPattern("$0 as? $1", - (baseClause as? KtDotQualifiedExpression)?.getLeftMostReceiverExpression() ?: baseClause, + it.leftHandSide, it.typeReference!!) } - return if (baseClause.evaluatesTo(receiverExpression)) { + return if (baseClauseEvaluatesToReceiver()) { if (condition is KtIsExpression) newReceiver!! else baseClause } else { @@ -177,9 +178,8 @@ data class IfThenToSelectData( } } - internal fun hasImplicitReceiver(): Boolean { - return baseClause.getResolvedCall(context)?.getImplicitReceiverValue() != null - } + internal fun hasImplicitReceiver(): Boolean = + baseClause.getResolvedCall(context)?.getImplicitReceiverValue() != null } internal fun KtIfExpression.buildSelectTransformationData(): IfThenToSelectData? { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt index d5219634545..92073a77b13 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt @@ -40,7 +40,7 @@ class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntentionlight_idea_test_case If-Then foldable to '?.' + Replace 'if' expression with safe access expression + + + property.kt + 10 + light_idea_test_case + + If-Then foldable to '?.' + Replace 'if' expression with safe cast expression + + + propertyNotNull.kt + 9 + light_idea_test_case + + If-Then foldable to '?.' Remove redundant 'if' expression diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/property.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/property.kt new file mode 100644 index 00000000000..f0c944ad599 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/property.kt @@ -0,0 +1,11 @@ +// IS_APPLICABLE: true +// INTENTION_TEXT: Replace 'if' expression with safe cast expression + +interface Foo +interface Bar : Foo + +data class Data(val foo: Foo) + +fun handle(data: Data) { + val bar = if (data.foo is Bar) data.foo else null +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/property.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/property.kt.after new file mode 100644 index 00000000000..5a3bb590bf9 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/property.kt.after @@ -0,0 +1,11 @@ +// IS_APPLICABLE: true +// INTENTION_TEXT: Replace 'if' expression with safe cast expression + +interface Foo +interface Bar : Foo + +data class Data(val foo: Foo) + +fun handle(data: Data) { + val bar = data.foo as? Bar +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/propertyNotNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/propertyNotNull.kt new file mode 100644 index 00000000000..cd8cdcd6ec2 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/propertyNotNull.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: true +// INTENTION_TEXT: Remove redundant 'if' expression + +interface Bar + +data class Data(val bar: Bar?) + +fun handle(data: Data) { + val bar = if (data.bar != null) data.bar else null +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/propertyNotNull.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/propertyNotNull.kt.after new file mode 100644 index 00000000000..e8513e737e7 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/propertyNotNull.kt.after @@ -0,0 +1,10 @@ +// IS_APPLICABLE: true +// INTENTION_TEXT: Remove redundant 'if' expression + +interface Bar + +data class Data(val bar: Bar?) + +fun handle(data: Data) { + val bar = data.bar +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/propertyWithProperty.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/propertyWithProperty.kt new file mode 100644 index 00000000000..60181d3f2db --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/propertyWithProperty.kt @@ -0,0 +1,13 @@ +// IS_APPLICABLE: false + +interface Foo +interface Bar : Foo { + val x: String +} + +data class Data(val foo: Foo) + +fun handle(data: Data) { + // Not available yet (possible in principle) + val bar = if (data.foo is Bar) data.foo.x else null +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index aad5809fd2e..4426bdaab25 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -1774,6 +1774,24 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("property.kt") + public void testProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifThenToSafeAccess/property.kt"); + doTest(fileName); + } + + @TestMetadata("propertyNotNull.kt") + public void testPropertyNotNull() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifThenToSafeAccess/propertyNotNull.kt"); + doTest(fileName); + } + + @TestMetadata("propertyWithProperty.kt") + public void testPropertyWithProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifThenToSafeAccess/propertyWithProperty.kt"); + doTest(fileName); + } + @TestMetadata("rhsEqualsNull.kt") public void testRhsEqualsNull() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifThenToSafeAccess/rhsEqualsNull.kt");