"If null to elvis" now converts to elvis also !is check right after initializer #KT-14032 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
121f0ec810
commit
0903402282
@@ -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>
|
|
||||||
+5
@@ -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>
|
|
||||||
@@ -731,7 +731,7 @@
|
|||||||
<usageToPsiElementProvider implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinUsageToPsiElementProvider"/>
|
<usageToPsiElementProvider implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinUsageToPsiElementProvider"/>
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.IfNullToElvisIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
@@ -1451,7 +1451,7 @@
|
|||||||
language="kotlin"
|
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 '?:'"
|
displayName="If-Null return/break/... foldable to '?:'"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
|
|||||||
+23
-9
@@ -35,9 +35,9 @@ import org.jetbrains.kotlin.types.typeUtil.isNothing
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
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? {
|
override fun applicabilityRange(element: KtIfExpression): TextRange? {
|
||||||
val data = calcData(element) ?: return null
|
val data = calcData(element) ?: return null
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun applyTo(element: KtIfExpression, editor: Editor?) {
|
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 factory = KtPsiFactory(element)
|
||||||
|
|
||||||
val explicitTypeToSet = when {
|
val explicitTypeToSet = when {
|
||||||
@@ -67,6 +67,9 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
|
|||||||
val childRangeAfter = childRangeBefore.withoutLastStatement()
|
val childRangeAfter = childRangeBefore.withoutLastStatement()
|
||||||
|
|
||||||
val elvis = factory.createExpressionByPattern("$0 ?: $1", initializer, ifNullExpr) as KtBinaryExpression
|
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)
|
val newElvis = initializer.replaced(elvis)
|
||||||
element.delete()
|
element.delete()
|
||||||
|
|
||||||
@@ -82,15 +85,25 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
|
|||||||
private data class Data(
|
private data class Data(
|
||||||
val initializer: KtExpression,
|
val initializer: KtExpression,
|
||||||
val declaration: KtVariableDeclaration,
|
val declaration: KtVariableDeclaration,
|
||||||
val ifNullExpression: KtExpression
|
val ifNullExpression: KtExpression,
|
||||||
|
val typeChecked: KtTypeReference? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun calcData(ifExpression: KtIfExpression): Data? {
|
private fun calcData(ifExpression: KtIfExpression): Data? {
|
||||||
if (ifExpression.`else` != null) return null
|
if (ifExpression.`else` != null) return null
|
||||||
|
|
||||||
val binaryExpression = ifExpression.condition as? KtBinaryExpression ?: return null
|
val operationExpression = ifExpression.condition as? KtOperationExpression ?: return null
|
||||||
if (binaryExpression.operationToken != KtTokens.EQEQ) return null
|
val value = when (operationExpression) {
|
||||||
val value = binaryExpression.expressionComparedToNull() as? KtNameReferenceExpression ?: return null
|
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
|
if (ifExpression.parent !is KtBlockExpression) return null
|
||||||
val prevStatement = ifExpression.siblings(forward = false, withItself = false)
|
val prevStatement = ifExpression.siblings(forward = false, withItself = false)
|
||||||
@@ -99,13 +112,14 @@ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfE
|
|||||||
if (prevStatement.nameAsName != value.getReferencedNameAsName()) return null
|
if (prevStatement.nameAsName != value.getReferencedNameAsName()) return null
|
||||||
val initializer = prevStatement.initializer ?: return null
|
val initializer = prevStatement.initializer ?: return null
|
||||||
val then = ifExpression.then ?: return null
|
val then = ifExpression.then ?: return null
|
||||||
|
val typeReference = (operationExpression as? KtIsExpression)?.typeReference
|
||||||
|
|
||||||
if (then is KtBlockExpression) {
|
if (then is KtBlockExpression) {
|
||||||
val statement = then.statements.singleOrNull() ?: return null
|
val statement = then.statements.singleOrNull() ?: return null
|
||||||
return Data(initializer, prevStatement, statement)
|
return Data(initializer, prevStatement, statement, typeReference)
|
||||||
}
|
}
|
||||||
else {
|
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(ConvertToExpressionBodyIntention(convertEmptyToUnit = false)) { it is KtPropertyAccessor }
|
||||||
registerIntentionBasedProcessing(IfThenToSafeAccessIntention())
|
registerIntentionBasedProcessing(IfThenToSafeAccessIntention())
|
||||||
registerIntentionBasedProcessing(IfThenToElvisIntention())
|
registerIntentionBasedProcessing(IfThenToElvisIntention())
|
||||||
registerIntentionBasedProcessing(IfNullToElvisIntention())
|
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
|
||||||
registerIntentionBasedProcessing(SimplifyNegatedBinaryExpressionIntention())
|
registerIntentionBasedProcessing(SimplifyNegatedBinaryExpressionIntention())
|
||||||
registerIntentionBasedProcessing(ReplaceGetOrSetIntention(), additionalChecker = ReplaceGetOrSetInspection.additionalChecker)
|
registerIntentionBasedProcessing(ReplaceGetOrSetIntention(), additionalChecker = ReplaceGetOrSetInspection.additionalChecker)
|
||||||
registerIntentionBasedProcessing(AddOperatorModifierIntention())
|
registerIntentionBasedProcessing(AddOperatorModifierIntention())
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
org.jetbrains.kotlin.idea.intentions.IfNullToElvisIntention
|
org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(arg: Any?) {
|
||||||
|
val n = arg
|
||||||
|
if (<caret>n !is Int) return
|
||||||
|
}
|
||||||
@@ -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) {
|
fun foo(p: List<String?>, b: Boolean) {
|
||||||
var v = p[0]
|
var v = p[0]
|
||||||
@@ -6,4 +6,4 @@ fun foo(p: List<String?>, b: Boolean) {
|
|||||||
if (b) v = null
|
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) {
|
fun foo(p: List<String?>, b: Boolean) {
|
||||||
var v = p[0]
|
var v = p[0]
|
||||||
<caret>if (v == null) return
|
<caret>if (v == null) return
|
||||||
if (b) v = null
|
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);
|
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")
|
@TestMetadata("OtherVar1.kt")
|
||||||
public void testOtherVar1() throws Exception {
|
public void testOtherVar1() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/ifNullToElvis/OtherVar1.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/ifNullToElvis/OtherVar1.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user