"If null to elvis" now converts to elvis also !is check right after initializer #KT-14032 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-10-10 15:53:23 +03:00
committed by Mikhail Glukhikh
parent 121f0ec810
commit 0903402282
15 changed files with 55 additions and 28 deletions
@@ -0,0 +1,5 @@
<html>
<body>
This inspection reports an if expression checking variable being null or not of a type right after initializing it that can be converted into an elvis operator in the initializer
</body>
</html>
@@ -1,5 +0,0 @@
<html>
<body>
This inspection reports an if expression checking variable being null right after initializing it that can be converted into an elvis operator in the initializer
</body>
</html>
@@ -0,0 +1,5 @@
<html>
<body>
Converts an if expression checking variable being null or not of a type right after initializing it to an elvis operator in the initializer (if applicable)
</body>
</html>
@@ -1,5 +0,0 @@
<html>
<body>
Converts an if expression checking variable being null right after initializing it to an elvis operator in the initializer (if applicable)
</body>
</html>
+2 -2
View File
@@ -731,7 +731,7 @@
<usageToPsiElementProvider implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinUsageToPsiElementProvider"/>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.IfNullToElvisIntention</className>
<className>org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention</className>
<category>Kotlin</category>
</intentionAction>
@@ -1451,7 +1451,7 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.IfNullToElvisInspection"
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisInspection"
displayName="If-Null return/break/... foldable to '?:'"
groupName="Kotlin"
enabledByDefault="true"
@@ -35,9 +35,9 @@ import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class IfNullToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfNullToElvisIntention::class)
class FoldInitializerAndIfToElvisInspection : IntentionBasedInspection<KtIfExpression>(FoldInitializerAndIfToElvisIntention::class)
class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' with elvis operator"){
class FoldInitializerAndIfToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' with elvis operator"){
override fun applicabilityRange(element: KtIfExpression): TextRange? {
val data = calcData(element) ?: return null
@@ -49,7 +49,7 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
}
override fun applyTo(element: KtIfExpression, editor: Editor?) {
val (initializer, declaration, ifNullExpr) = calcData(element)!!
val (initializer, declaration, ifNullExpr, typeReference) = calcData(element)!!
val factory = KtPsiFactory(element)
val explicitTypeToSet = when {
@@ -67,6 +67,9 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
val childRangeAfter = childRangeBefore.withoutLastStatement()
val elvis = factory.createExpressionByPattern("$0 ?: $1", initializer, ifNullExpr) as KtBinaryExpression
if (typeReference != null) {
elvis.left!!.replace(factory.createExpressionByPattern("$0 as? $1", initializer, typeReference))
}
val newElvis = initializer.replaced(elvis)
element.delete()
@@ -82,15 +85,25 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
private data class Data(
val initializer: KtExpression,
val declaration: KtVariableDeclaration,
val ifNullExpression: KtExpression
val ifNullExpression: KtExpression,
val typeChecked: KtTypeReference? = null
)
private fun calcData(ifExpression: KtIfExpression): Data? {
if (ifExpression.`else` != null) return null
val binaryExpression = ifExpression.condition as? KtBinaryExpression ?: return null
if (binaryExpression.operationToken != KtTokens.EQEQ) return null
val value = binaryExpression.expressionComparedToNull() as? KtNameReferenceExpression ?: return null
val operationExpression = ifExpression.condition as? KtOperationExpression ?: return null
val value = when (operationExpression) {
is KtBinaryExpression -> {
if (operationExpression.operationToken != KtTokens.EQEQ) return null
operationExpression.expressionComparedToNull()
}
is KtIsExpression -> {
if (!operationExpression.isNegated) return null
operationExpression.leftHandSide
}
else -> return null
} as? KtNameReferenceExpression ?: return null
if (ifExpression.parent !is KtBlockExpression) return null
val prevStatement = ifExpression.siblings(forward = false, withItself = false)
@@ -99,13 +112,14 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
if (prevStatement.nameAsName != value.getReferencedNameAsName()) return null
val initializer = prevStatement.initializer ?: return null
val then = ifExpression.then ?: return null
val typeReference = (operationExpression as? KtIsExpression)?.typeReference
if (then is KtBlockExpression) {
val statement = then.statements.singleOrNull() ?: return null
return Data(initializer, prevStatement, statement)
return Data(initializer, prevStatement, statement, typeReference)
}
else {
return Data(initializer, prevStatement, then)
return Data(initializer, prevStatement, then, typeReference)
}
}
@@ -61,7 +61,7 @@ object J2KPostProcessingRegistrar {
registerIntentionBasedProcessing(ConvertToExpressionBodyIntention(convertEmptyToUnit = false)) { it is KtPropertyAccessor }
registerIntentionBasedProcessing(IfThenToSafeAccessIntention())
registerIntentionBasedProcessing(IfThenToElvisIntention())
registerIntentionBasedProcessing(IfNullToElvisIntention())
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
registerIntentionBasedProcessing(SimplifyNegatedBinaryExpressionIntention())
registerIntentionBasedProcessing(ReplaceGetOrSetIntention(), additionalChecker = ReplaceGetOrSetInspection.additionalChecker)
registerIntentionBasedProcessing(AddOperatorModifierIntention())
+1 -1
View File
@@ -1 +1 @@
org.jetbrains.kotlin.idea.intentions.IfNullToElvisIntention
org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention
+4
View File
@@ -0,0 +1,4 @@
fun foo(arg: Any?) {
val n = arg
if (<caret>n !is Int) return
}
+3
View File
@@ -0,0 +1,3 @@
fun foo(arg: Any?) {
val n = arg as? Int ?: return
}
@@ -1,4 +1,4 @@
// "Suppress 'IfNullToElvis' for fun foo" "true"
// "Suppress 'FoldInitializerAndIfToElvis' for fun foo" "true"
fun foo(p: List<String?>, b: Boolean) {
var v = p[0]
@@ -6,4 +6,4 @@ fun foo(p: List<String?>, b: Boolean) {
if (b) v = null
}
// TOOL: org.jetbrains.kotlin.idea.intentions.IfNullToElvisInspection
// TOOL: org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisInspection
@@ -1,10 +1,10 @@
// "Suppress 'IfNullToElvis' for fun foo" "true"
// "Suppress 'FoldInitializerAndIfToElvis' for fun foo" "true"
@Suppress("IfNullToElvis")
@Suppress("FoldInitializerAndIfToElvis")
fun foo(p: List<String?>, b: Boolean) {
var v = p[0]
<caret>if (v == null) return
if (b) v = null
}
// TOOL: org.jetbrains.kotlin.idea.intentions.IfNullToElvisInspection
// TOOL: org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisInspection
@@ -6463,6 +6463,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("NotIs.kt")
public void testNotIs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/ifNullToElvis/NotIs.kt");
doTest(fileName);
}
@TestMetadata("OtherVar1.kt")
public void testOtherVar1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/ifNullToElvis/OtherVar1.kt");