diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt index f93e2ea2cbb..4b7a8838731 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt @@ -350,6 +350,7 @@ fun main(args: Array) { model("intentions/branched/elvisToIfThen", testMethod = "doTestElvisToIfThen") model("intentions/branched/ifThenToElvis", testMethod = "doTestIfThenToElvis") model("intentions/branched/safeAccessToIfThen", testMethod = "doTestSafeAccessToIfThen") + model("intentions/branched/ifThenToSafeAccess", testMethod = "doTestIfThenToSafeAccess") model("intentions/branched/folding/ifToAssignment", testMethod = "doTestFoldIfToAssignment") model("intentions/branched/folding/ifToReturn", testMethod = "doTestFoldIfToReturn") model("intentions/branched/folding/ifToReturnAsymmetrically", testMethod = "doTestFoldIfToReturnAsymmetrically") diff --git a/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/after.kt.template b/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/after.kt.template new file mode 100644 index 00000000000..693c07d2393 --- /dev/null +++ b/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/after.kt.template @@ -0,0 +1 @@ +val result = maybeSomething?.perform(something) diff --git a/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/before.kt.template b/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/before.kt.template new file mode 100644 index 00000000000..1ff0c342acb --- /dev/null +++ b/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/before.kt.template @@ -0,0 +1 @@ +val result = if (maybeSomething != null) maybeSomething.perform(something) else null diff --git a/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/description.html b/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/description.html new file mode 100644 index 00000000000..52968f84275 --- /dev/null +++ b/idea/resources/intentionDescriptions/IfThenToSafeAccessIntention/description.html @@ -0,0 +1,5 @@ + + + Converts an if-then expression to an expression that uses a safe-access operator (if applicable) + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 6d3a746ea38..d62d4bd80dd 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -489,6 +489,11 @@ Kotlin + + org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions.IfThenToSafeAccessIntention + Kotlin + + org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions.IfToWhenIntention Kotlin diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties index 97ebf1843a5..c4dd0f5643c 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties @@ -225,6 +225,8 @@ if.then.to.elvis=Replace 'if' expression with elvis expression if.then.to.elvis.family=Replace 'if' expression With Elvis Expression safe.access.to.if.then=Replace safe access expression with 'if' expression safe.access.to.if.then.family=Replace Safe Access Expression With 'if' Expression +if.then.to.safe.access=Replace 'if' expression with safe access expression +if.then.to.safe.access.family=Replace 'if' Expression with Safe Access Expression if.to.when=Replace 'if' with 'when' if.to.when.family=Replace 'if' with 'when' when.to.if=Replace 'when' with 'if' diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt new file mode 100644 index 00000000000..da24dc2bf0a --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/IfThenToSafeAccessIntention.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions + +import org.jetbrains.jet.plugin.intentions.JetSelfTargetingIntention +import com.intellij.openapi.editor.Editor +import org.jetbrains.jet.lang.psi.JetExpression +import org.jetbrains.jet.lang.psi.JetIfExpression +import org.jetbrains.jet.lang.psi.JetBinaryExpression +import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.plugin.intentions.branchedTransformations.extractExpressionIfSingle +import org.jetbrains.jet.plugin.intentions.branchedTransformations.comparesNonNullToNull +import org.jetbrains.jet.plugin.intentions.branchedTransformations.getNonNullExpression +import org.jetbrains.jet.plugin.intentions.branchedTransformations.isNullExpressionOrEmptyBlock +import org.jetbrains.jet.plugin.intentions.branchedTransformations.replace +import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression +import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStableVariable +import org.jetbrains.jet.plugin.intentions.branchedTransformations.inlineReceiverIfApplicableWithPrompt + +public class IfThenToSafeAccessIntention : JetSelfTargetingIntention("if.then.to.safe.access", javaClass()) { + + override fun isApplicableTo(element: JetIfExpression): Boolean { + val condition = element.getCondition() + val thenClause = element.getThen() + val elseClause = element.getElse() + if (condition !is JetBinaryExpression || !condition.comparesNonNullToNull()) return false + + val receiverExpression = condition.getNonNullExpression() + if (receiverExpression == null || !receiverExpression.isStableVariable()) return false + + return when (condition.getOperationToken()) { + JetTokens.EQEQ -> + thenClause?.isNullExpressionOrEmptyBlock() ?: true && + elseClause != null && clauseContainsAppropriateDotQualifiedExpression(elseClause, receiverExpression) + + JetTokens.EXCLEQ -> + elseClause?.isNullExpressionOrEmptyBlock() ?: true && + thenClause != null && clauseContainsAppropriateDotQualifiedExpression(thenClause, receiverExpression) + + else -> + false + } + } + + override fun applyTo(element: JetIfExpression, editor: Editor) { + val condition = element.getCondition() as JetBinaryExpression + val receiverExpression = checkNotNull(condition.getNonNullExpression(), "The receiver expression cannot be null") + + val selectorExpression = + when(condition.getOperationToken()) { + + JetTokens.EQEQ -> { + val elseClause = checkNotNull(element.getElse(), "The else clause cannot be null") + findSelectorExpressionInClause(elseClause, receiverExpression) + } + + JetTokens.EXCLEQ -> { + val thenClause = checkNotNull(element.getThen(), "The then clause cannot be null") + findSelectorExpressionInClause(thenClause, receiverExpression) + } + + else -> + throw IllegalStateException("Operation token must be either null or not null") + } + + val resultingExprString = "${receiverExpression.getText()}?.${selectorExpression?.getText()}" + val safeAccessExpr = element.replace(resultingExprString) as JetSafeQualifiedExpression + safeAccessExpr.inlineReceiverIfApplicableWithPrompt(editor) + } + + fun clauseContainsAppropriateDotQualifiedExpression(clause: JetExpression, receiverExpression: JetExpression): Boolean = + findSelectorExpressionInClause(clause, receiverExpression) != null + + fun findSelectorExpressionInClause(clause: JetExpression, receiverExpression: JetExpression): JetExpression? { + val expression = clause.extractExpressionIfSingle() as? JetDotQualifiedExpression + + if (expression?.getReceiverExpression()?.getText() != receiverExpression.getText()) return null + + return expression?.getSelectorExpression() + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/blockHasMoreThanOneStatement.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/blockHasMoreThanOneStatement.kt new file mode 100644 index 00000000000..e8e6f896e53 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/blockHasMoreThanOneStatement.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "abc" + if (foo != null) { + print ("Hello") + foo.length + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/blockUsesDifferentVar.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/blockUsesDifferentVar.kt new file mode 100644 index 00000000000..5908e4ddef0 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/blockUsesDifferentVar.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + var foo: String? = "foo" + var bar: String? = "bar" + if (foo != null) { + bar.length + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/conditionComparesNullWithNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/conditionComparesNullWithNull.kt new file mode 100644 index 00000000000..dfb67445d55 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/conditionComparesNullWithNull.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo = "foo" + if (null == null) { + foo.length + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/conditionInvalidBinaryExp.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/conditionInvalidBinaryExp.kt new file mode 100644 index 00000000000..45bcd64e3a5 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/conditionInvalidBinaryExp.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo = "foo" + if (foo > null) { + foo.length + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/conditionNotBinaryExpr.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/conditionNotBinaryExpr.kt new file mode 100644 index 00000000000..a3e4840e933 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/conditionNotBinaryExpr.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String = "foo" + if (foo * 10) { + foo.length + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueIfUsedMoreThanOnce.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueIfUsedMoreThanOnce.kt new file mode 100644 index 00000000000..62909e54f69 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueIfUsedMoreThanOnce.kt @@ -0,0 +1,14 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + print(foo) + if (foo != null) { + foo.length() + } + else { + null + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueIfUsedMoreThanOnce.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueIfUsedMoreThanOnce.kt.after new file mode 100644 index 00000000000..07df4d7cb02 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueIfUsedMoreThanOnce.kt.after @@ -0,0 +1,9 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + print(foo) + foo?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueOutsideOfScope.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueOutsideOfScope.kt new file mode 100644 index 00000000000..ad692c4df57 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueOutsideOfScope.kt @@ -0,0 +1,13 @@ +fun maybeFoo(): String? { + return "foo" +} + +val x = maybeFoo() + +fun main(args: Array) { + if (x != null) { + x.length() + } else { + null + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueOutsideOfScope.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueOutsideOfScope.kt.after new file mode 100644 index 00000000000..6665cb79390 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/doesNotinlineValueOutsideOfScope.kt.after @@ -0,0 +1,9 @@ +fun maybeFoo(): String? { + return "foo" +} + +val x = maybeFoo() + +fun main(args: Array) { + x?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/emptyCondition.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyCondition.kt new file mode 100644 index 00000000000..410f549fae4 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyCondition.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo = "foo" + if () { + foo.length + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/emptyElseBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyElseBlock.kt new file mode 100644 index 00000000000..1175234b604 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyElseBlock.kt @@ -0,0 +1,13 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo != null) { + foo.length + } + else { + + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/emptyElseBlock.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyElseBlock.kt.after new file mode 100644 index 00000000000..cb42a95887b --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyElseBlock.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/emptyThenBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyThenBlock.kt new file mode 100644 index 00000000000..783bdd89eb3 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyThenBlock.kt @@ -0,0 +1,12 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo == null) { + } + else { + foo.length() + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/emptyThenBlock.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyThenBlock.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/emptyThenBlock.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseBothInBlocks.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseBothInBlocks.kt new file mode 100644 index 00000000000..380ad91c1a9 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseBothInBlocks.kt @@ -0,0 +1,13 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo != null) { + foo.length() + } + else { + null + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseBothInBlocks.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseBothInBlocks.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseBothInBlocks.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseNotInBlocks.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseNotInBlocks.kt new file mode 100644 index 00000000000..477185371da --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseNotInBlocks.kt @@ -0,0 +1,11 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo != null) + foo.length() + else + null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseNotInBlocks.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseNotInBlocks.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAndElseNotInBlocks.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/ifAsExpression.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAsExpression.kt new file mode 100644 index 00000000000..0c1862c362a --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAsExpression.kt @@ -0,0 +1,13 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + val x = if (foo == null) { + null + } + else { + foo.length + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/ifAsExpression.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAsExpression.kt.after new file mode 100644 index 00000000000..4bbf14d33eb --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/ifAsExpression.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val x = maybeFoo()?.length +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/lhsEqualsNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsEqualsNull.kt new file mode 100644 index 00000000000..9e40449ed9d --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsEqualsNull.kt @@ -0,0 +1,11 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo == null) + null + else + foo.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/lhsEqualsNull.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsEqualsNull.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsEqualsNull.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/lhsNotEqualsNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsNotEqualsNull.kt new file mode 100644 index 00000000000..477185371da --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsNotEqualsNull.kt @@ -0,0 +1,11 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo != null) + foo.length() + else + null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/lhsNotEqualsNull.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsNotEqualsNull.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/lhsNotEqualsNull.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/missingNecessaryElseClause.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/missingNecessaryElseClause.kt new file mode 100644 index 00000000000..6f40921914a --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/missingNecessaryElseClause.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo = null + if (foo == null) { + null + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/missingNecessaryThenClause.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/missingNecessaryThenClause.kt new file mode 100644 index 00000000000..19e17fa72c1 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/missingNecessaryThenClause.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo = null + if (foo != null) + else { + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/noCondition.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/noCondition.kt new file mode 100644 index 00000000000..e279a4cfa6b --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/noCondition.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + if { + foo.length() + } else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/noElseBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/noElseBlock.kt new file mode 100644 index 00000000000..540f6c9c2ad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/noElseBlock.kt @@ -0,0 +1,10 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo != null) { + foo.length() + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/noElseBlock.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/noElseBlock.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/noElseBlock.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/noNullInCondition.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/noNullInCondition.kt new file mode 100644 index 00000000000..d6b5b7b9d45 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/noNullInCondition.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + val bar: String? = null + if (foo == bar) { + foo.length() + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/noNullInCondition2.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/noNullInCondition2.kt new file mode 100644 index 00000000000..e43bf8493b5 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/noNullInCondition2.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + val bar: String? = null + if (foo == bar) { + bar.length() + } + else null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/noThenBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/noThenBlock.kt new file mode 100644 index 00000000000..35dd651a2d1 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/noThenBlock.kt @@ -0,0 +1,10 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (foo == null) else { + foo.length() + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/noThenBlock.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/noThenBlock.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/noThenBlock.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/notApplicableForFunction.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/notApplicableForFunction.kt new file mode 100644 index 00000000000..53a42595091 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/notApplicableForFunction.kt @@ -0,0 +1,11 @@ +//IS_APPLICABLE: false +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + if (maybeFoo() == null) + null + else + maybeFoo().length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/notApplicableForLocalVar.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/notApplicableForLocalVar.kt new file mode 100644 index 00000000000..e63b7e966bc --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/notApplicableForLocalVar.kt @@ -0,0 +1,12 @@ +//IS_APPLICABLE: false +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + var foo = maybeFoo() + if (foo == null) + null + else + foo.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/otherBlockHasMoreThanOneStatement.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/otherBlockHasMoreThanOneStatement.kt new file mode 100644 index 00000000000..afa18c05c77 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/otherBlockHasMoreThanOneStatement.kt @@ -0,0 +1,11 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "abc" + if (foo != null) { + foo.length + } + else { + print("Hi") + null + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/rhsEqualsNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsEqualsNull.kt new file mode 100644 index 00000000000..741c7b8201b --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsEqualsNull.kt @@ -0,0 +1,11 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (null == foo) + null + else + foo.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/rhsEqualsNull.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsEqualsNull.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsEqualsNull.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/rhsNotEqualsNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsNotEqualsNull.kt new file mode 100644 index 00000000000..446ee02b391 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsNotEqualsNull.kt @@ -0,0 +1,11 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + val foo = maybeFoo() + if (null != foo) + foo.length() + else + null +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/rhsNotEqualsNull.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsNotEqualsNull.kt.after new file mode 100644 index 00000000000..005ab996cad --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/rhsNotEqualsNull.kt.after @@ -0,0 +1,7 @@ +fun maybeFoo(): String? { + return "foo" +} + +fun main(args: Array) { + maybeFoo()?.length() +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/thenAndElseBothNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/thenAndElseBothNull.kt new file mode 100644 index 00000000000..98446403533 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/thenAndElseBothNull.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + if (foo == null) { + null + } + else { + null + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/thenAndElseNotNull.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/thenAndElseNotNull.kt new file mode 100644 index 00000000000..e0284d9c0c1 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/thenAndElseNotNull.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + if (foo == null) { + foo.length() + } + else { + foo.length() + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableEmptyElseBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableEmptyElseBlock.kt new file mode 100644 index 00000000000..29b3dc79fc4 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableEmptyElseBlock.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + if (foo == null) { + null + } + else { + + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableEmptyThenBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableEmptyThenBlock.kt new file mode 100644 index 00000000000..b00af088ac3 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableEmptyThenBlock.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + if (foo != null) { + } + else { + null + } + +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableNoElseBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableNoElseBlock.kt new file mode 100644 index 00000000000..3c6d197adb6 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableNoElseBlock.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + if (foo == null) { + null + } +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableNoThenBlock.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableNoThenBlock.kt new file mode 100644 index 00000000000..67741749c64 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/unacceptableNoThenBlock.kt @@ -0,0 +1,9 @@ +// IS_APPLICABLE: false +fun main(args: Array) { + val foo: String? = "foo" + if (foo != null) + else { + null + } + +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/willNotInlineClassProperty.kt b/idea/testData/intentions/branched/ifThenToSafeAccess/willNotInlineClassProperty.kt new file mode 100644 index 00000000000..1a533cccf84 --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/willNotInlineClassProperty.kt @@ -0,0 +1,8 @@ +class F(a: Int?) { + val b = a + val c = if (b != null) b.toString() else null +} + +fun main(args: Array) { + F(1).c +} diff --git a/idea/testData/intentions/branched/ifThenToSafeAccess/willNotInlineClassProperty.kt.after b/idea/testData/intentions/branched/ifThenToSafeAccess/willNotInlineClassProperty.kt.after new file mode 100644 index 00000000000..01d1cd06eef --- /dev/null +++ b/idea/testData/intentions/branched/ifThenToSafeAccess/willNotInlineClassProperty.kt.after @@ -0,0 +1,8 @@ +class F(a: Int?) { + val b = a + val c = b?.toString() +} + +fun main(args: Array) { + F(1).c +} diff --git a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java index 6736e32c7cb..85bfacfac16 100644 --- a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java @@ -43,6 +43,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes doTestIntention(path, new SafeAccessToIfThenIntention()); } + public void doTestIfThenToSafeAccess(@NotNull String path) throws Exception { + doTestIntention(path, new IfThenToSafeAccessIntention()); + } + public void doTestFoldIfToAssignment(@NotNull String path) throws Exception { doTestIntention(path, new FoldIfToAssignmentIntention()); }