Added IfThenToDoubleBangIntention

This commit is contained in:
Zack Grannan
2014-04-14 15:26:53 -07:00
committed by Zalim Bashorov
parent 8476a790bd
commit aec5ae5dd4
57 changed files with 623 additions and 0 deletions
@@ -343,6 +343,7 @@ fun main(args: Array<String>) {
testClass(javaClass<AbstractCodeTransformationTest>()) {
model("intentions/branched/doubleBangToIfThen", testMethod = "doTestDoubleBangToIfThen")
model("intentions/branched/ifThenToDoubleBang", testMethod = "doTestIfThenToDoubleBang")
model("intentions/branched/elvisToIfThen", testMethod = "doTestElvisToIfThen")
model("intentions/branched/ifThenToElvis", testMethod = "doTestIfThenToElvis")
model("intentions/branched/safeAccessToIfThen", testMethod = "doTestSafeAccessToIfThen")
@@ -0,0 +1 @@
foo(maybeSomething!!)
@@ -0,0 +1 @@
foo(if (maybeSomething != null) maybeSomething else throw KotlinNullPointerException())
@@ -0,0 +1,6 @@
<html>
<body>
Converts an if-then expression that checks if a value is null to an equivalent expression
using the '!!' operator.
</body>
</html>
+5
View File
@@ -499,6 +499,11 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions.IfThenToDoubleBangIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions.ElvisToIfThenIntention</className>
<category>Kotlin</category>
@@ -225,6 +225,9 @@ double.bang.to.if.then.exception.text=Expression ''{0}'' must not be null
double.bang.to.if.then.choose.exception=Choose Exception Class
double.bang.to.if.then=Replace '!!' expression with 'if' expression
double.bang.to.if.then.family=Replace '!!' Expression With 'if' Expression
if.then.to.double.bang=Replace 'if' expression with '!!' expression
if.then.to.double.bang.replace.exception=Replace 'if' expression with '!!' expression (will remove Exception)
if.then.to.double.bang.family=Replace 'if' expression With '!!' Expression
elvis.to.if.then=Replace elvis expression with 'if' expression
elvis.to.if.then.family=Replace Elvis Expression With 'if' Expression
if.then.to.elvis=Replace 'if' expression with elvis expression
@@ -0,0 +1,101 @@
/*
* 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.JetIfExpression
import org.jetbrains.jet.lang.psi.JetBinaryExpression
import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.plugin.intentions.branchedTransformations.evaluatesTo
import org.jetbrains.jet.plugin.intentions.branchedTransformations.comparesNonNullToNull
import org.jetbrains.jet.plugin.intentions.branchedTransformations.getNonNullExpression
import org.jetbrains.jet.plugin.intentions.branchedTransformations.replace
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStableVariable
import org.jetbrains.jet.lang.psi.JetPostfixExpression
import org.jetbrains.jet.plugin.intentions.branchedTransformations.inlineBaseExpressionIfApplicableWithPrompt
import org.jetbrains.jet.plugin.intentions.branchedTransformations.extractExpressionIfSingle
import org.jetbrains.jet.lang.psi.JetThrowExpression
import org.jetbrains.jet.plugin.JetBundle
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isNullExpressionOrEmptyBlock
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStatement
import org.jetbrains.jet.plugin.intentions.branchedTransformations.throwsNullPointerExceptionWithNoArguments
public class IfThenToDoubleBangIntention : JetSelfTargetingIntention<JetIfExpression>("if.then.to.double.bang", 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 expression = condition.getNonNullExpression()
if (expression == null) return false
val token = condition.getOperationToken()
if (token != JetTokens.EQEQ && token != JetTokens.EXCLEQ) return false
val throwExpression =
when (token) {
JetTokens.EQEQ -> thenClause?.extractExpressionIfSingle()
JetTokens.EXCLEQ -> elseClause?.extractExpressionIfSingle()
else -> throw IllegalStateException("Token must be either '!=' or '==' ")
} as? JetThrowExpression
if (throwExpression == null) return false
val matchingClause =
when (token) {
JetTokens.EQEQ -> elseClause
JetTokens.EXCLEQ -> thenClause
else -> throw IllegalStateException("Token must be either '!=' or '==' ")
}
val matchesAsStatement = element.isStatement() && (matchingClause?.isNullExpressionOrEmptyBlock() ?: true)
val matches = matchesAsStatement || (matchingClause?.evaluatesTo(expression) ?: false && expression.isStableVariable())
if (matches) {
val message =
if (throwExpression.throwsNullPointerExceptionWithNoArguments()) {
JetBundle.message("if.then.to.double.bang")
}
else {
// Warn that custom exception will be overwritten by intention action
JetBundle.message("if.then.to.double.bang.replace.exception")
}
setText(message)
return true
}
else {
return false
}
}
override fun applyTo(element: JetIfExpression, editor: Editor) {
val condition = element.getCondition() as JetBinaryExpression
val expression = checkNotNull(condition.getNonNullExpression(), "condition must contain non null expression")
val resultingExprString = expression.getText() + "!!"
val result = element.replace(resultingExprString) as JetPostfixExpression
result.inlineBaseExpressionIfApplicableWithPrompt(editor)
}
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
throw NullPointerException()
}
else {
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun main(args: Array<String>) {
"foo"!!
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo != null<caret>) {
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun main(args: Array<String>) {
"foo"!!
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun foo(): Any? = "foo"
fun main(args: Array<String>) {
if (foo() == null<caret>) {
throw KotlinNullPointerException()
}
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo(): Any? = "foo"
fun main(args: Array<String>) {
foo()!!
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
throw NullPointerException()
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun main(args: Array<String>) {
"foo"!!
}
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = null
if (foo != null<caret>) {
print ("Hello")
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = null
val a = "a"
if (foo != null<caret>) {
a
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,11 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (null == <caret>null) {
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun <T> T.compareTo(a: T): Int = 0
fun main(args: Array<String>) {
val foo = null
if (foo > null<caret>) {
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,17 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>kotlin.Boolean</td></tr><tr><td>Found:</td><td>kotlin.Int</td></tr></table></html>
// ERROR: Condition must be of type kotlin.Boolean, but is of type kotlin.Int
// ERROR: Infix call corresponds to a dot-qualified call 'foo.times(10)' which is not allowed on a nullable receiver 'foo'. Use ?.-qualified call instead
fun String?.times(a: Int): Boolean = a == 0
fun main(args: Array<String>) {
val foo: Int? = 4
if (foo * 10<caret>) {
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
print(foo)
if (foo != null<caret>) {
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
print(foo)
foo!!
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
val x = maybeFoo()
fun main(args: Array<String>) {
if (x !=<caret> null) {
x
} else {
throw NullPointerException()
}
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
val x = maybeFoo()
fun main(args: Array<String>) {
x!!
}
@@ -0,0 +1,11 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = "foo"
if (<caret>) {
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,11 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = null
if (foo != null<caret>) {
foo
}
else {
}
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
}
else {
foo
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>) {
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()!!
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>)
foo
else
throw NullPointerException()
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()!!
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
val x = if (foo == null<caret>) {
throw KotlinNullPointerException()
}
else {
foo
}
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val x = maybeFoo()!!
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo == null<caret>)
throw NullPointerException()
else
foo
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()!!
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (foo != null<caret>)
foo
else
throw NullPointerException("'foo' must not be null")
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()!!
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
null
}
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>)
else {
foo
}
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>kotlin.Boolean</td></tr><tr><td>Found:</td><td>() &rarr; kotlin.String?</td></tr></table></html>
// ERROR: Condition must be of type kotlin.Boolean, but is of type () -> kotlin.String?
fun main(args: Array<String>) {
val foo: String? = "foo"
if<caret> {
foo
} else throw NullPointerException()
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = "foo"
val bar = "bar"
if (foo == bar<caret>) {
foo
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
//IS_APPLICABLE: false
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
if (maybeFoo() == null<caret>)
maybeFoo()
else
throw NullPointerException()
}
@@ -0,0 +1,13 @@
// WITH_RUNTIME
//IS_APPLICABLE: false
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
var foo = maybeFoo()
if (foo == null<caret>)
throw NullPointerException()
else
foo
}
@@ -0,0 +1,11 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = "foo"
if (foo == null<caret>) {
null
}
else {
foo
}
}
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo: String? = null
if (foo != null<caret>) {
foo
}
else {
print ("Hello")
throw NullPointerException("'foo' must not be null")
}
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (null == foo<caret>)
throw NullPointerException()
else
foo
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()!!
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
val foo = maybeFoo()
if (null != foo<caret>)
foo
else
throw NullPointerException()
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
fun maybeFoo(): String? {
return "foo"
}
fun main(args: Array<String>) {
maybeFoo()!!
}
@@ -0,0 +1,11 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun main(args: Array<String>) {
val foo = null
if (foo == null<caret>) {
null
}
else {
null
}
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
class NullPointerException : Exception()
fun foo(): Any? = "foo"
fun main(args: Array<String>) {
if (foo() == null<caret>) {
throw java.lang.NullPointerException()
}
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
class NullPointerException : Exception()
fun foo(): Any? = "foo"
fun main(args: Array<String>) {
foo()!!
}
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
fun main(args: Array<String>) {
val foo: String? = "foo"
val y = if (foo == null<caret>) {
throw NullPointerException()
}
else {
}
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
// IS_APPLICABLE: FALSE
fun main(args: Array<String>) {
val foo: String? = "foo"
val y = if (foo == null<caret>) {
}
else {
throw NullPointerException()
}
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
class F(a: Int?) {
val b = a
val c = if (b != <caret> null) b else throw NullPointerException()
}
fun main(args: Array<String>) {
F(1).c
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
class F(a: Int?) {
val b = a
val c = b!!
}
fun main(args: Array<String>) {
F(1).c
}
@@ -42,6 +42,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes
doTestIntention(path, new DoubleBangToIfThenIntention());
}
public void doTestIfThenToDoubleBang(@NotNull String path) throws Exception {
doTestIntention(path, new IfThenToDoubleBangIntention());
}
public void doTestElvisToIfThen(@NotNull String path) throws Exception {
doTestIntention(path, new ElvisToIfThenIntention());
}