Introduce Variable: Reimplement in-place refactoring using AbstractInplaceIntroducer. Extract common superclass AbstractKotlinInplaceIntroducer
This commit is contained in:
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.introduce
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer
|
||||
import com.intellij.refactoring.rename.inplace.InplaceRefactoring
|
||||
import com.intellij.ui.NonFocusableCheckBox
|
||||
import com.intellij.util.ui.FormBuilder
|
||||
import org.jetbrains.kotlin.idea.JetFileType
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import java.awt.BorderLayout
|
||||
|
||||
public abstract class AbstractKotlinInplaceIntroducer<D: JetNamedDeclaration>(
|
||||
expression: JetExpression,
|
||||
occurrences: Array<JetExpression>,
|
||||
title: String,
|
||||
project: Project,
|
||||
editor: Editor
|
||||
): AbstractInplaceIntroducer<D, JetExpression>(project, editor, expression, null, occurrences, title, JetFileType.INSTANCE) {
|
||||
protected fun initFormComponents(init: FormBuilder.() -> Unit) {
|
||||
myWholePanel.setLayout(BorderLayout())
|
||||
|
||||
with(FormBuilder.createFormBuilder()) {
|
||||
init()
|
||||
myWholePanel.add(getPanel(), BorderLayout.CENTER)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun runWriteCommandAndRestart(action: () -> Unit) {
|
||||
myEditor.putUserData(InplaceRefactoring.INTRODUCE_RESTART, true)
|
||||
try {
|
||||
stopIntroduce(myEditor)
|
||||
myProject.executeWriteCommand(getCommandName(), getCommandName(), action)
|
||||
// myExprMarker was invalidated by stopIntroduce()
|
||||
myExprMarker = createMarker(myExpr)
|
||||
startInplaceIntroduceTemplate()
|
||||
}
|
||||
finally {
|
||||
myEditor.putUserData(InplaceRefactoring.INTRODUCE_RESTART, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getActionName(): String? = null
|
||||
|
||||
override fun restoreExpression(
|
||||
containingFile: PsiFile,
|
||||
declaration: D,
|
||||
marker: RangeMarker,
|
||||
exprText: String
|
||||
): JetExpression? {
|
||||
if (!declaration.isValid()) return null
|
||||
|
||||
return containingFile
|
||||
.findElementAt(marker.getStartOffset())
|
||||
?.getNonStrictParentOfType<JetSimpleNameExpression>()
|
||||
?.replaced(JetPsiFactory(myProject).createExpression(exprText))
|
||||
}
|
||||
|
||||
override fun updateTitle(declaration: D?) = updateTitle(declaration, null)
|
||||
|
||||
override fun saveSettings(declaration: D?) {
|
||||
|
||||
}
|
||||
}
|
||||
+8
-44
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.openapi.editor.impl.DocumentMarkupModel
|
||||
import com.intellij.openapi.editor.markup.EffectType
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
||||
@@ -27,28 +26,24 @@ import com.intellij.openapi.editor.markup.MarkupModel
|
||||
import com.intellij.openapi.editor.markup.TextAttributes
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiAnchor
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.NonFocusableCheckBox
|
||||
import com.intellij.util.ui.FormBuilder
|
||||
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.introduce.AbstractKotlinInplaceIntroducer
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinInplaceVariableIntroducer
|
||||
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.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getValueParameters
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Color
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
import javax.swing.JCheckBox
|
||||
|
||||
public class KotlinInplaceParameterIntroducer(
|
||||
@@ -57,17 +52,15 @@ public class KotlinInplaceParameterIntroducer(
|
||||
val suggestedNames: Array<out String>,
|
||||
project: Project,
|
||||
editor: Editor
|
||||
): AbstractInplaceIntroducer<JetParameter, JetExpression>(
|
||||
project,
|
||||
editor,
|
||||
): AbstractKotlinInplaceIntroducer<JetParameter>(
|
||||
originalDescriptor.originalRange.elements.single() as JetExpression,
|
||||
null,
|
||||
originalDescriptor.occurrencesToReplace
|
||||
.map { it.elements.single() as JetExpression }
|
||||
.filterNotNull()
|
||||
.toTypedArray(),
|
||||
INTRODUCE_PARAMETER,
|
||||
JetFileType.INSTANCE
|
||||
project,
|
||||
editor
|
||||
) {
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(javaClass<KotlinInplaceParameterIntroducer>())
|
||||
@@ -106,7 +99,7 @@ public class KotlinInplaceParameterIntroducer(
|
||||
private var replaceAllCheckBox: JCheckBox? = null
|
||||
|
||||
init {
|
||||
val panel = with(FormBuilder.createFormBuilder()) {
|
||||
initFormComponents {
|
||||
addComponent(getPreviewComponent())
|
||||
|
||||
val defaultValueCheckBox = NonFocusableCheckBox("Introduce default value")
|
||||
@@ -126,12 +119,7 @@ public class KotlinInplaceParameterIntroducer(
|
||||
addComponent(replaceAllCheckBox)
|
||||
this@KotlinInplaceParameterIntroducer.replaceAllCheckBox = replaceAllCheckBox
|
||||
}
|
||||
|
||||
getPanel()
|
||||
}
|
||||
|
||||
myWholePanel.setLayout(BorderLayout())
|
||||
myWholePanel.add(panel, BorderLayout.CENTER)
|
||||
}
|
||||
|
||||
override fun getActionName() = "IntroduceParameter"
|
||||
@@ -159,24 +147,6 @@ public class KotlinInplaceParameterIntroducer(
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -185,8 +155,6 @@ public class KotlinInplaceParameterIntroducer(
|
||||
|
||||
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
|
||||
@@ -249,10 +217,6 @@ public class KotlinInplaceParameterIntroducer(
|
||||
revalidate()
|
||||
}
|
||||
|
||||
override fun saveSettings(variable: JetParameter?) {
|
||||
|
||||
}
|
||||
|
||||
override fun performIntroduce() {
|
||||
getDescriptorToRefactor(isReplaceAllOccurrences()).performRefactoring()
|
||||
}
|
||||
|
||||
+14
-11
@@ -73,7 +73,7 @@ import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
|
||||
|
||||
public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
||||
|
||||
private static final String INTRODUCE_VARIABLE = JetRefactoringBundle.message("introduce.variable");
|
||||
public static final String INTRODUCE_VARIABLE = JetRefactoringBundle.message("introduce.variable");
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file, DataContext dataContext) {
|
||||
@@ -198,9 +198,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
||||
calculateAnchor(commonParent, commonContainer, allReplaces),
|
||||
JetNameValidatorImpl.Target.PROPERTIES
|
||||
);
|
||||
String[] suggestedNames = JetNameSuggester.suggestNames(expression, validator, "value");
|
||||
final LinkedHashSet<String> suggestedNamesSet = new LinkedHashSet<String>();
|
||||
Collections.addAll(suggestedNamesSet, suggestedNames);
|
||||
final String[] suggestedNames = JetNameSuggester.suggestNames(expression, validator, "value");
|
||||
final Ref<JetProperty> propertyRef = new Ref<JetProperty>();
|
||||
final ArrayList<JetExpression> references = new ArrayList<JetExpression>();
|
||||
final Ref<JetExpression> reference = new Ref<JetExpression>();
|
||||
@@ -222,13 +220,18 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
PsiDocumentManager.getInstance(project).
|
||||
doPostponedOperationsAndUnblockDocument(editor.getDocument());
|
||||
KotlinInplaceVariableIntroducer<JetProperty> variableIntroducer =
|
||||
new KotlinInplaceVariableIntroducer<JetProperty>(property, editor, project, INTRODUCE_VARIABLE,
|
||||
references.toArray(new JetExpression[references.size()]),
|
||||
reference.get(), finalReplaceOccurrence,
|
||||
property, /*todo*/false, /*todo*/false,
|
||||
expressionType, finalNoTypeInference);
|
||||
variableIntroducer.performInplaceRefactoring(suggestedNamesSet);
|
||||
KotlinVariableInplaceIntroducer variableIntroducer =
|
||||
new KotlinVariableInplaceIntroducer(property,
|
||||
reference.get(),
|
||||
references.toArray(new JetExpression[references.size()]),
|
||||
suggestedNames,
|
||||
/*todo*/ false,
|
||||
/*todo*/ false,
|
||||
expressionType,
|
||||
finalNoTypeInference,
|
||||
project,
|
||||
editor);
|
||||
variableIntroducer.startInplaceIntroduceTemplate();
|
||||
}
|
||||
}
|
||||
else if (onNonInteractiveFinish != null) {
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable
|
||||
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil
|
||||
import com.intellij.ui.NonFocusableCheckBox
|
||||
import com.intellij.util.ui.FormBuilder
|
||||
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.AbstractKotlinInplaceIntroducer
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import java.awt.BorderLayout
|
||||
|
||||
public class KotlinVariableInplaceIntroducer(
|
||||
val addedVariable: JetProperty,
|
||||
val originalExpression: JetExpression,
|
||||
val occurrencesToReplace: Array<JetExpression>,
|
||||
val suggestedNames: Array<out String>,
|
||||
val isVar: Boolean,
|
||||
val doNotChangeVar: Boolean,
|
||||
val expressionType: JetType?,
|
||||
val noTypeInference: Boolean,
|
||||
project: Project,
|
||||
editor: Editor
|
||||
): AbstractKotlinInplaceIntroducer<JetProperty>(
|
||||
originalExpression,
|
||||
occurrencesToReplace,
|
||||
KotlinIntroduceVariableHandler.INTRODUCE_VARIABLE,
|
||||
project,
|
||||
editor
|
||||
) {
|
||||
companion object {
|
||||
}
|
||||
|
||||
init {
|
||||
initFormComponents {
|
||||
if (!doNotChangeVar) {
|
||||
val varCheckBox = NonFocusableCheckBox("Declare with var")
|
||||
varCheckBox.setSelected(isVar)
|
||||
varCheckBox.setMnemonic('v')
|
||||
varCheckBox.addActionListener {
|
||||
myProject.executeWriteCommand(getCommandName(), getCommandName()) {
|
||||
PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument())
|
||||
|
||||
val psiFactory = JetPsiFactory(myProject)
|
||||
val keyword = if (varCheckBox.isSelected()) psiFactory.createVarKeyword() else psiFactory.createValKeyword()
|
||||
addedVariable.getValOrVarKeyword().replace(keyword)
|
||||
}
|
||||
}
|
||||
addComponent(varCheckBox)
|
||||
}
|
||||
|
||||
if (expressionType != null && !noTypeInference) {
|
||||
val expressionTypeCheckBox = NonFocusableCheckBox("Specify type explicitly")
|
||||
expressionTypeCheckBox.setSelected(false)
|
||||
expressionTypeCheckBox.setMnemonic('t')
|
||||
expressionTypeCheckBox.addActionListener {
|
||||
runWriteCommandAndRestart {
|
||||
if (expressionTypeCheckBox.isSelected()) {
|
||||
val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(expressionType)
|
||||
addedVariable.setTypeReference(JetPsiFactory(myProject).createType(renderedType))
|
||||
}
|
||||
else {
|
||||
addedVariable.setTypeReference(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
addComponent(expressionTypeCheckBox)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getVariable() = addedVariable
|
||||
|
||||
override fun suggestNames(replaceAll: Boolean, variable: JetProperty?) = suggestedNames
|
||||
|
||||
override fun createFieldToStartTemplateOn(replaceAll: Boolean, names: Array<out String>) = addedVariable
|
||||
|
||||
override fun addAdditionalVariables(builder: TemplateBuilderImpl) {
|
||||
addedVariable.getTypeReference()?.let {
|
||||
builder.replaceElement(it,
|
||||
"TypeReferenceVariable",
|
||||
SpecifyTypeExplicitlyIntention.createTypeExpressionForTemplate(expressionType!!),
|
||||
false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildTemplateAndStart(refs: Collection<PsiReference>,
|
||||
stringUsages: Collection<util.Pair<PsiElement, TextRange>>,
|
||||
scope: PsiElement,
|
||||
containingFile: PsiFile): Boolean {
|
||||
myEditor.getCaretModel().moveToOffset(getNameIdentifier()!!.startOffset)
|
||||
|
||||
val result = super.buildTemplateAndStart(refs, stringUsages, scope, containingFile)
|
||||
|
||||
val templateState = TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor))
|
||||
if (templateState != null && addedVariable.getTypeReference() != null) {
|
||||
templateState.addTemplateStateListener(SpecifyTypeExplicitlyIntention.createTypeReferencePostprocessor(addedVariable))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun updateTitle(variable: JetProperty?, value: String?) {
|
||||
// No preview to update
|
||||
}
|
||||
|
||||
override fun deleteTemplateField(psiField: JetProperty?) {
|
||||
// Do not delete introduced variable as it was created outside of in-place refactoring
|
||||
}
|
||||
|
||||
override fun isReplaceAllOccurrences() = true
|
||||
|
||||
override fun setReplaceAllOccurrences(allOccurrences: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
override fun getComponent() = myWholePanel
|
||||
|
||||
override fun performIntroduce() {
|
||||
val replacement = JetPsiFactory(myProject).createExpression(addedVariable.getName() ?: return)
|
||||
getOccurrences().forEach {
|
||||
if (it.isValid()) {
|
||||
it.replace(replacement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user