DeprecatedSymbolUsageFix: more correct generation of "let" for safe call
This commit is contained in:
@@ -45,11 +45,10 @@ public class JetNameSuggester {
|
||||
}
|
||||
|
||||
private static void addName(ArrayList<String> result, @Nullable String name, JetNameValidator validator) {
|
||||
if (name == null) return;
|
||||
if ("class".equals(name)) name = "clazz";
|
||||
if (!isIdentifier(name)) return;
|
||||
String newName = validator.validateName(name);
|
||||
if (newName == null) return;
|
||||
result.add(newName);
|
||||
result.add(validator.validateName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,8 +92,13 @@ public class JetNameSuggester {
|
||||
}
|
||||
|
||||
public static @NotNull String[] suggestNamesForExpression(@NotNull JetExpression expression, @NotNull JetNameValidator validator) {
|
||||
return suggestNamesForExpression(expression, validator, null);
|
||||
}
|
||||
|
||||
public static @NotNull String[] suggestNamesForExpression(@NotNull JetExpression expression, @NotNull JetNameValidator validator, @Nullable String defaultName) {
|
||||
ArrayList<String> result = new ArrayList<String>();
|
||||
addNamesForExpression(result, expression, validator);
|
||||
if (result.isEmpty()) addName(result, defaultName, validator);
|
||||
return ArrayUtil.toStringArray(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.JetNameValidator
|
||||
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
@@ -97,9 +99,9 @@ public class DeprecatedSymbolUsageFix(
|
||||
val bindingContext = element.analyze()
|
||||
val resolvedCall = element.getResolvedCall(bindingContext)!!
|
||||
val descriptor = resolvedCall.getResultingDescriptor()
|
||||
val callElement = resolvedCall.getCall().getCallElement() as JetExpression
|
||||
val qualifiedExpression = callElement.getParent() as? JetQualifiedExpression
|
||||
val expressionToReplace = qualifiedExpression ?: callElement
|
||||
val callExpression = resolvedCall.getCall().getCallElement() as JetExpression
|
||||
val qualifiedExpression = callExpression.getParent() as? JetQualifiedExpression
|
||||
val expressionToReplace = qualifiedExpression ?: callExpression
|
||||
|
||||
val USER_CODE_KEY = Key<Unit>("USER_CODE")
|
||||
|
||||
@@ -125,8 +127,19 @@ public class DeprecatedSymbolUsageFix(
|
||||
}
|
||||
|
||||
if (expressionToReplace.isUsedAsExpression(bindingContext)) {
|
||||
expression = psiFactory.createExpressionByPattern("$0?.let { $1 }", explicitReceiver!!, expression)
|
||||
thisReplacement = psiFactory.createExpression("it")
|
||||
if (!isNameUsed("it", callExpression, expression)) {
|
||||
expression = psiFactory.createExpressionByPattern("$0?.let { $1 }", explicitReceiver!!, expression)
|
||||
thisReplacement = psiFactory.createExpression("it")
|
||||
}
|
||||
else {
|
||||
val nameValidator = object : JetNameValidator() {
|
||||
override fun validateInner(name: String) = !isNameUsed(name, callExpression, expression)
|
||||
}
|
||||
val name = JetNameSuggester.suggestNamesForExpression(explicitReceiver!!, nameValidator, "t").first()
|
||||
val nameInCode = IdeDescriptorRenderers.SOURCE_CODE.renderName(Name.identifier(name))
|
||||
expression = psiFactory.createExpressionByPattern("$0?.let { $nameInCode -> $1 }", explicitReceiver, expression)
|
||||
thisReplacement = psiFactory.createExpression(nameInCode)
|
||||
}
|
||||
}
|
||||
else {
|
||||
expression = psiFactory.createExpressionByPattern("if ($0 != null) { $1 }", explicitReceiver!!, expression)
|
||||
@@ -301,6 +314,24 @@ public class DeprecatedSymbolUsageFix(
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNameUsed(name: String, vararg inExpressions: JetExpression): Boolean {
|
||||
var result = false
|
||||
inExpressions.forEach {
|
||||
it.accept(object : JetVisitorVoid(){
|
||||
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||
if (expression.getReferencedName() == name) {
|
||||
result = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitJetElement(element: JetElement) {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
companion object : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val nameExpression = diagnostic.getPsiElement() as? JetSimpleNameExpression ?: return null
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace with 'c.newFun(this)'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("c.newFun(this)"))
|
||||
fun oldFun(c: Char): Char = c.newFun(this)
|
||||
}
|
||||
|
||||
fun Char.newFun(x: X): Char = this
|
||||
|
||||
fun foo(x: X?, p: Boolean, s: String) {
|
||||
val chars = s.filter {
|
||||
val v = if (p)
|
||||
x?.<caret>oldFun(it)
|
||||
else
|
||||
null
|
||||
v != 'a'
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// "Replace with 'c.newFun(this)'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("c.newFun(this)"))
|
||||
fun oldFun(c: Char): Char = c.newFun(this)
|
||||
}
|
||||
|
||||
fun Char.newFun(x: X): Char = this
|
||||
|
||||
fun foo(x: X?, p: Boolean, s: String) {
|
||||
val chars = s.filter {
|
||||
val v = if (p)
|
||||
x?.let { x -> it.newFun(x) }
|
||||
else
|
||||
null
|
||||
v != 'a'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with 's.filter { it != c }'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("s.filter { it != c }"))
|
||||
fun oldFun(s: String): CharSequence = s.filter { it != c }
|
||||
|
||||
val c = 'x'
|
||||
}
|
||||
|
||||
fun foo(x: X?, s: String) {
|
||||
bar(x?.<caret>oldFun(s))
|
||||
}
|
||||
|
||||
fun bar(s: CharSequence?){}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Replace with 's.filter { it != c }'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("s.filter { it != c }"))
|
||||
fun oldFun(s: String): CharSequence = s.filter { it != c }
|
||||
|
||||
val c = 'x'
|
||||
}
|
||||
|
||||
fun foo(x: X?, s: String) {
|
||||
bar(x?.<caret>let { x -> s.filter { it != x.c } })
|
||||
}
|
||||
|
||||
fun bar(s: CharSequence?){}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace with 'c1.newFun(this, c2)'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("c1.newFun(this, c2)"))
|
||||
fun oldFun(c1: Char, c2: Char): Char = c1.newFun(this, c2)
|
||||
|
||||
val c: Char = 'a'
|
||||
}
|
||||
|
||||
fun Char.newFun(x: X, c: Char): Char = this
|
||||
|
||||
fun foo(s: String, x: X) {
|
||||
val chars = s.filter {
|
||||
O.x?.<caret>oldFun(it, x.c) != 'a'
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
var x: X? = null
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// "Replace with 'c1.newFun(this, c2)'" "true"
|
||||
|
||||
class X {
|
||||
@deprecated("", ReplaceWith("c1.newFun(this, c2)"))
|
||||
fun oldFun(c1: Char, c2: Char): Char = c1.newFun(this, c2)
|
||||
|
||||
val c: Char = 'a'
|
||||
}
|
||||
|
||||
fun Char.newFun(x: X, c: Char): Char = this
|
||||
|
||||
fun foo(s: String, x: X) {
|
||||
val chars = s.filter {
|
||||
O.x?.<caret>let { x1 -> it.newFun(x1, x.c) } != 'a'
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
var x: X? = null
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// "Replace with 'c1.newFun(this, c2)'" "true"
|
||||
|
||||
class X(val c: Char) {
|
||||
@deprecated("", ReplaceWith("c1.newFun(this, c2)"))
|
||||
fun oldFun(c1: Char, c2: Char): Char = c1.newFun(this, c2)
|
||||
}
|
||||
|
||||
fun Char.newFun(x: X, c: Char): Char = this
|
||||
|
||||
fun foo(s: String, t: X) {
|
||||
val chars = s.filter {
|
||||
(X('a') + X('b'))?.<caret>oldFun(it, t.c) != 'a'
|
||||
}
|
||||
}
|
||||
|
||||
fun X.plus(x: X): X? = null
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with 'c1.newFun(this, c2)'" "true"
|
||||
|
||||
class X(val c: Char) {
|
||||
@deprecated("", ReplaceWith("c1.newFun(this, c2)"))
|
||||
fun oldFun(c1: Char, c2: Char): Char = c1.newFun(this, c2)
|
||||
}
|
||||
|
||||
fun Char.newFun(x: X, c: Char): Char = this
|
||||
|
||||
fun foo(s: String, t: X) {
|
||||
val chars = s.filter {
|
||||
(X('a') + X('b'))?.let { t1 -> it.newFun(t1, t.c) } != 'a'
|
||||
}
|
||||
}
|
||||
|
||||
fun X.plus(x: X): X? = null
|
||||
@@ -2896,6 +2896,30 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("changeThisSafeCallWithValue1Runtime.kt")
|
||||
public void testChangeThisSafeCallWithValue1Runtime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValue1Runtime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("changeThisSafeCallWithValue2Runtime.kt")
|
||||
public void testChangeThisSafeCallWithValue2Runtime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValue2Runtime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("changeThisSafeCallWithValue3Runtime.kt")
|
||||
public void testChangeThisSafeCallWithValue3Runtime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValue3Runtime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("changeThisSafeCallWithValue4Runtime.kt")
|
||||
public void testChangeThisSafeCallWithValue4Runtime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValue4Runtime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("changeThisSafeCallWithValueRuntime.kt")
|
||||
public void testChangeThisSafeCallWithValueRuntime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/changeThisSafeCallWithValueRuntime.kt");
|
||||
|
||||
Reference in New Issue
Block a user