Introduce Parameter: Reimplement in-place refactoring using AbstractInplaceIntroducer
This simplifies implementation and fixes bug with unnecessarily detailed command history available through undo/redo
This commit is contained in:
+133
-166
@@ -19,11 +19,7 @@ package org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter
|
|||||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.EditorFactory
|
import com.intellij.openapi.editor.RangeMarker
|
||||||
import com.intellij.openapi.editor.colors.EditorColors
|
|
||||||
import com.intellij.openapi.editor.event.DocumentAdapter
|
|
||||||
import com.intellij.openapi.editor.event.DocumentEvent
|
|
||||||
import com.intellij.openapi.editor.ex.EditorEx
|
|
||||||
import com.intellij.openapi.editor.impl.DocumentMarkupModel
|
import com.intellij.openapi.editor.impl.DocumentMarkupModel
|
||||||
import com.intellij.openapi.editor.markup.EffectType
|
import com.intellij.openapi.editor.markup.EffectType
|
||||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
||||||
@@ -31,50 +27,47 @@ import com.intellij.openapi.editor.markup.MarkupModel
|
|||||||
import com.intellij.openapi.editor.markup.TextAttributes
|
import com.intellij.openapi.editor.markup.TextAttributes
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiAnchor
|
||||||
import com.intellij.ui.DottedBorder
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer
|
||||||
import com.intellij.ui.JBColor
|
import com.intellij.ui.JBColor
|
||||||
import com.intellij.ui.NonFocusableCheckBox
|
import com.intellij.ui.NonFocusableCheckBox
|
||||||
|
import com.intellij.util.ui.FormBuilder
|
||||||
import org.jetbrains.kotlin.idea.JetFileType
|
import org.jetbrains.kotlin.idea.JetFileType
|
||||||
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinInplaceVariableIntroducer
|
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinInplaceVariableIntroducer
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
|
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiRange
|
||||||
|
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
|
||||||
import org.jetbrains.kotlin.idea.util.supertypes
|
import org.jetbrains.kotlin.idea.util.supertypes
|
||||||
import org.jetbrains.kotlin.psi.JetExpression
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.JetParameter
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.psi.JetParameterList
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getValueParameters
|
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.LinkedHashSet
|
import javax.swing.JCheckBox
|
||||||
import javax.swing.BorderFactory
|
|
||||||
import javax.swing.JPanel
|
|
||||||
import javax.swing.border.EmptyBorder
|
|
||||||
import javax.swing.border.LineBorder
|
|
||||||
|
|
||||||
public class KotlinInplaceParameterIntroducer(
|
public class KotlinInplaceParameterIntroducer(
|
||||||
val originalDescriptor: IntroduceParameterDescriptor,
|
val originalDescriptor: IntroduceParameterDescriptor,
|
||||||
val addedParameter: JetParameter,
|
|
||||||
val parameterType: JetType,
|
val parameterType: JetType,
|
||||||
editor: Editor,
|
val suggestedNames: Array<out String>,
|
||||||
project: Project
|
project: Project,
|
||||||
): KotlinInplaceVariableIntroducer<JetParameter>(
|
editor: Editor
|
||||||
addedParameter,
|
): AbstractInplaceIntroducer<JetParameter, JetExpression>(
|
||||||
editor,
|
|
||||||
project,
|
project,
|
||||||
INTRODUCE_PARAMETER,
|
editor,
|
||||||
JetExpression.EMPTY_ARRAY,
|
originalDescriptor.originalRange.elements.single() as JetExpression,
|
||||||
null,
|
null,
|
||||||
false,
|
originalDescriptor.occurrencesToReplace
|
||||||
addedParameter,
|
.map { it.elements.single() as JetExpression }
|
||||||
false,
|
.filterNotNull()
|
||||||
true,
|
.toTypedArray(),
|
||||||
parameterType,
|
INTRODUCE_PARAMETER,
|
||||||
false
|
JetFileType.INSTANCE
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private val LOG = Logger.getInstance(javaClass<KotlinInplaceParameterIntroducer>())
|
private val LOG = Logger.getInstance(javaClass<KotlinInplaceParameterIntroducer>())
|
||||||
@@ -110,9 +103,98 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var descriptor = originalDescriptor
|
private var descriptor = originalDescriptor
|
||||||
private var previewer: EditorEx? = null
|
private var replaceAllCheckBox: JCheckBox? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
val panel = with(FormBuilder.createFormBuilder()) {
|
||||||
|
addComponent(getPreviewComponent())
|
||||||
|
|
||||||
|
val defaultValueCheckBox = NonFocusableCheckBox("Introduce default value")
|
||||||
|
defaultValueCheckBox.setSelected(descriptor.withDefaultValue)
|
||||||
|
defaultValueCheckBox.setMnemonic('d')
|
||||||
|
defaultValueCheckBox.addActionListener {
|
||||||
|
descriptor = descriptor.copy(withDefaultValue = defaultValueCheckBox.isSelected())
|
||||||
|
updateTitle(getVariable())
|
||||||
|
}
|
||||||
|
addComponent(defaultValueCheckBox)
|
||||||
|
|
||||||
|
val occurrenceCount = descriptor.occurrencesToReplace.size()
|
||||||
|
if (occurrenceCount > 1) {
|
||||||
|
val replaceAllCheckBox = NonFocusableCheckBox("Replace all occurrences ($occurrenceCount)")
|
||||||
|
replaceAllCheckBox.setSelected(true)
|
||||||
|
replaceAllCheckBox.setMnemonic('R')
|
||||||
|
addComponent(replaceAllCheckBox)
|
||||||
|
this@KotlinInplaceParameterIntroducer.replaceAllCheckBox = replaceAllCheckBox
|
||||||
|
}
|
||||||
|
|
||||||
|
getPanel()
|
||||||
|
}
|
||||||
|
|
||||||
|
myWholePanel.setLayout(BorderLayout())
|
||||||
|
myWholePanel.add(panel, BorderLayout.CENTER)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getActionName() = "IntroduceParameter"
|
||||||
|
|
||||||
|
override fun checkLocalScope() = descriptor.callable
|
||||||
|
|
||||||
|
override fun getVariable() = originalDescriptor.callable.getValueParameters().lastOrNull()
|
||||||
|
|
||||||
|
override fun suggestNames(replaceAll: Boolean, variable: JetParameter?) = suggestedNames
|
||||||
|
|
||||||
|
override fun createFieldToStartTemplateOn(replaceAll: Boolean, names: Array<out String>): JetParameter? {
|
||||||
|
return runWriteAction {
|
||||||
|
with(descriptor) {
|
||||||
|
val parameterList = callable.getValueParameterList()
|
||||||
|
?: (callable as JetClass).createPrimaryConstructorParameterListIfAbsent()
|
||||||
|
val parameter = JetPsiFactory(myProject).createParameter("${newParameterName}: ${newParameterTypeText}")
|
||||||
|
parameterList.addParameter(parameter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteTemplateField(psiField: JetParameter) {
|
||||||
|
if (psiField.isValid()) {
|
||||||
|
(psiField.getParent() as? JetParameterList)?.removeParameter(psiField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun restoreExpression(
|
||||||
|
containingFile: PsiFile,
|
||||||
|
parameter: JetParameter,
|
||||||
|
marker: RangeMarker,
|
||||||
|
exprText: String
|
||||||
|
): JetExpression? {
|
||||||
|
if (!parameter.isValid()) return null
|
||||||
|
|
||||||
|
val refExpr = containingFile.findElementAt(marker.getStartOffset())?.getNonStrictParentOfType<JetSimpleNameExpression>()
|
||||||
|
?: return null
|
||||||
|
val refName = refExpr.getReferencedName()
|
||||||
|
if (refExpr.getReference()?.resolve() == parameter || parameter.getName() == refName || exprText == refName) {
|
||||||
|
return refExpr.replaced(JetPsiFactory(myProject).createExpression(exprText))
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isReplaceAllOccurrences() = replaceAllCheckBox?.isSelected() ?: true
|
||||||
|
|
||||||
|
override fun setReplaceAllOccurrences(allOccurrences: Boolean) {
|
||||||
|
replaceAllCheckBox?.setSelected(allOccurrences)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getComponent() = myWholePanel
|
||||||
|
|
||||||
|
override fun updateTitle(parameter: JetParameter?) = updateTitle(parameter, null)
|
||||||
|
|
||||||
|
override fun updateTitle(addedParameter: JetParameter?, currentName: String?) {
|
||||||
|
val templateState = TemplateManagerImpl.getTemplateState(myEditor)
|
||||||
|
if (templateState == null || templateState.getTemplate() == null) return
|
||||||
|
|
||||||
|
val currentType = templateState
|
||||||
|
.getVariableValue(KotlinInplaceVariableIntroducer.TYPE_REFERENCE_VARIABLE_NAME)
|
||||||
|
?.getText()
|
||||||
|
|
||||||
private fun updatePreview(currentName: String?, currentType: String?) {
|
|
||||||
with (descriptor) {
|
with (descriptor) {
|
||||||
val rangesToRemove = ArrayList<TextRange>()
|
val rangesToRemove = ArrayList<TextRange>()
|
||||||
var addedRange: TextRange? = null
|
var addedRange: TextRange? = null
|
||||||
@@ -128,6 +210,7 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
val parameterText = if (parameter == addedParameter){
|
val parameterText = if (parameter == addedParameter){
|
||||||
val parameterName = currentName ?: parameter.getName()
|
val parameterName = currentName ?: parameter.getName()
|
||||||
val parameterType = currentType ?: parameter.getTypeReference()!!.getText()
|
val parameterType = currentType ?: parameter.getTypeReference()!!.getText()
|
||||||
|
descriptor = descriptor.copy(newParameterName = parameterName, newParameterTypeText = parameterType)
|
||||||
val modifier = if (valVar != JetValVar.None) "${valVar.name} " else ""
|
val modifier = if (valVar != JetValVar.None) "${valVar.name} " else ""
|
||||||
val defaultValue = if (withDefaultValue) " = ${newArgumentValue.getText()}" else ""
|
val defaultValue = if (withDefaultValue) " = ${newArgumentValue.getText()}" else ""
|
||||||
|
|
||||||
@@ -155,7 +238,7 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
LOG.error("Added parameter not found: ${callable.getElementTextWithContext()}")
|
LOG.error("Added parameter not found: ${callable.getElementTextWithContext()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val document = previewer!!.getDocument()
|
val document = getPreviewEditor().getDocument()
|
||||||
runWriteAction { document.setText(builder.toString()) }
|
runWriteAction { document.setText(builder.toString()) }
|
||||||
|
|
||||||
val markupModel = DocumentMarkupModel.forDocument(document, myProject, true)
|
val markupModel = DocumentMarkupModel.forDocument(document, myProject, true)
|
||||||
@@ -166,145 +249,29 @@ public class KotlinInplaceParameterIntroducer(
|
|||||||
revalidate()
|
revalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAdvertisementActionId() = "IntroduceParameter"
|
override fun saveSettings(variable: JetParameter?) {
|
||||||
|
|
||||||
override fun initPanelControls() {
|
|
||||||
addPanelControl {
|
|
||||||
val previewer = EditorFactory.getInstance().createEditor(EditorFactory.getInstance().createDocument(""),
|
|
||||||
myProject,
|
|
||||||
JetFileType.INSTANCE,
|
|
||||||
true) as EditorEx
|
|
||||||
this.previewer = previewer
|
|
||||||
previewer.setOneLineMode(true)
|
|
||||||
|
|
||||||
with(previewer.getSettings()) {
|
|
||||||
setAdditionalLinesCount(0)
|
|
||||||
setAdditionalColumnsCount(1)
|
|
||||||
setRightMarginShown(false)
|
|
||||||
setFoldingOutlineShown(false)
|
|
||||||
setLineNumbersShown(false)
|
|
||||||
setLineMarkerAreaShown(false)
|
|
||||||
setIndentGuidesShown(false)
|
|
||||||
setVirtualSpace(false)
|
|
||||||
setLineCursorWidth(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
previewer.setHorizontalScrollbarVisible(false)
|
|
||||||
previewer.setVerticalScrollbarVisible(false)
|
|
||||||
previewer.setCaretEnabled(false)
|
|
||||||
|
|
||||||
|
|
||||||
val bg = previewer.getColorsScheme().getColor(EditorColors.CARET_ROW_COLOR)
|
|
||||||
previewer.setBackgroundColor(bg)
|
|
||||||
previewer.setBorder(BorderFactory.createCompoundBorder(DottedBorder(Color.gray), LineBorder(bg, 2)))
|
|
||||||
|
|
||||||
updatePreview(null, null)
|
|
||||||
|
|
||||||
val previewerPanel = JPanel(BorderLayout())
|
|
||||||
previewerPanel.add(previewer.getComponent(), BorderLayout.CENTER)
|
|
||||||
previewerPanel.setBorder(EmptyBorder(2, 2, 6, 2))
|
|
||||||
|
|
||||||
previewerPanel
|
|
||||||
}
|
|
||||||
|
|
||||||
addPanelControl {
|
|
||||||
val defaultValueCheckBox = NonFocusableCheckBox("Introduce default value")
|
|
||||||
defaultValueCheckBox.setSelected(descriptor.withDefaultValue)
|
|
||||||
defaultValueCheckBox.setMnemonic('d')
|
|
||||||
defaultValueCheckBox.addActionListener {
|
|
||||||
descriptor = descriptor.copy(withDefaultValue = defaultValueCheckBox.isSelected())
|
|
||||||
updatePreview(null, null)
|
|
||||||
}
|
|
||||||
defaultValueCheckBox
|
|
||||||
}
|
|
||||||
|
|
||||||
val occurrenceCount = descriptor.occurrencesToReplace.size()
|
|
||||||
if (occurrenceCount > 1) {
|
|
||||||
addPanelControl {
|
|
||||||
val replaceAllCheckBox = NonFocusableCheckBox("Replace all occurrences ($occurrenceCount)")
|
|
||||||
replaceAllCheckBox.setSelected(true)
|
|
||||||
replaceAllCheckBox.setMnemonic('R')
|
|
||||||
replaceAllCheckBox.addActionListener {
|
|
||||||
descriptor = descriptor.copy(
|
|
||||||
occurrencesToReplace = with(originalDescriptor) {
|
|
||||||
if (replaceAllCheckBox.isSelected()) {
|
|
||||||
occurrencesToReplace
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Collections.singletonList(originalOccurrence)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
updatePreview(null, null)
|
|
||||||
}
|
|
||||||
replaceAllCheckBox
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var myDocumentAdapter: DocumentAdapter? = null
|
override fun performIntroduce() {
|
||||||
|
getDescriptorToRefactor(isReplaceAllOccurrences()).performRefactoring()
|
||||||
fun startRefactoring(suggestedNames: LinkedHashSet<String>): Boolean {
|
|
||||||
if (!performInplaceRefactoring(suggestedNames)) return false
|
|
||||||
|
|
||||||
myDocumentAdapter = object : DocumentAdapter() {
|
|
||||||
override fun documentChanged(e: DocumentEvent?) {
|
|
||||||
if (previewer == null) return
|
|
||||||
val templateState = TemplateManagerImpl.getTemplateState(myEditor)
|
|
||||||
if (templateState != null) {
|
|
||||||
val name = templateState.getVariableValue(KotlinInplaceVariableIntroducer.PRIMARY_VARIABLE_NAME)?.getText()
|
|
||||||
val typeRefText = templateState.getVariableValue(KotlinInplaceVariableIntroducer.TYPE_REFERENCE_VARIABLE_NAME)?.getText()
|
|
||||||
updatePreview(name, typeRefText)
|
|
||||||
descriptor = descriptor.copy(newParameterName = name ?: descriptor.newParameterName,
|
|
||||||
newParameterTypeText = typeRefText ?: descriptor.newParameterTypeText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myEditor.getDocument().addDocumentListener(myDocumentAdapter!!)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun finish(success: Boolean) {
|
private fun getDescriptorToRefactor(replaceAll: Boolean): IntroduceParameterDescriptor {
|
||||||
super.finish(success)
|
val originalRange = getExpr().toRange()
|
||||||
myDocumentAdapter?.let { myEditor.getDocument().removeDocumentListener(it) }
|
return descriptor.copy(
|
||||||
}
|
originalRange = originalRange,
|
||||||
|
occurrencesToReplace = if (replaceAll) getOccurrences().map { it.toRange() } else originalRange.singletonList()
|
||||||
override fun checkLocalScope(): PsiElement? {
|
)
|
||||||
return descriptor.callable
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removeAddedParameter() {
|
|
||||||
runWriteAction { (addedParameter.getParent() as JetParameterList).removeParameter(addedParameter) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun performRefactoring(): Boolean {
|
|
||||||
removeAddedParameter()
|
|
||||||
descriptor.performRefactoring()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun performCleanup() {
|
|
||||||
removeAddedParameter()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun releaseResources() {
|
|
||||||
super.releaseResources()
|
|
||||||
previewer?.let {
|
|
||||||
EditorFactory.getInstance().releaseEditor(it)
|
|
||||||
previewer = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun switchToDialogUI() {
|
fun switchToDialogUI() {
|
||||||
stopIntroduce()
|
stopIntroduce(myEditor)
|
||||||
with (originalDescriptor) {
|
KotlinIntroduceParameterDialog(myProject,
|
||||||
KotlinIntroduceParameterDialog(myProject,
|
myEditor,
|
||||||
myEditor,
|
getDescriptorToRefactor(true),
|
||||||
this,
|
myNameSuggestions.toTypedArray(),
|
||||||
myNameSuggestions.copyToArray(),
|
listOf(parameterType) + parameterType.supertypes(),
|
||||||
listOf(parameterType) + parameterType.supertypes(),
|
KotlinIntroduceParameterHelper.Default).show()
|
||||||
KotlinIntroduceParameterHelper.Default).show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+14
-21
@@ -25,11 +25,13 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiReference
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
|
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.runRefactoringWithPostprocessing
|
||||||
import org.jetbrains.kotlin.idea.refactoring.JetNameValidatorImpl
|
import org.jetbrains.kotlin.idea.refactoring.JetNameValidatorImpl
|
||||||
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle
|
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
|
||||||
@@ -133,7 +135,10 @@ fun IntroduceParameterDescriptor.performRefactoring() {
|
|||||||
|
|
||||||
override fun performSilently(affectedFunctions: Collection<PsiElement>): Boolean = true
|
override fun performSilently(affectedFunctions: Collection<PsiElement>): Boolean = true
|
||||||
}
|
}
|
||||||
if (runChangeSignature(callable.getProject(), callableDescriptor, config, callable.analyze(), callable, INTRODUCE_PARAMETER)) {
|
|
||||||
|
val project = callable.getProject();
|
||||||
|
val changeSignature = { runChangeSignature(project, callableDescriptor, config, callable.analyze(), callable, INTRODUCE_PARAMETER) }
|
||||||
|
changeSignature.runRefactoringWithPostprocessing(project, "refactoring.changeSignature") {
|
||||||
occurrencesToReplace.forEach { occurrenceReplacer(it) }
|
occurrencesToReplace.forEach { occurrenceReplacer(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,10 +213,6 @@ public open class KotlinIntroduceParameterHandler(
|
|||||||
|
|
||||||
val parametersUsages = findInternalParameterUsages(targetParent)
|
val parametersUsages = findInternalParameterUsages(targetParent)
|
||||||
|
|
||||||
val psiFactory = JetPsiFactory(project)
|
|
||||||
val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(replacementType)
|
|
||||||
val newParameter = psiFactory.createParameter("${suggestedNames.first()}: $renderedType")
|
|
||||||
|
|
||||||
val forbiddenRanges =
|
val forbiddenRanges =
|
||||||
if (targetParent is JetClass) {
|
if (targetParent is JetClass) {
|
||||||
targetParent.getDeclarations().filter { isObjectOrNonInnerClass(it) }.map { it.getTextRange() }
|
targetParent.getDeclarations().filter { isObjectOrNonInnerClass(it) }.map { it.getTextRange() }
|
||||||
@@ -243,24 +244,16 @@ public open class KotlinIntroduceParameterHandler(
|
|||||||
val isTestMode = ApplicationManager.getApplication().isUnitTestMode()
|
val isTestMode = ApplicationManager.getApplication().isUnitTestMode()
|
||||||
val inplaceIsAvailable = editor.getSettings().isVariableInplaceRenameEnabled() && !isTestMode
|
val inplaceIsAvailable = editor.getSettings().isVariableInplaceRenameEnabled() && !isTestMode
|
||||||
|
|
||||||
val addedParameter = if (inplaceIsAvailable) {
|
|
||||||
runWriteAction {
|
|
||||||
val parameterList = targetParent.getValueParameterList()
|
|
||||||
?: (targetParent as JetClass).createPrimaryConstructorParameterListIfAbsent()
|
|
||||||
parameterList.addParameter(newParameter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else newParameter
|
|
||||||
|
|
||||||
val originalExpression = JetPsiUtil.safeDeparenthesize(expression)
|
val originalExpression = JetPsiUtil.safeDeparenthesize(expression)
|
||||||
|
val psiFactory = JetPsiFactory(project)
|
||||||
val introduceParameterDescriptor =
|
val introduceParameterDescriptor =
|
||||||
helper.configure(
|
helper.configure(
|
||||||
IntroduceParameterDescriptor(
|
IntroduceParameterDescriptor(
|
||||||
originalRange = originalExpression.toRange(),
|
originalRange = originalExpression.toRange(),
|
||||||
callable = targetParent,
|
callable = targetParent,
|
||||||
callableDescriptor = functionDescriptor,
|
callableDescriptor = functionDescriptor,
|
||||||
newParameterName = addedParameter.getName()!!,
|
newParameterName = suggestedNames.first(),
|
||||||
newParameterTypeText = renderedType,
|
newParameterTypeText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(replacementType),
|
||||||
newArgumentValue = originalExpression,
|
newArgumentValue = originalExpression,
|
||||||
withDefaultValue = false,
|
withDefaultValue = false,
|
||||||
parametersUsages = parametersUsages,
|
parametersUsages = parametersUsages,
|
||||||
@@ -282,11 +275,11 @@ public open class KotlinIntroduceParameterHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val introducer = KotlinInplaceParameterIntroducer(introduceParameterDescriptor,
|
val introducer = KotlinInplaceParameterIntroducer(introduceParameterDescriptor,
|
||||||
addedParameter,
|
|
||||||
replacementType,
|
replacementType,
|
||||||
editor,
|
suggestedNames.toTypedArray(),
|
||||||
project)
|
project,
|
||||||
if (introducer.startRefactoring(suggestedNames)) return
|
editor)
|
||||||
|
if (introducer.startInplaceIntroduceTemplate()) return
|
||||||
}
|
}
|
||||||
|
|
||||||
KotlinIntroduceParameterDialog(project,
|
KotlinIntroduceParameterDialog(project,
|
||||||
@@ -300,7 +293,7 @@ public open class KotlinIntroduceParameterHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
|
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
|
||||||
(KotlinInplaceVariableIntroducer.getActiveInstance(editor) as? KotlinInplaceParameterIntroducer)?.let {
|
(AbstractInplaceIntroducer.getActiveIntroducer(editor) as? KotlinInplaceParameterIntroducer)?.let {
|
||||||
it.switchToDialogUI()
|
it.switchToDialogUI()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
|||||||
import com.intellij.lang.java.JavaLanguage
|
import com.intellij.lang.java.JavaLanguage
|
||||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils
|
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.refactoring.listeners.RefactoringEventData
|
||||||
|
import com.intellij.refactoring.listeners.RefactoringEventListener
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter
|
import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter
|
||||||
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
|
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
|
||||||
@@ -568,4 +570,38 @@ fun PsiExpression.j2k(): JetExpression? {
|
|||||||
IdeaResolverForConverter)
|
IdeaResolverForConverter)
|
||||||
val text = j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports
|
val text = j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports
|
||||||
return JetPsiFactory(getProject()).createExpression(text)
|
return JetPsiFactory(getProject()).createExpression(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun (() -> Any).runRefactoringWithPostprocessing(
|
||||||
|
project: Project,
|
||||||
|
targetRefactoringId: String,
|
||||||
|
finishAction: () -> Unit
|
||||||
|
) {
|
||||||
|
val connection = project.getMessageBus().connect()
|
||||||
|
connection.subscribe(RefactoringEventListener.REFACTORING_EVENT_TOPIC,
|
||||||
|
object: RefactoringEventListener {
|
||||||
|
override fun undoRefactoring(refactoringId: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun refactoringStarted(refactoringId: String, beforeData: RefactoringEventData?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun conflictsDetected(refactoringId: String, conflictsData: RefactoringEventData) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun refactoringDone(refactoringId: String, afterData: RefactoringEventData?) {
|
||||||
|
if (refactoringId == targetRefactoringId) {
|
||||||
|
try {
|
||||||
|
finishAction()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
connection.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this()
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user