Constructor usages are replaced too

This commit is contained in:
Valentin Kipyatkov
2015-09-01 22:43:38 +03:00
parent de13e23a0a
commit 366204da85
9 changed files with 117 additions and 6 deletions
@@ -18,17 +18,19 @@ package org.jetbrains.kotlin.idea.quickfix.replaceWith
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetNameReferenceExpression
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetUserType
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
class ClassUsageReplacementStrategy(
private val replacement: JetUserType
) : UsageReplacementStrategy {
private val factory = JetPsiFactory(replacement)
private val qualifierAsExpression = replacement.qualifier?.let { factory.createExpression(it.text) }
override fun createReplacer(usage: JetSimpleNameExpression): (() -> JetElement)? {
if (usage !is JetNameReferenceExpression) return null
if (replacement.referenceExpression == null) return null
val parent = usage.parent
when (parent) {
@@ -39,7 +41,31 @@ class ClassUsageReplacementStrategy(
} //TODO: type arguments and type arguments of outer class are lost
}
is JetCallExpression -> {
if (usage != parent.calleeExpression) return null
return { replaceConstructorCall(parent) }
}
else -> return null //TODO
}
}
private fun replaceConstructorCall(callExpression: JetCallExpression): JetElement {
callExpression.calleeExpression!!.replace(replacement.referenceExpression!!)
val expressionToReplace = callExpression.getQualifiedExpressionForSelectorOrThis()
val newExpression = if (qualifierAsExpression != null)
factory.createExpressionByPattern("$0.$1", qualifierAsExpression, callExpression)
else
callExpression
val result = if (expressionToReplace != newExpression) {
expressionToReplace.replaced(newExpression)
}
else {
expressionToReplace
}
return ShortenReferences.DEFAULT.process(result)
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.quickfix.replaceWith
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.JetElement
@@ -32,10 +33,16 @@ interface UsageReplacementStrategy {
fun build(element: JetSimpleNameExpression, replaceWith: ReplaceWith): UsageReplacementStrategy? {
val resolutionFacade = element.getResolutionFacade()
val bindingContext = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL)
val target = element.mainReference.resolveToDescriptors(bindingContext).singleOrNull() ?: return null
var target = element.mainReference.resolveToDescriptors(bindingContext).singleOrNull() ?: return null
var replacePatternFromSymbol = DeprecatedSymbolUsageFixBase.replaceWithPattern(target, resolutionFacade.project)
if (replacePatternFromSymbol == null && target is ConstructorDescriptor) {
target = target.containingDeclaration
replacePatternFromSymbol = DeprecatedSymbolUsageFixBase.replaceWithPattern(target, resolutionFacade.project)
}
// check that ReplaceWith hasn't changed
if (DeprecatedSymbolUsageFixBase.replaceWithPattern(target, resolutionFacade.project) != replaceWith) return null
if (replacePatternFromSymbol != replaceWith) return null
when (target) {
is CallableDescriptor -> {
@@ -0,0 +1,10 @@
// "Replace with 'NewClass'" "true"
@deprecated("", ReplaceWith("NewClass"))
class OldClass(p: Int)
class NewClass(p: Int)
fun foo() {
<caret>OldClass(1)
}
@@ -0,0 +1,10 @@
// "Replace with 'NewClass'" "true"
@deprecated("", ReplaceWith("NewClass"))
class OldClass(p: Int)
class NewClass(p: Int)
fun foo() {
NewClass(1)
}
@@ -0,0 +1,8 @@
// "Replace with 'java.util.Random'" "true"
@deprecated("", ReplaceWith("java.util.Random"))
class OldClass
fun foo() {
<caret>OldClass(1)
}
@@ -0,0 +1,10 @@
import java.util.Random
// "Replace with 'java.util.Random'" "true"
@deprecated("", ReplaceWith("java.util.Random"))
class OldClass
fun foo() {
Random(1)
}
@@ -0,0 +1,11 @@
// "Replace with 'NewClass'" "true"
package ppp
@deprecated("", ReplaceWith("NewClass"))
class OldClass(p: Int)
class NewClass(p: Int)
fun foo() {
ppp.<caret>OldClass(1)
}
@@ -0,0 +1,11 @@
// "Replace with 'NewClass'" "true"
package ppp
@deprecated("", ReplaceWith("NewClass"))
class OldClass(p: Int)
class NewClass(p: Int)
fun foo() {
NewClass(1)
}
@@ -3312,6 +3312,24 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/classUsages"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("constructorUsage1.kt")
public void testConstructorUsage1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage1.kt");
doTest(fileName);
}
@TestMetadata("constructorUsage2.kt")
public void testConstructorUsage2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage2.kt");
doTest(fileName);
}
@TestMetadata("constructorUsage3.kt")
public void testConstructorUsage3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage3.kt");
doTest(fileName);
}
@TestMetadata("imports.kt")
public void testImports() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/imports.kt");