List<SmartPsiFileRange> (@NotNull final Project project, @NotNull final Editor editor, @NotNull final PyCodeFragment fragment, @NotNull final PsiElement expression, final Boolean processDuplicates) { List<SmartPsiFileRange> pointers = new ArrayList<>(); if (!fragment.getOutputVariables().isEmpty()) { CommonRefactoringUtil.showErrorHint(project, editor, PyPsiBundle.message("refactoring.extract.method.error.local.variable.modifications"), RefactoringBundle.message("error.title"), "refactoring.extractMethod"); return pointers; } if (fragment.isReturnInstructionInside()) { CommonRefactoringUtil.showErrorHint(project, editor, PyPsiBundle.message("refactoring.extract.method.error.returns"), RefactoringBundle.message("error.title"), "refactoring.extractMethod"); return pointers; } final PyFunction function = PsiTreeUtil.getParentOfType(expression, 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.isClassMethod(); final Pair<String, AbstractVariableData[]> data = getNameAndVariableData(project, fragment, expression, isClassMethod, isStaticMethod); if (data.first == null || data.second == null) { return pointers; } final String methodName = data.first; final AbstractVariableData[] variableData = data.second; final SimpleDuplicatesFinder finder = new SimpleDuplicatesFinder(expression, expression, fragment.getOutputVariables(), variableData); if (fragment.getOutputVariables().isEmpty()) { CommandProcessor.getInstance().executeCommand(project, () -> { // Generate method final boolean isAsync = fragment.isAsync(); final PyFunction generatedMethod = generateMethodFromExpression(methodName, variableData, expression, flags, isAsync); final PyFunction insertedMethod = WriteAction.compute(() -> insertGeneratedMethod(expression, generatedMethod)); // Process parameters final boolean isMethod = PyPsiUtils.isMethodContext(expression); WriteAction.run(() -> processParameters(project, insertedMethod, variableData, isMethod, isClassMethod, isStaticMethod)); // Generating call element final StringBuilder builder = new StringBuilder(); if (isAsync) { builder.append("async "); } builder.append("def f():\n "); if (isAsync) { builder.append("await "); } else if (fragment.isYieldInside()) { builder.append("yield from "); } else { builder.append("return "); } if (isMethod) { appendSelf(expression, builder, isStaticMethod); } builder.append(methodName); builder.append("(").append(createCallArgsString(variableData)).append(")"); final PyElementGenerator generator = PyElementGenerator.getInstance(project); final PyFunction function1 = generator.createFromText(LanguageLevel.forElement(expression), PyFunction.class, builder.toString()); final PyElement generated = function1.getStatementList().getStatements()[0]; 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); List<SimpleMatch> duplicates = collectDuplicates(finder, expression, insertedMethod); // When a single reference is extracted into an identity function, prevent unrelated expressions being replaced with calls to it if (expression instanceof PyReferenceExpression) { duplicates = ContainerUtil.filter(duplicates, it -> it.getStartElement() == it.getEndElement() && expression.getText().equals(it.getStartElement().getText())); } // replace statements with call PsiElement insertedCallElement = null; PsiFile file = expression.getContainingFile(); SmartPointerManager pointerManager = SmartPointerManager.getInstance(project); if (processDuplicates) { pointers.addAll(ContainerUtil.map(duplicates, p -> pointerManager.createSmartPsiFileRangePointer(file, p.getStartElement().getTextRange()))); } if (callElement != null) { insertedCallElement = WriteAction.compute(() -> PyReplaceExpressionUtil.replaceExpression(expression, callElement)); 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); } } } setSelectionAndCaret(editor, insertedCallElement); // Set editor }, PyPsiBundle.message("refactoring.extract.method"), null); } return pointers; }