"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"/>
|
||||
|
||||
<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"
|
||||
|
||||
+23
-9
@@ -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
@@ -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) {
|
||||
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");
|
||||
|
||||
Reference in New Issue
Block a user