mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fine-grained write actions in "Extract Method" refactoring for Python
This way it's safer to launch time-consuming dependent tasks (e.g. searching for code duplicates) synchonously since under WriteAction they might cause deadlock.
This commit is contained in:
+37
-29
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.codeFragment.CodeFragment;
|
||||
import com.intellij.lang.LanguageNamesValidation;
|
||||
import com.intellij.lang.refactoring.NamesValidator;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -107,7 +108,7 @@ public class PyExtractMethodUtil {
|
||||
|
||||
final SimpleDuplicatesFinder finder = new SimpleDuplicatesFinder(statement1, statement2, fragment.getOutputVariables(), variableData);
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> {
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> {
|
||||
final RefactoringEventData beforeData = new RefactoringEventData();
|
||||
beforeData.addElements(new PsiElement[]{statement1, statement2});
|
||||
project.getMessageBus().syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
|
||||
@@ -127,7 +128,7 @@ public class PyExtractMethodUtil {
|
||||
if (hasOutputVariables) {
|
||||
// Generate return modified variables statements
|
||||
final String outputVariables = StringUtil.join(fragment.getOutputVariables(), ", ");
|
||||
String newMethodText = builder + "return " + outputVariables;
|
||||
final String newMethodText = builder + "return " + outputVariables;
|
||||
builder.append(outputVariables);
|
||||
|
||||
final PyFunction function1 = generator.createFromText(languageLevel, PyFunction.class, newMethodText);
|
||||
@@ -136,15 +137,17 @@ public class PyExtractMethodUtil {
|
||||
}
|
||||
|
||||
// Generate method
|
||||
PyFunction generatedMethod = generateMethodFromElements(project, methodName, variableData, newMethodElements, flags, isAsync);
|
||||
generatedMethod = insertGeneratedMethod(statement1, generatedMethod);
|
||||
final PyFunction generatedMethod = generateMethodFromElements(project, methodName, variableData, newMethodElements, flags, isAsync);
|
||||
final PyFunction insertedMethod = WriteAction.compute(() -> insertGeneratedMethod(statement1, generatedMethod));
|
||||
|
||||
// Process parameters
|
||||
final PsiElement firstElement = elementsRange.get(0);
|
||||
final boolean isMethod = PyPsiUtils.isMethodContext(firstElement);
|
||||
processParameters(project, generatedMethod, variableData, isMethod, isClassMethod, isStaticMethod);
|
||||
processGlobalWrites(generatedMethod, fragment);
|
||||
processNonlocalWrites(generatedMethod, fragment);
|
||||
WriteAction.run(() -> {
|
||||
processParameters(project, insertedMethod, variableData, isMethod, isClassMethod, isStaticMethod);
|
||||
processGlobalWrites(insertedMethod, fragment);
|
||||
processNonlocalWrites(insertedMethod, fragment);
|
||||
});
|
||||
|
||||
// Generate call element
|
||||
if (hasOutputVariables) {
|
||||
@@ -165,29 +168,29 @@ public class PyExtractMethodUtil {
|
||||
builder.append(methodName).append("(");
|
||||
builder.append(createCallArgsString(variableData)).append(")");
|
||||
final PyFunction function1 = generator.createFromText(languageLevel, PyFunction.class, builder.toString());
|
||||
PsiElement callElement = function1.getStatementList().getStatements()[0];
|
||||
final PsiElement callElement = function1.getStatementList().getStatements()[0];
|
||||
|
||||
// Both statements are used in finder, so should be valid at this moment
|
||||
PyPsiUtils.assertValid(statement1);
|
||||
PyPsiUtils.assertValid(statement2);
|
||||
final List<SimpleMatch> duplicates = collectDuplicates(finder, statement1, generatedMethod);
|
||||
final List<SimpleMatch> duplicates = collectDuplicates(finder, statement1, insertedMethod);
|
||||
|
||||
// replace statements with call
|
||||
callElement = replaceElements(elementsRange, callElement);
|
||||
callElement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(callElement);
|
||||
|
||||
if (callElement != null) {
|
||||
processDuplicates(duplicates, callElement, editor);
|
||||
PsiElement insertedCallElement = WriteAction.compute(() -> replaceElements(elementsRange, callElement));
|
||||
insertedCallElement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(insertedCallElement);
|
||||
|
||||
if (insertedCallElement != null) {
|
||||
processDuplicates(duplicates, insertedCallElement, editor);
|
||||
}
|
||||
|
||||
// Set editor
|
||||
setSelectionAndCaret(editor, callElement);
|
||||
setSelectionAndCaret(editor, insertedCallElement);
|
||||
|
||||
final RefactoringEventData afterData = new RefactoringEventData();
|
||||
afterData.addElement(generatedMethod);
|
||||
afterData.addElement(insertedMethod);
|
||||
project.getMessageBus().syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
|
||||
.refactoringDone(getRefactoringId(), afterData);
|
||||
}), PyBundle.message("refactoring.extract.method"), null);
|
||||
}, PyBundle.message("refactoring.extract.method"), null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -307,15 +310,15 @@ public class PyExtractMethodUtil {
|
||||
|
||||
final SimpleDuplicatesFinder finder = new SimpleDuplicatesFinder(expression, expression, fragment.getOutputVariables(), variableData);
|
||||
if (fragment.getOutputVariables().isEmpty()) {
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> {
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> {
|
||||
// Generate method
|
||||
final boolean isAsync = fragment.isAsync();
|
||||
PyFunction generatedMethod = generateMethodFromExpression(project, methodName, variableData, expression, flags, isAsync);
|
||||
generatedMethod = insertGeneratedMethod(expression, generatedMethod);
|
||||
final PyFunction generatedMethod = generateMethodFromExpression(project, methodName, variableData, expression, flags, isAsync);
|
||||
final PyFunction insertedMethod = WriteAction.compute(() -> insertGeneratedMethod(expression, generatedMethod));
|
||||
|
||||
// Process parameters
|
||||
final boolean isMethod = PyPsiUtils.isMethodContext(expression);
|
||||
processParameters(project, generatedMethod, variableData, isMethod, isClassMethod, isStaticMethod);
|
||||
WriteAction.run(() -> processParameters(project, insertedMethod, variableData, isMethod, isClassMethod, isStaticMethod));
|
||||
|
||||
// Generating call element
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
@@ -341,26 +344,31 @@ public class PyExtractMethodUtil {
|
||||
final PyFunction function1 = generator.createFromText(LanguageLevel.forElement(expression), PyFunction.class,
|
||||
builder.toString());
|
||||
final PyElement generated = function1.getStatementList().getStatements()[0];
|
||||
PsiElement callElement = null;
|
||||
final PsiElement callElement;
|
||||
if (generated instanceof PyReturnStatement) {
|
||||
callElement = ((PyReturnStatement)generated).getExpression();
|
||||
}
|
||||
else if (generated instanceof PyExpressionStatement) {
|
||||
callElement = ((PyExpressionStatement)generated).getExpression();
|
||||
}
|
||||
else {
|
||||
callElement = null;
|
||||
}
|
||||
|
||||
PyPsiUtils.assertValid(expression);
|
||||
final List<SimpleMatch> duplicates = collectDuplicates(finder, expression, generatedMethod);
|
||||
final List<SimpleMatch> duplicates = collectDuplicates(finder, expression, insertedMethod);
|
||||
|
||||
// replace statements with call
|
||||
PsiElement insertedCallElement = null;
|
||||
if (callElement != null) {
|
||||
callElement = PyReplaceExpressionUtil.replaceExpression(expression, callElement);
|
||||
}
|
||||
if (callElement != null) {
|
||||
processDuplicates(duplicates, callElement, editor);
|
||||
insertedCallElement = WriteAction.compute(() -> PyReplaceExpressionUtil.replaceExpression(expression, callElement));
|
||||
if (insertedCallElement != null) {
|
||||
processDuplicates(duplicates, insertedCallElement, editor);
|
||||
}
|
||||
}
|
||||
setSelectionAndCaret(editor, insertedCallElement);
|
||||
// Set editor
|
||||
setSelectionAndCaret(editor, callElement);
|
||||
}), PyBundle.message("refactoring.extract.method"), null);
|
||||
}, PyBundle.message("refactoring.extract.method"), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user