Introduce Parameter: Remove parameters which become unused after occurrence replacement
This commit is contained in:
-4
@@ -33,10 +33,6 @@ public class JetMutableMethodDescriptor(val original: JetMethodDescriptor): JetM
|
|||||||
parameters.add(parameter)
|
parameters.add(parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun setParameter(index: Int, parameter: JetParameterInfo) {
|
|
||||||
parameters[index] = parameter
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun removeParameter(index: Int) {
|
public fun removeParameter(index: Int) {
|
||||||
parameters.remove(index)
|
parameters.remove(index)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-6
@@ -83,13 +83,25 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
private val LOG = Logger.getInstance(javaClass<KotlinInplaceParameterIntroducer>())
|
private val LOG = Logger.getInstance(javaClass<KotlinInplaceParameterIntroducer>())
|
||||||
}
|
}
|
||||||
|
|
||||||
object PreviewDecorator {
|
enum class PreviewDecorator {
|
||||||
protected val textAttributes: TextAttributes = with(TextAttributes()) {
|
FOR_ADD: PreviewDecorator() {
|
||||||
setEffectType(EffectType.ROUNDED_BOX)
|
override val textAttributes: TextAttributes = with(TextAttributes()) {
|
||||||
setEffectColor(JBColor.RED)
|
setEffectType(EffectType.ROUNDED_BOX)
|
||||||
this
|
setEffectColor(JBColor.RED)
|
||||||
|
this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FOR_REMOVAL: PreviewDecorator() {
|
||||||
|
override val textAttributes: TextAttributes = with(TextAttributes()) {
|
||||||
|
setEffectType(EffectType.STRIKEOUT)
|
||||||
|
setEffectColor(Color.BLACK)
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract val textAttributes: TextAttributes
|
||||||
|
|
||||||
fun applyToRange(range: TextRange, markupModel: MarkupModel) {
|
fun applyToRange(range: TextRange, markupModel: MarkupModel) {
|
||||||
markupModel.addRangeHighlighter(range.getStartOffset(),
|
markupModel.addRangeHighlighter(range.getStartOffset(),
|
||||||
range.getEndOffset(),
|
range.getEndOffset(),
|
||||||
@@ -104,6 +116,7 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
|
|
||||||
private fun updatePreview(currentName: String?, currentType: String?) {
|
private fun updatePreview(currentName: String?, currentType: String?) {
|
||||||
with (descriptor) {
|
with (descriptor) {
|
||||||
|
val rangesToRemove = ArrayList<TextRange>()
|
||||||
var addedRange: TextRange? = null
|
var addedRange: TextRange? = null
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
|
|
||||||
@@ -129,6 +142,9 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
if (parameter == addedParameter) {
|
if (parameter == addedParameter) {
|
||||||
addedRange = range
|
addedRange = range
|
||||||
}
|
}
|
||||||
|
else if (parameter in parametersToRemove) {
|
||||||
|
rangesToRemove.add(range)
|
||||||
|
}
|
||||||
|
|
||||||
if (i < parameters.lastIndex) {
|
if (i < parameters.lastIndex) {
|
||||||
builder.append(", ")
|
builder.append(", ")
|
||||||
@@ -145,7 +161,8 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
|
|
||||||
val markupModel = DocumentMarkupModel.forDocument(document, myProject, true)
|
val markupModel = DocumentMarkupModel.forDocument(document, myProject, true)
|
||||||
markupModel.removeAllHighlighters()
|
markupModel.removeAllHighlighters()
|
||||||
addedRange?.let { PreviewDecorator.applyToRange(it, markupModel) }
|
rangesToRemove.forEach { PreviewDecorator.FOR_REMOVAL.applyToRange(it, markupModel) }
|
||||||
|
addedRange?.let { PreviewDecorator.FOR_ADD.applyToRange(it, markupModel) }
|
||||||
}
|
}
|
||||||
revalidate()
|
revalidate()
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-11
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.TextRange
|
|||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
@@ -35,18 +36,26 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.KotlinIntroduceHandlerBase
|
import org.jetbrains.kotlin.idea.refactoring.introduce.KotlinIntroduceHandlerBase
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetParent
|
import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetParent
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHintByKey
|
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHintByKey
|
||||||
|
import org.jetbrains.kotlin.idea.search.usagesSearch.DefaultSearchHelper
|
||||||
|
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchTarget
|
||||||
|
import org.jetbrains.kotlin.idea.search.usagesSearch.search
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.idea.util.approximateWithResolvableType
|
import org.jetbrains.kotlin.idea.util.approximateWithResolvableType
|
||||||
|
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiUnifier
|
||||||
|
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
|
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getValueParameters
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils
|
import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import java.util.Collections
|
||||||
import kotlin.test.fail
|
import kotlin.test.fail
|
||||||
|
|
||||||
public data class IntroduceParameterDescriptor(
|
public data class IntroduceParameterDescriptor(
|
||||||
@@ -54,7 +63,8 @@ public data class IntroduceParameterDescriptor(
|
|||||||
val callable: JetNamedDeclaration,
|
val callable: JetNamedDeclaration,
|
||||||
val callableDescriptor: FunctionDescriptor,
|
val callableDescriptor: FunctionDescriptor,
|
||||||
val addedParameter: JetParameter,
|
val addedParameter: JetParameter,
|
||||||
val parameterType: JetType
|
val parameterType: JetType,
|
||||||
|
val parametersToRemove: List<JetParameter>
|
||||||
) {
|
) {
|
||||||
val valVar: JetValVar
|
val valVar: JetValVar
|
||||||
|
|
||||||
@@ -81,10 +91,13 @@ public data class IntroduceParameterDescriptor(
|
|||||||
fun IntroduceParameterDescriptor.performRefactoring() {
|
fun IntroduceParameterDescriptor.performRefactoring() {
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
JetPsiUtil.deleteElementWithDelimiters(addedParameter)
|
JetPsiUtil.deleteElementWithDelimiters(addedParameter)
|
||||||
|
|
||||||
val config = object: JetChangeSignatureConfiguration {
|
val config = object: JetChangeSignatureConfiguration {
|
||||||
override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor {
|
override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor {
|
||||||
return originalDescriptor.modify {
|
return originalDescriptor.modify {
|
||||||
|
val parameters = callable.getValueParameters()
|
||||||
|
parametersToRemove.map { parameters.indexOf(it) }.sortDescending().forEach { removeParameter(it) }
|
||||||
|
|
||||||
val parameterInfo = JetParameterInfo(name = addedParameter.getName()!!,
|
val parameterInfo = JetParameterInfo(name = addedParameter.getName()!!,
|
||||||
type = parameterType,
|
type = parameterType,
|
||||||
defaultValueForParameter = JetPsiUtil.deparenthesize(originalExpression),
|
defaultValueForParameter = JetPsiUtil.deparenthesize(originalExpression),
|
||||||
@@ -103,7 +116,7 @@ fun IntroduceParameterDescriptor.performRefactoring() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase() {
|
public class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase() {
|
||||||
public fun invoke(project: Project, editor: Editor, expression: JetExpression, targetParent: JetNamedDeclaration) {
|
fun invoke(project: Project, editor: Editor, expression: JetExpression, targetParent: JetNamedDeclaration) {
|
||||||
val psiFactory = JetPsiFactory(project)
|
val psiFactory = JetPsiFactory(project)
|
||||||
|
|
||||||
val parameterList = targetParent.getValueParameterList()
|
val parameterList = targetParent.getValueParameterList()
|
||||||
@@ -119,15 +132,25 @@ public class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase() {
|
|||||||
val expressionType = context[BindingContext.EXPRESSION_TYPE, expression] ?: KotlinBuiltIns.getInstance().getAnyType()
|
val expressionType = context[BindingContext.EXPRESSION_TYPE, expression] ?: KotlinBuiltIns.getInstance().getAnyType()
|
||||||
val parameterType = expressionType.approximateWithResolvableType(JetScopeUtils.getResolutionScope(targetParent, context), false)
|
val parameterType = expressionType.approximateWithResolvableType(JetScopeUtils.getResolutionScope(targetParent, context), false)
|
||||||
|
|
||||||
val validatorContainer =
|
val body = when (targetParent) {
|
||||||
when (targetParent) {
|
is JetFunction -> targetParent.getBodyExpression()
|
||||||
is JetFunction -> targetParent.getBodyExpression()
|
is JetClass -> targetParent.getBody()
|
||||||
is JetClass -> targetParent.getBody()
|
else -> null
|
||||||
else -> null
|
} ?: throw AssertionError("Body element is not found: ${JetPsiUtil.getElementTextWithContext(targetParent)}")
|
||||||
} ?: throw AssertionError("Body element is not found: ${JetPsiUtil.getElementTextWithContext(targetParent)}")
|
val nameValidator = JetNameValidatorImpl(body, null, JetNameValidatorImpl.Target.PROPERTIES)
|
||||||
val nameValidator = JetNameValidatorImpl(validatorContainer, null, JetNameValidatorImpl.Target.PROPERTIES)
|
|
||||||
val suggestedNames = linkedSetOf(*JetNameSuggester.suggestNames(parameterType, nameValidator, "p"))
|
val suggestedNames = linkedSetOf(*JetNameSuggester.suggestNames(parameterType, nameValidator, "p"))
|
||||||
|
|
||||||
|
val parametersToRemove = (parameterList?.getParameters() ?: Collections.emptyList()).filter {
|
||||||
|
if (!it.hasValOrVarNode()) {
|
||||||
|
val usages = DefaultSearchHelper<JetParameter>()
|
||||||
|
.newRequest(UsagesSearchTarget(element = it))
|
||||||
|
.search()
|
||||||
|
.toList()
|
||||||
|
usages.isNotEmpty() && usages.all { expression.isAncestor(it.getElement()) }
|
||||||
|
}
|
||||||
|
else false
|
||||||
|
}
|
||||||
|
|
||||||
project.executeCommand(INTRODUCE_PARAMETER) {
|
project.executeCommand(INTRODUCE_PARAMETER) {
|
||||||
val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(parameterType)
|
val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(parameterType)
|
||||||
val newParameter = psiFactory.createParameter("${suggestedNames.first()}: $renderedType")
|
val newParameter = psiFactory.createParameter("${suggestedNames.first()}: $renderedType")
|
||||||
@@ -160,7 +183,8 @@ public class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase() {
|
|||||||
targetParent,
|
targetParent,
|
||||||
functionDescriptor,
|
functionDescriptor,
|
||||||
addedParameter,
|
addedParameter,
|
||||||
parameterType)
|
parameterType,
|
||||||
|
parametersToRemove)
|
||||||
if (editor.getSettings().isVariableInplaceRenameEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
|
if (editor.getSettings().isVariableInplaceRenameEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||||
with(PsiDocumentManager.getInstance(project)) {
|
with(PsiDocumentManager.getInstance(project)) {
|
||||||
commitDocument(editor.getDocument())
|
commitDocument(editor.getDocument())
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// TARGET:
|
||||||
|
class A(val a: Int, s: String) {
|
||||||
|
fun foo() = (<selection>a + 1</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val t = A(1, "2").a
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// TARGET:
|
||||||
|
class A(val a: Int, s: String, val i: Int = a + 1) {
|
||||||
|
fun foo() = (i) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val t = A(1, "2").a
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// TARGET:
|
||||||
|
class A(val a: Int, s: String) {
|
||||||
|
fun foo() = (<selection>a + 1</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1, "2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// TARGET:
|
||||||
|
class A(val a: Int, s: String, val i: Int = a + 1) {
|
||||||
|
fun foo() = (i) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1, "2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// TARGET:
|
||||||
|
class A(val a: Int, s: String) {
|
||||||
|
val x = a + 2
|
||||||
|
|
||||||
|
fun foo() = (<selection>a + 1</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1, "2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// TARGET:
|
||||||
|
class A(val a: Int, s: String, val i: Int = a + 1) {
|
||||||
|
val x = a + 2
|
||||||
|
|
||||||
|
fun foo() = (i) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
A(1, "2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(a: Int, s: String, b: Int): Int {
|
||||||
|
return (<selection>a + b</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1, "2", 3)
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(s: String, i: Int = a + b): Int {
|
||||||
|
return (i) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo("2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(a: Int, s: String): Int {
|
||||||
|
return (<selection>a + 1</selection>) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1, "2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(s: String, i: Int = a + 1): Int {
|
||||||
|
return (i) * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo("2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(a: Int, s: String): Int {
|
||||||
|
return (<selection>a + 1</selection>) * a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1, "2")
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(a: Int, s: String, i: Int = a + 1): Int {
|
||||||
|
return (i) * a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(1, "2")
|
||||||
|
}
|
||||||
+36
@@ -2215,12 +2215,48 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doIntroduceParameterTest(fileName);
|
doIntroduceParameterTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classParameterUsedOutside.kt")
|
||||||
|
public void testClassParameterUsedOutside() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classParameterUsedOutside.kt");
|
||||||
|
doIntroduceParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classUnusedParameter.kt")
|
||||||
|
public void testClassUnusedParameter() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classUnusedParameter.kt");
|
||||||
|
doIntroduceParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classUsedParameter.kt")
|
||||||
|
public void testClassUsedParameter() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classUsedParameter.kt");
|
||||||
|
doIntroduceParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("defaultValueInParens.kt")
|
@TestMetadata("defaultValueInParens.kt")
|
||||||
public void testDefaultValueInParens() throws Exception {
|
public void testDefaultValueInParens() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/defaultValueInParens.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/defaultValueInParens.kt");
|
||||||
doIntroduceParameterTest(fileName);
|
doIntroduceParameterTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionMultipleUnusedParameters.kt")
|
||||||
|
public void testFunctionMultipleUnusedParameters() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionMultipleUnusedParameters.kt");
|
||||||
|
doIntroduceParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionUnusedParameter.kt")
|
||||||
|
public void testFunctionUnusedParameter() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionUnusedParameter.kt");
|
||||||
|
doIntroduceParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionUsedParameter.kt")
|
||||||
|
public void testFunctionUsedParameter() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionUsedParameter.kt");
|
||||||
|
doIntroduceParameterTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("functionWithApproximatedType.kt")
|
@TestMetadata("functionWithApproximatedType.kt")
|
||||||
public void testFunctionWithApproximatedType() throws Exception {
|
public void testFunctionWithApproximatedType() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionWithApproximatedType.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionWithApproximatedType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user