Replace with safe call: do not add redundant elvis operator

#KT-34432 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-10-18 20:36:59 +09:00
committed by Dmitry Gridin
parent fa0398ffd3
commit e8effe6727
10 changed files with 80 additions and 7 deletions
@@ -46,7 +46,7 @@ abstract class ReplaceCallFix(
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val element = element ?: return
val elvis = elvisOrEmpty(notNullNeeded)
val elvis = element.elvisOrEmpty(notNullNeeded)
val betweenReceiverAndOperation = element.elementsBetweenReceiverAndOperation().joinToString(separator = "") { it.text }
val newExpression = KtPsiFactory(element).createExpressionByPattern(
"$0$betweenReceiverAndOperation$operation$1$elvis",
@@ -54,7 +54,7 @@ abstract class ReplaceCallFix(
element.selectorExpression!!
)
val replacement = element.replace(newExpression)
if (notNullNeeded) {
if (elvis.isNotEmpty()) {
replacement.moveCaretToEnd(editor, project)
}
}
@@ -78,10 +78,10 @@ class ReplaceImplicitReceiverCallFix(
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val element = element ?: return
val elvis = elvisOrEmpty(notNullNeeded)
val elvis = element.elvisOrEmpty(notNullNeeded)
val newExpression = KtPsiFactory(element).createExpressionByPattern("this?.$0$elvis", element)
val replacement = element.replace(newExpression)
if (notNullNeeded) {
if (elvis.isNotEmpty()) {
replacement.moveCaretToEnd(editor, project)
}
}
@@ -21,14 +21,20 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
fun elvisOrEmpty(notNullNeeded: Boolean): String = if (notNullNeeded) "?:" else ""
fun KtExpression.elvisOrEmpty(notNullNeeded: Boolean): String {
if (!notNullNeeded) return ""
val binaryExpression = getStrictParentOfType<KtBinaryExpression>()
return if (binaryExpression?.left == this && binaryExpression.operationToken == KtTokens.ELVIS) "" else "?:"
}
fun KtExpression.shouldHaveNotNullType(): Boolean {
val parent = parent
@@ -43,7 +43,7 @@ class ReplaceInfixOrOperatorCallFix(
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val element = element ?: return
val psiFactory = KtPsiFactory(file)
val elvis = elvisOrEmpty(notNullNeeded)
val elvis = element.elvisOrEmpty(notNullNeeded)
var replacement: PsiElement? = null
when (element) {
is KtArrayAccessExpression -> {
@@ -83,7 +83,7 @@ class ReplaceInfixOrOperatorCallFix(
}
}
}
if (notNullNeeded) {
if (elvis.isNotEmpty()) {
replacement?.moveCaretToEnd(editor, project)
}
}
@@ -0,0 +1,7 @@
// "Replace with safe (?.) call" "true"
// WITH_RUNTIME
fun foo(list: List<String>?) {
var s = ""
s = list[0]<caret> ?: ""
}
@@ -0,0 +1,7 @@
// "Replace with safe (?.) call" "true"
// WITH_RUNTIME
fun foo(list: List<String>?) {
var s = ""
s = list?.get(0) ?: ""
}
+10
View File
@@ -0,0 +1,10 @@
// "Replace with safe (?.) call" "true"
// WITH_RUNTIME
fun main() {
var a = foo()<caret>.length ?: 0
}
fun foo(): String? {
return ""
}
@@ -0,0 +1,10 @@
// "Replace with safe (?.) call" "true"
// WITH_RUNTIME
fun main() {
var a = foo()?.length ?: 0
}
fun foo(): String? {
return ""
}
@@ -0,0 +1,9 @@
// "Replace with safe (this?.) call" "true"
// WITH_RUNTIME
var i = 0
fun foo(a: String?) {
a.run {
i = <caret>length ?: 0
}
}
@@ -0,0 +1,9 @@
// "Replace with safe (this?.) call" "true"
// WITH_RUNTIME
var i = 0
fun foo(a: String?) {
a.run {
i = this?.length ?: 0
}
}
@@ -10901,6 +10901,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
runTest("idea/testData/quickfix/replaceInfixOrOperatorCall/callExpression.kt");
}
@TestMetadata("hasElvis.kt")
public void testHasElvis() throws Exception {
runTest("idea/testData/quickfix/replaceInfixOrOperatorCall/hasElvis.kt");
}
@TestMetadata("list.kt")
public void testList() throws Exception {
runTest("idea/testData/quickfix/replaceInfixOrOperatorCall/list.kt");
@@ -11098,6 +11103,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
runTest("idea/testData/quickfix/replaceWithSafeCall/functionCall.kt");
}
@TestMetadata("hasElvis.kt")
public void testHasElvis() throws Exception {
runTest("idea/testData/quickfix/replaceWithSafeCall/hasElvis.kt");
}
@TestMetadata("hasElvis2.kt")
public void testHasElvis2() throws Exception {
runTest("idea/testData/quickfix/replaceWithSafeCall/hasElvis2.kt");
}
@TestMetadata("invokeOperator.kt")
public void testInvokeOperator() throws Exception {
runTest("idea/testData/quickfix/replaceWithSafeCall/invokeOperator.kt");