List<SmartPsiFileRange> (@NotNull final Project project, @NotNull final Editor editor, @NotNull final PyCodeFragment fragment, @NotNull final PsiElement statement1, @NotNull final PsiElement statement2, Boolean processDuplicates) { List<SmartPsiFileRange> pointers = new ArrayList<>(); if (!fragment.getOutputVariables().isEmpty() && fragment.isReturnInstructionInside()) { CommonRefactoringUtil.showErrorHint(project, editor, PyPsiBundle.message("refactoring.extract.method.error.local.variable.modifications.and.returns"), RefactoringBundle.message("error.title"), "refactoring.extractMethod"); return pointers; } final PyFunction function = PsiTreeUtil.getParentOfType(statement1, PyFunction.class); final PyUtil.MethodFlags flags = function == null ? null : PyUtil.MethodFlags.of(function); final boolean isClassMethod = flags != null && flags.isClassMethod(); final boolean isStaticMethod = flags != null && flags.isStaticMethod(); // collect statements final List<PsiElement> elementsRange = PsiTreeUtil.getElementsOfRange(statement1, statement2); if (elementsRange.isEmpty()) { CommonRefactoringUtil.showErrorHint(project, editor, PyPsiBundle.message("refactoring.extract.method.error.empty.fragment"), RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod"); return pointers; } final Pair<String, AbstractVariableData[]> data = getNameAndVariableData(project, fragment, statement1, isClassMethod, isStaticMethod); if (data.first == null || data.second == null) { return pointers; } PsiFile file = statement1.getContainingFile(); final String methodName = data.first; final AbstractVariableData[] variableData = data.second; final SimpleDuplicatesFinder finder = new SimpleDuplicatesFinder(statement1, statement2, fragment.getOutputVariables(), variableData); CommandProcessor.getInstance().executeCommand(project, () -> { final RefactoringEventData beforeData = new RefactoringEventData(); beforeData.addElements(new PsiElement[]{statement1, statement2}); project.getMessageBus().syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC) .refactoringStarted(getRefactoringId(), beforeData); final StringBuilder builder = new StringBuilder(); final boolean isAsync = fragment.isAsync(); if (isAsync) { builder.append("async "); } builder.append("def f():\n "); final List<PsiElement> newMethodElements = new ArrayList<>(elementsRange); final boolean hasOutputVariables = !fragment.getOutputVariables().isEmpty(); final PyElementGenerator generator = PyElementGenerator.getInstance(project); final LanguageLevel languageLevel = LanguageLevel.forElement(statement1); if (hasOutputVariables) { // Generate return modified variables statements final String outputVariables = StringUtil.join(fragment.getOutputVariables(), ", "); final String newMethodText = builder + "return " + outputVariables; builder.append(outputVariables); final PyFunction function1 = generator.createFromText(languageLevel, PyFunction.class, newMethodText); final PsiElement returnStatement = function1.getStatementList().getStatements()[0]; newMethodElements.add(returnStatement); } // Generate method final PyFunction generatedMethod = generateMethodFromElements(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); WriteAction.run(() -> { processParameters(project, insertedMethod, variableData, isMethod, isClassMethod, isStaticMethod); processGlobalWrites(insertedMethod, fragment); processNonlocalWrites(insertedMethod, fragment); }); // Generate call element if (hasOutputVariables) { builder.append(" = "); } else if (fragment.isReturnInstructionInside()) { builder.append("return "); } if (isAsync) { builder.append("await "); } else if (fragment.isYieldInside()) { builder.append("yield from "); } if (isMethod) { appendSelf(firstElement, builder, isStaticMethod); } builder.append(methodName).append("("); builder.append(createCallArgsString(variableData)).append(")"); final PyFunction function1 = generator.createFromText(languageLevel, PyFunction.class, builder.toString()); 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, insertedMethod); // replace statements with call PsiElement insertedCallElement = WriteAction.compute(() -> replaceElements(elementsRange, callElement)); insertedCallElement = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(insertedCallElement); SmartPointerManager pointerManager = SmartPointerManager.getInstance(project); if (processDuplicates) { pointers.addAll(ContainerUtil.map(duplicates, p -> pointerManager.createSmartPsiFileRangePointer(file, p.getStartElement().getTextRange()))); } if (insertedCallElement != null) { pointers.add(0, pointerManager.createSmartPsiFileRangePointer(file, insertedMethod.getNameIdentifier().getTextRange())); pointers.add(pointerManager.createSmartPsiFileRangePointer(file, insertedCallElement.getTextRange())); if (processDuplicates) { processDuplicates(duplicates, insertedCallElement, editor); } } // Set editor setSelectionAndCaret(editor, insertedCallElement); final RefactoringEventData afterData = new RefactoringEventData(); afterData.addElement(insertedMethod); project.getMessageBus().syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC) .refactoringDone(getRefactoringId(), afterData); }, PyPsiBundle.message("refactoring.extract.method"), null); return pointers; }