Fix "Replace !! with if-then" inspection in receiver position

#KT-5412 Fixed
This commit is contained in:
Burak Eregar
2019-03-15 05:58:25 +03:00
committed by Mikhail Glukhikh
parent 162de77b71
commit 1455451601
8 changed files with 137 additions and 14 deletions
@@ -28,18 +28,15 @@ import com.intellij.psi.PsiDocumentManager
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.ChooseStringExpression
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNotNullExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNullExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceValueForCondition
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtPostfixExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtThrowExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfixExpression>(KtPostfixExpression::class.java, "Replace '!!' expression with 'if' expression"), LowPriorityAction {
class DoubleBangToIfThenIntention :
SelfTargetingRangeIntention<KtPostfixExpression>(KtPostfixExpression::class.java, "Replace '!!' expression with 'if' expression"),
LowPriorityAction {
override fun applicabilityRange(element: KtPostfixExpression): TextRange? {
return if (element.operationToken == KtTokens.EXCLEXCL && element.baseExpression != null)
element.operationReference.textRange
@@ -60,12 +57,31 @@ class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfixExpress
val ifStatement = if (isStatement)
element.convertToIfNullExpression(base, defaultException)
else
element.convertToIfNotNullExpression(base, base, defaultException)
else {
val selectorExpression = element.getQualifiedExpressionForReceiver()?.selectorExpression
val thenClause = selectorExpression?.let {
KtPsiFactory(element).createExpressionByPattern("$0.$1", base, it)
} ?: base
val hasSelector = thenClause != base
if (hasSelector) {
val prevSibling = selectorExpression?.prevSibling
selectorExpression?.delete()
prevSibling?.delete()
}
element.convertToIfNotNullExpression(base, thenClause, defaultException).apply {
if (hasSelector) {
with(parent) {
firstChild.delete()
lastChild.delete()
}
}
}
}
val thrownExpression =
((if (isStatement) ifStatement.then else ifStatement.`else`) as KtThrowExpression).thrownExpression!!
((if (isStatement) ifStatement.then else ifStatement.`else`) as KtThrowExpression).thrownExpression!!
val message = StringUtil.escapeStringCharacters("Expression '$expressionText' must not be null")
val nullPtrExceptionText = "NullPointerException(\"$message\")"
val kotlinNullPtrExceptionText = "KotlinNullPointerException()"
@@ -79,7 +95,7 @@ class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfixExpress
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
editor.caretModel.moveToOffset(thrownExpression.node!!.startOffset)
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object: TemplateEditingAdapter() {
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object : TemplateEditingAdapter() {
override fun templateFinished(template: Template, brokenOff: Boolean) {
if (!isStable && !isStatement) {
ifStatement.introduceValueForCondition(ifStatement.then!!, editor)
@@ -0,0 +1,15 @@
// WITH_RUNTIME
fun foo(): String? {
return "foo"
}
class A {
fun f(): Int {
return 42
}
}
fun main(args: Array<String>) {
val a: A? = A()
a<caret>!!.f()
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
fun foo(): String? {
return "foo"
}
class A {
fun f(): Int {
return 42
}
}
fun main(args: Array<String>) {
val a: A? = A()
if (a != null) a.f() else throw NullPointerException("Expression 'a' must not be null")
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
fun foo(): String? {
return "foo"
}
class A {
val g = 44
fun f(): Int {
return 42
}
}
fun main(args: Array<String>) {
val a: A? = A()
a<caret>!!.g
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
fun foo(): String? {
return "foo"
}
class A {
val g = 44
fun f(): Int {
return 42
}
}
fun main(args: Array<String>) {
val a: A? = A()
if (a != null) a.g else throw NullPointerException("Expression 'a' must not be null")
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
fun foo(): String? {
return "foo"
}
class A {
fun f(): Int {
return 42
}
}
fun main(args: Array<String>) {
val a: A? = A()
val b = a<caret>!!.f()
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
fun foo(): String? {
return "foo"
}
class A {
fun f(): Int {
return 42
}
}
fun main(args: Array<String>) {
val a: A? = A()
val b = if (a != null) a.f() else throw NullPointerException("Expression 'a' must not be null")
}
@@ -2059,6 +2059,21 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/branched/doubleBangToIfThen/localVar.kt");
}
@TestMetadata("replaceParentExpression.kt")
public void testReplaceParentExpression() throws Exception {
runTest("idea/testData/intentions/branched/doubleBangToIfThen/replaceParentExpression.kt");
}
@TestMetadata("replaceParentExpression2.kt")
public void testReplaceParentExpression2() throws Exception {
runTest("idea/testData/intentions/branched/doubleBangToIfThen/replaceParentExpression2.kt");
}
@TestMetadata("replaceParentExpression3.kt")
public void testReplaceParentExpression3() throws Exception {
runTest("idea/testData/intentions/branched/doubleBangToIfThen/replaceParentExpression3.kt");
}
@TestMetadata("simpleNameExpressionInParens.kt")
public void testSimpleNameExpressionInParens() throws Exception {
runTest("idea/testData/intentions/branched/doubleBangToIfThen/simpleNameExpressionInParens.kt");