mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
added extract parameter refactoring
This commit is contained in:
@@ -452,6 +452,9 @@ refactoring.introduce.variable.scope.error=Name clashes with existing variable o
|
||||
refactoring.introduce.constant.dialog.title=Extract Constant
|
||||
refactoring.introduce.constant.scope.error=Name is already declared in scope
|
||||
|
||||
# introduce parameter
|
||||
refactoring.introduce.parameter.dialog.title=Extract Parameter
|
||||
|
||||
# pull up
|
||||
refactoring.pull.up.dialog.title=Pull members up to
|
||||
refactoring.pull.up.error.cannot.perform.refactoring.using.selected.elements=Cannot perform pull member up using selected element(s)
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.jetbrains.python.refactoring.classes.extractSuperclass.PyExtractSuper
|
||||
import com.jetbrains.python.refactoring.classes.pullUp.PyPullUpHandler;
|
||||
import com.jetbrains.python.refactoring.classes.pushDown.PyPushDownHandler;
|
||||
import com.jetbrains.python.refactoring.extractmethod.PyExtractMethodHandler;
|
||||
import com.jetbrains.python.refactoring.introduce.parameter.PyIntroduceParameterHandler;
|
||||
import com.jetbrains.python.refactoring.introduce.constant.PyIntroduceConstantHandler;
|
||||
import com.jetbrains.python.refactoring.introduce.field.PyIntroduceFieldHandler;
|
||||
import com.jetbrains.python.refactoring.introduce.variable.PyIntroduceVariableHandler;
|
||||
@@ -74,4 +75,10 @@ public class PyRefactoringProvider extends RefactoringSupportProvider {
|
||||
public ChangeSignatureHandler getChangeSignatureHandler() {
|
||||
return new PyChangeSignatureHandler();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RefactoringActionHandler getIntroduceParameterHandler() {
|
||||
return new PyIntroduceParameterHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,15 +391,17 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
|
||||
}
|
||||
|
||||
protected void performInplaceIntroduce(IntroduceOperation operation) {
|
||||
final PyAssignmentStatement statement = performRefactoring(operation);
|
||||
PyTargetExpression target = (PyTargetExpression) statement.getTargets() [0];
|
||||
final List<PsiElement> occurrences = operation.getOccurrences();
|
||||
final PsiElement occurrence = findOccurrenceUnderCaret(occurrences, operation.getEditor());
|
||||
PsiElement elementForCaret = occurrence != null ? occurrence : target;
|
||||
operation.getEditor().getCaretModel().moveToOffset(elementForCaret.getTextRange().getStartOffset());
|
||||
final InplaceVariableIntroducer<PsiElement> introducer =
|
||||
new PyInplaceVariableIntroducer(target, operation, occurrences);
|
||||
introducer.performInplaceRefactoring(new LinkedHashSet<String>(operation.getSuggestedNames()));
|
||||
final PsiElement statement = performRefactoring(operation);
|
||||
if (statement instanceof PyAssignmentStatement) {
|
||||
PyTargetExpression target = (PyTargetExpression) ((PyAssignmentStatement)statement).getTargets() [0];
|
||||
final List<PsiElement> occurrences = operation.getOccurrences();
|
||||
final PsiElement occurrence = findOccurrenceUnderCaret(occurrences, operation.getEditor());
|
||||
PsiElement elementForCaret = occurrence != null ? occurrence : target;
|
||||
operation.getEditor().getCaretModel().moveToOffset(elementForCaret.getTextRange().getStartOffset());
|
||||
final InplaceVariableIntroducer<PsiElement> introducer =
|
||||
new PyInplaceVariableIntroducer(target, operation, occurrences);
|
||||
introducer.performInplaceRefactoring(new LinkedHashSet<String>(operation.getSuggestedNames()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void performIntroduceWithDialog(IntroduceOperation operation) {
|
||||
@@ -415,14 +417,14 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
|
||||
operation.setInitPlace(dialog.getInitPlace());
|
||||
}
|
||||
|
||||
PyAssignmentStatement declaration = performRefactoring(operation);
|
||||
PsiElement declaration = performRefactoring(operation);
|
||||
final Editor editor = operation.getEditor();
|
||||
editor.getCaretModel().moveToOffset(declaration.getTextRange().getEndOffset());
|
||||
editor.getSelectionModel().removeSelection();
|
||||
}
|
||||
|
||||
protected PyAssignmentStatement performRefactoring(IntroduceOperation operation) {
|
||||
PyAssignmentStatement declaration = createDeclaration(operation);
|
||||
protected PsiElement performRefactoring(IntroduceOperation operation) {
|
||||
PsiElement declaration = createDeclaration(operation);
|
||||
|
||||
declaration = performReplace(declaration, operation);
|
||||
declaration = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(declaration);
|
||||
@@ -506,12 +508,12 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
|
||||
return PyRefactoringUtil.getOccurrences(expression, context);
|
||||
}
|
||||
|
||||
private PyAssignmentStatement performReplace(@NotNull final PyAssignmentStatement declaration,
|
||||
final IntroduceOperation operation) {
|
||||
private PsiElement performReplace(@NotNull final PsiElement declaration,
|
||||
final IntroduceOperation operation) {
|
||||
final PyExpression expression = operation.getInitializer();
|
||||
final Project project = operation.getProject();
|
||||
return new WriteCommandAction<PyAssignmentStatement>(project, expression.getContainingFile()) {
|
||||
protected void run(final Result<PyAssignmentStatement> result) throws Throwable {
|
||||
return new WriteCommandAction<PsiElement>(project, expression.getContainingFile()) {
|
||||
protected void run(final Result<PsiElement> result) throws Throwable {
|
||||
result.setResult(addDeclaration(operation, declaration));
|
||||
|
||||
PyExpression newExpression = createExpression(project, operation.getName(), declaration);
|
||||
@@ -537,18 +539,18 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyAssignmentStatement addDeclaration(IntroduceOperation operation, PyAssignmentStatement declaration) {
|
||||
public PsiElement addDeclaration(IntroduceOperation operation, PsiElement declaration) {
|
||||
final PsiElement expression = operation.getInitializer();
|
||||
final Pair<PsiElement, TextRange> data = expression.getUserData(PyPsiUtils.SELECTION_BREAKS_AST_NODE);
|
||||
if (data == null) {
|
||||
return (PyAssignmentStatement)addDeclaration(expression, declaration, operation);
|
||||
return addDeclaration(expression, declaration, operation);
|
||||
}
|
||||
else {
|
||||
return (PyAssignmentStatement)addDeclaration(data.first, declaration, operation);
|
||||
return addDeclaration(data.first, declaration, operation);
|
||||
}
|
||||
}
|
||||
|
||||
protected PyExpression createExpression(Project project, String name, PyAssignmentStatement declaration) {
|
||||
protected PyExpression createExpression(Project project, String name, PsiElement declaration) {
|
||||
return PyElementGenerator.getInstance(project).createExpressionFromText(name);
|
||||
}
|
||||
|
||||
|
||||
+11
-9
@@ -196,7 +196,7 @@ public class PyIntroduceFieldHandler extends IntroduceHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PyExpression createExpression(Project project, String name, PyAssignmentStatement declaration) {
|
||||
protected PyExpression createExpression(Project project, String name, PsiElement declaration) {
|
||||
final String text = declaration.getText();
|
||||
final String self_name = text.substring(0, text.indexOf('.'));
|
||||
return PyElementGenerator.getInstance(project).createExpressionFromText(self_name + "." + name);
|
||||
@@ -281,15 +281,17 @@ public class PyIntroduceFieldHandler extends IntroduceHandler {
|
||||
|
||||
@Override
|
||||
protected void performInplaceIntroduce(IntroduceOperation operation) {
|
||||
final PyAssignmentStatement statement = performRefactoring(operation);
|
||||
final PsiElement statement = performRefactoring(operation);
|
||||
// put caret on identifier after "self."
|
||||
final List<PsiElement> occurrences = operation.getOccurrences();
|
||||
final PsiElement occurrence = findOccurrenceUnderCaret(occurrences, operation.getEditor());
|
||||
PyTargetExpression target = (PyTargetExpression) statement.getTargets() [0];
|
||||
putCaretOnFieldName(operation.getEditor(), occurrence != null ? occurrence : target);
|
||||
final InplaceVariableIntroducer<PsiElement> introducer = new PyInplaceFieldIntroducer(target, operation, occurrences);
|
||||
introducer.performInplaceRefactoring(new LinkedHashSet<String>(operation.getSuggestedNames()));
|
||||
}
|
||||
if (statement instanceof PyAssignmentStatement) {
|
||||
final List<PsiElement> occurrences = operation.getOccurrences();
|
||||
final PsiElement occurrence = findOccurrenceUnderCaret(occurrences, operation.getEditor());
|
||||
PyTargetExpression target = (PyTargetExpression) ((PyAssignmentStatement)statement).getTargets() [0];
|
||||
putCaretOnFieldName(operation.getEditor(), occurrence != null ? occurrence : target);
|
||||
final InplaceVariableIntroducer<PsiElement> introducer = new PyInplaceFieldIntroducer(target, operation, occurrences);
|
||||
introducer.performInplaceRefactoring(new LinkedHashSet<String>(operation.getSuggestedNames()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void putCaretOnFieldName(Editor editor, PsiElement occurrence) {
|
||||
PyQualifiedExpression qExpr = PsiTreeUtil.getParentOfType(occurrence, PyQualifiedExpression.class, false);
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package com.jetbrains.python.refactoring.introduce.parameter;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightUtilBase;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.introduce.inplace.InplaceVariableIntroducer;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.refactoring.introduce.IntroduceHandler;
|
||||
import com.jetbrains.python.refactoring.introduce.IntroduceOperation;
|
||||
import com.jetbrains.python.refactoring.introduce.variable.VariableValidator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: ktisha
|
||||
*/
|
||||
public class PyIntroduceParameterHandler extends IntroduceHandler {
|
||||
public PyIntroduceParameterHandler() {
|
||||
super(new VariableValidator(), PyBundle.message("refactoring.introduce.parameter.dialog.title"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHelpId() {
|
||||
return "python.reference.introduceParameter";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiElement addDeclaration(@NotNull PsiElement expression,
|
||||
@NotNull PsiElement declaration,
|
||||
@NotNull IntroduceOperation operation) {
|
||||
return doIntroduceParameter(expression, (PyAssignmentStatement)declaration);
|
||||
}
|
||||
|
||||
|
||||
public PsiElement doIntroduceParameter(PsiElement expression, PyAssignmentStatement declaration) {
|
||||
PyFunction function = PsiTreeUtil.getParentOfType(expression, PyFunction.class);
|
||||
if (function != null && declaration != null) {
|
||||
PyParameterList parameterList = function.getParameterList();
|
||||
List<String> newParams = new ArrayList<String>();
|
||||
if (parameterList.hasKeywordContainer()) {
|
||||
for (PyParameter parameter : parameterList.getParameters()) {
|
||||
if (parameter instanceof PyNamedParameter && ((PyNamedParameter)parameter).isKeywordContainer()) {
|
||||
newParams.add(declaration.getText());
|
||||
}
|
||||
newParams.add(parameter.getText());
|
||||
}
|
||||
final PyParameterList replacementList =
|
||||
PyElementGenerator.getInstance(function.getProject()).createFromText(LanguageLevel.forElement(parameterList),
|
||||
PyFunction.class, "def f("
|
||||
+ StringUtil.join(newParams, ",")
|
||||
+ "): pass").getParameterList();
|
||||
parameterList = (PyParameterList)parameterList.replace(replacementList);
|
||||
CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(parameterList);
|
||||
}
|
||||
else {
|
||||
parameterList.addParameter(PyElementGenerator.getInstance(function.getProject()).createParameter(declaration.getText()));
|
||||
}
|
||||
CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(function);
|
||||
return parameterList.findParameterByName(declaration.getTargets()[0].getText());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkIntroduceContext(PsiFile file, Editor editor, PsiElement element) {
|
||||
if (element != null) {
|
||||
final PyFunction function = PsiTreeUtil.getParentOfType(element, PyFunction.class);
|
||||
if (function == null) {
|
||||
CommonRefactoringUtil.showErrorHint(file.getProject(), editor,
|
||||
"Introduce Parameter refactoring cannot be performed outside any function",
|
||||
RefactoringBundle.message("introduce.parameter.title"), null);
|
||||
return false;
|
||||
}
|
||||
if (isResolvedToParameter(element)) {
|
||||
CommonRefactoringUtil.showErrorHint(file.getProject(), editor,
|
||||
PyBundle.message("refactoring.introduce.selection.error"),
|
||||
RefactoringBundle.message("introduce.parameter.title"), null);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.checkIntroduceContext(file, editor, element);
|
||||
}
|
||||
|
||||
private boolean isResolvedToParameter(PsiElement element) {
|
||||
while (element instanceof PyReferenceExpression) {
|
||||
final PsiReference reference = element.getReference();
|
||||
if (reference != null && reference.resolve() instanceof PyNamedParameter)
|
||||
return true;
|
||||
element = ((PyReferenceExpression)element).getQualifier();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performInplaceIntroduce(IntroduceOperation operation) {
|
||||
final PsiElement statement = performRefactoring(operation);
|
||||
if (statement instanceof PyNamedParameter) {
|
||||
final List<PsiElement> occurrences = operation.getOccurrences();
|
||||
final PsiElement occurrence = findOccurrenceUnderCaret(occurrences, operation.getEditor());
|
||||
PsiElement elementForCaret = occurrence != null ? occurrence : statement;
|
||||
operation.getEditor().getCaretModel().moveToOffset(elementForCaret.getTextRange().getStartOffset());
|
||||
final InplaceVariableIntroducer<PsiElement> introducer =
|
||||
new PyInplaceParameterIntroducer((PyNamedParameter)statement, operation, occurrences);
|
||||
introducer.performInplaceRefactoring(new LinkedHashSet<String>(operation.getSuggestedNames()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class PyInplaceParameterIntroducer extends InplaceVariableIntroducer<PsiElement> {
|
||||
private final PyNamedParameter myTarget;
|
||||
|
||||
public PyInplaceParameterIntroducer(PyNamedParameter target,
|
||||
IntroduceOperation operation,
|
||||
List<PsiElement> occurrences) {
|
||||
super(target, operation.getEditor(), operation.getProject(), "Introduce Parameter",
|
||||
occurrences.toArray(new PsiElement[occurrences.size()]), null);
|
||||
myTarget = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement checkLocalScope() {
|
||||
return myTarget.getContainingFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
def funcq(param1, a="test", **args):
|
||||
b = a
|
||||
return b
|
||||
@@ -0,0 +1,3 @@
|
||||
def funcq(param1, **args):
|
||||
b = "tes<caret>t"
|
||||
return b
|
||||
@@ -0,0 +1,3 @@
|
||||
y = 1
|
||||
def f(x, a=y.foo.bar):
|
||||
return a.baz()
|
||||
@@ -0,0 +1,4 @@
|
||||
y = 1
|
||||
def f(x):
|
||||
return <selection>y.foo\
|
||||
.bar</selection>.baz()
|
||||
@@ -0,0 +1,3 @@
|
||||
def f(x):
|
||||
return <selection>x.foo\
|
||||
.bar</selection>.baz()
|
||||
@@ -0,0 +1,2 @@
|
||||
def f(x, a="test"):
|
||||
return a
|
||||
@@ -0,0 +1,2 @@
|
||||
def f(x):
|
||||
return "<caret>test"
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.jetbrains.python.refactoring;
|
||||
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.refactoring.introduce.IntroduceHandler;
|
||||
import com.jetbrains.python.refactoring.introduce.parameter.PyIntroduceParameterHandler;
|
||||
|
||||
/**
|
||||
* User: ktisha
|
||||
*/
|
||||
@TestDataPath("$CONTENT_ROOT/../testData/refactoring/introduceParameter/")
|
||||
public class PyIntroduceParameterTest extends PyIntroduceTestCase {
|
||||
public void testSimple() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReferencedParameter() {
|
||||
doTestCannotPerform(PyBundle.message("refactoring.introduce.selection.error"));
|
||||
}
|
||||
|
||||
public void testParameter() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testKwParameter() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return super.getTestDataPath() + "/refactoring/introduceParameter";
|
||||
}
|
||||
|
||||
protected IntroduceHandler createHandler() {
|
||||
return new PyIntroduceParameterHandler();
|
||||
}
|
||||
|
||||
private void doTestCannotPerform(String expected) {
|
||||
try {
|
||||
doTest();
|
||||
}
|
||||
catch (CommonRefactoringUtil.RefactoringErrorHintException e) {
|
||||
assertEquals(expected, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user