Added ifThenToSafeAccessIntention

This commit is contained in:
Zack Grannan
2014-03-02 17:48:45 -08:00
committed by Zalim Bashorov
parent 1f720c8559
commit 3862a3b5bc
56 changed files with 558 additions and 0 deletions
@@ -350,6 +350,7 @@ fun main(args: Array<String>) {
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")
@@ -0,0 +1 @@
val result = maybeSomething?.perform(something)
@@ -0,0 +1 @@
val result = if (maybeSomething != null) maybeSomething.perform(something) else null
@@ -0,0 +1,5 @@
<html>
<body>
Converts an if-then expression to an expression that uses a safe-access operator (if applicable)
</body>
</html>
+5
View File
@@ -489,6 +489,11 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions.IfThenToSafeAccessIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions.IfToWhenIntention</className>
<category>Kotlin</category>
@@ -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'
@@ -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<JetIfExpression>("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()
}
}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "abc"
if (foo != null<caret>) {
print ("Hello")
foo.length
}
else null
}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
var foo: String? = "foo"
var bar: String? = "bar"
if (foo != null<caret>) {
bar.length
}
else null
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = "foo"
if (null == <caret>null) {
foo.length
}
else null
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = "foo"
if (foo > null<caret>) {
foo.length
}
else null
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String = "foo"
if (foo * 10<caret>) {
foo.length
}
else null
}
@@ -0,0 +1,14 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
print(foo)
if (foo != null<caret>) {
foo.length()
}
else {
null
}
}
@@ -0,0 +1,9 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
print(foo)
foo?.length()
}
@@ -0,0 +1,13 @@
fun maybeFoo(): String? {
return "foo"
}
val x = maybeFoo()
fun main(args: Array<String>) {
if (x !=<caret> null) {
x.length()
} else {
null
}
}
@@ -0,0 +1,9 @@
fun maybeFoo(): String? {
return "foo"
}
val x = maybeFoo()
fun main(args: Array<String>) {
x?.length()
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = "foo"
if (<caret>) {
foo.length
}
else null
}
@@ -0,0 +1,13 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>) {
foo.length
}
else {
}
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length
}
@@ -0,0 +1,12 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo == null<caret>) {
}
else {
foo.length()
}
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,13 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>) {
foo.length()
}
else {
null
}
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,11 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>)
foo.length()
else
null
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,13 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
val x = if (foo == null<caret>) {
null
}
else {
foo.length
}
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val x = maybeFoo()?.length
}
@@ -0,0 +1,11 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo == null<caret>)
null
else
foo.length()
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,11 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>)
foo.length()
else
null
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = null
if (foo == null<caret>) {
null
}
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = null
if (foo != null<caret>)
else {
}
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if<caret> {
foo.length()
} else null
}
@@ -0,0 +1,10 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>) {
foo.length()
}
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
val bar: String? = null
if (foo == bar<caret>) {
foo.length()
}
else null
}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
val bar: String? = null
if (foo == bar<caret>) {
bar.length()
}
else null
}
@@ -0,0 +1,10 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo == null<caret>) else {
foo.length()
}
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,11 @@
//IS_APPLICABLE: false
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
if (maybeFoo() == null<caret>)
null
else
maybeFoo().length()
}
@@ -0,0 +1,12 @@
//IS_APPLICABLE: false
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
var foo = maybeFoo()
if (foo == null<caret>)
null
else
foo.length()
}
@@ -0,0 +1,11 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "abc"
if (foo != null<caret>) {
foo.length
}
else {
print("Hi")
null
}
}
@@ -0,0 +1,11 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (null == foo<caret>)
null
else
foo.length()
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,11 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (null != foo<caret>)
foo.length()
else
null
}
@@ -0,0 +1,7 @@
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()?.length()
}
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null) {
null
}
else {
null
}
}
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
foo.length()
}
else {
foo.length()
}
}
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
null
}
else {
}
}
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo != null<caret>) {
}
else {
null
}
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
null
}
}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo != null<caret>)
else {
null
}
}
@@ -0,0 +1,8 @@
class F(a: Int?) {
val b = a
val c = if (b !=<caret> null) b.toString() else null
}
fun main(args: Array<String>) {
F(1).c
}
@@ -0,0 +1,8 @@
class F(a: Int?) {
val b = a
val c = b?.toString()
}
fun main(args: Array<String>) {
F(1).c
}
@@ -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());
}