Search in sources :

Example 1 with AbstractVariableData

use of com.intellij.refactoring.util.AbstractVariableData in project intellij-community by JetBrains.

the class PyExtractMethodUtil method getNameAndVariableData.

@NotNull
private static Pair<String, AbstractVariableData[]> getNameAndVariableData(@NotNull final Project project, @NotNull final CodeFragment fragment, @NotNull final PsiElement element, final boolean isClassMethod, final boolean isStaticMethod) {
    final ExtractMethodValidator validator = new PyExtractMethodValidator(element, project);
    if (ApplicationManager.getApplication().isUnitTestMode()) {
        String name = System.getProperty(NAME);
        if (name == null) {
            name = "foo";
        }
        final String error = validator.check(name);
        if (error != null) {
            if (ApplicationManager.getApplication().isUnitTestMode()) {
                throw new CommonRefactoringUtil.RefactoringErrorHintException(error);
            }
            if (Messages.showOkCancelDialog(error + ". " + RefactoringBundle.message("do.you.wish.to.continue"), RefactoringBundle.message("warning.title"), Messages.getWarningIcon()) != Messages.OK) {
                throw new CommonRefactoringUtil.RefactoringErrorHintException(error);
            }
        }
        final List<AbstractVariableData> data = new ArrayList<>();
        for (String in : fragment.getInputVariables()) {
            final AbstractVariableData d = new AbstractVariableData();
            d.name = in + "_new";
            d.originalName = in;
            d.passAsParameter = true;
            data.add(d);
        }
        return Pair.create(name, data.toArray(new AbstractVariableData[data.size()]));
    }
    final boolean isMethod = PyPsiUtils.isMethodContext(element);
    final ExtractMethodDecorator decorator = new ExtractMethodDecorator() {

        @NotNull
        public String createMethodSignature(final String methodName, @NotNull final AbstractVariableData[] variableDatas) {
            final StringBuilder builder = new StringBuilder();
            if (isClassMethod) {
                builder.append("cls");
            } else if (isMethod && !isStaticMethod) {
                builder.append("self");
            }
            for (AbstractVariableData variableData : variableDatas) {
                if (variableData.passAsParameter) {
                    if (builder.length() != 0) {
                        builder.append(", ");
                    }
                    builder.append(variableData.name);
                }
            }
            builder.insert(0, "(");
            builder.insert(0, methodName);
            builder.insert(0, "def ");
            builder.append(")");
            return builder.toString();
        }
    };
    final AbstractExtractMethodDialog dialog = new AbstractExtractMethodDialog(project, "method_name", fragment, validator, decorator, PythonFileType.INSTANCE) {

        @Override
        protected String getHelpId() {
            return "python.reference.extractMethod";
        }
    };
    dialog.show();
    //return if don`t want to extract method
    if (!dialog.isOK()) {
        return Pair.empty();
    }
    return Pair.create(dialog.getMethodName(), dialog.getAbstractVariableData());
}
Also used : AbstractVariableData(com.intellij.refactoring.util.AbstractVariableData) NotNull(org.jetbrains.annotations.NotNull) NotNull(org.jetbrains.annotations.NotNull)

Example 2 with AbstractVariableData

use of com.intellij.refactoring.util.AbstractVariableData in project intellij-community by JetBrains.

the class AbstractExtractMethodDialog method createVariableDataByNames.

public static AbstractVariableData[] createVariableDataByNames(final List<String> args) {
    final AbstractVariableData[] datas = new AbstractVariableData[args.size()];
    for (int i = 0; i < args.size(); i++) {
        final AbstractVariableData data = new AbstractVariableData();
        final String name = args.get(i);
        data.originalName = name;
        data.name = name;
        data.passAsParameter = true;
        datas[i] = data;
    }
    return datas;
}
Also used : AbstractVariableData(com.intellij.refactoring.util.AbstractVariableData)

Example 3 with AbstractVariableData

use of com.intellij.refactoring.util.AbstractVariableData in project intellij-community by JetBrains.

the class AbstractExtractMethodDialog method updateOutputVariables.

private void updateOutputVariables() {
    final StringBuilder builder = new StringBuilder();
    boolean first = true;
    for (String variable : myOutputVariables) {
        if (myVariablesMap != null) {
            final AbstractVariableData data = myVariablesMap.get(variable);
            final String outputName = data != null ? data.getName() : variable;
            if (first) {
                first = false;
            } else {
                builder.append(", ");
            }
            builder.append(outputName);
        }
    }
    myOutputVariablesTextArea.setText(builder.length() > 0 ? builder.toString() : RefactoringBundle.message("refactoring.extract.method.dialog.empty"));
}
Also used : AbstractVariableData(com.intellij.refactoring.util.AbstractVariableData)

Example 4 with AbstractVariableData

use of com.intellij.refactoring.util.AbstractVariableData in project intellij-community by JetBrains.

the class PyExtractMethodUtil method extractFromStatements.

public static void extractFromStatements(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PyCodeFragment fragment, @NotNull final PsiElement statement1, @NotNull final PsiElement statement2) {
    if (!fragment.getOutputVariables().isEmpty() && fragment.isReturnInstructionInside()) {
        CommonRefactoringUtil.showErrorHint(project, editor, PyBundle.message("refactoring.extract.method.error.local.variable.modifications.and.returns"), RefactoringBundle.message("error.title"), "refactoring.extractMethod");
        return;
    }
    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 = PyPsiUtils.collectElements(statement1, statement2);
    if (elementsRange.isEmpty()) {
        CommonRefactoringUtil.showErrorHint(project, editor, PyBundle.message("refactoring.extract.method.error.empty.fragment"), RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod");
        return;
    }
    final Pair<String, AbstractVariableData[]> data = getNameAndVariableData(project, fragment, statement1, isClassMethod, isStaticMethod);
    if (data.first == null || data.second == null) {
        return;
    }
    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(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);
        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);
        if (insertedCallElement != null) {
            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);
    }, PyBundle.message("refactoring.extract.method"), null);
}
Also used : AbstractVariableData(com.intellij.refactoring.util.AbstractVariableData) RefactoringEventData(com.intellij.refactoring.listeners.RefactoringEventData)

Example 5 with AbstractVariableData

use of com.intellij.refactoring.util.AbstractVariableData in project intellij-community by JetBrains.

the class PyExtractMethodUtil method processParameters.

private static void processParameters(@NotNull final Project project, @NotNull final PyFunction generatedMethod, @NotNull final AbstractVariableData[] variableData, final boolean isMethod, final boolean isClassMethod, final boolean isStaticMethod) {
    final Map<String, String> map = createMap(variableData);
    // Rename parameters
    for (PyParameter parameter : generatedMethod.getParameterList().getParameters()) {
        final String name = parameter.getName();
        final String newName = map.get(name);
        if (name != null && newName != null && !name.equals(newName)) {
            final Map<PsiElement, String> allRenames = new java.util.HashMap<>();
            allRenames.put(parameter, newName);
            final UsageInfo[] usages = RenameUtil.findUsages(parameter, newName, false, false, allRenames);
            try {
                RenameUtil.doRename(parameter, newName, usages, project, new RefactoringElementListenerComposite());
            } catch (IncorrectOperationException e) {
                RenameUtil.showErrorMessage(e, parameter, project);
                return;
            }
        }
    }
    // Change signature according to pass settings and
    final PyFunctionBuilder builder = new PyFunctionBuilder("foo", generatedMethod);
    if (isClassMethod) {
        builder.parameter("cls");
    } else if (isMethod && !isStaticMethod) {
        builder.parameter("self");
    }
    for (AbstractVariableData data : variableData) {
        if (data.isPassAsParameter()) {
            builder.parameter(data.getName());
        }
    }
    final PyParameterList pyParameterList = builder.buildFunction(project, LanguageLevel.forElement(generatedMethod)).getParameterList();
    generatedMethod.getParameterList().replace(pyParameterList);
}
Also used : HashMap(com.intellij.util.containers.hash.HashMap) RefactoringElementListenerComposite(com.intellij.refactoring.listeners.RefactoringElementListenerComposite) AbstractVariableData(com.intellij.refactoring.util.AbstractVariableData) PyFunctionBuilder(com.jetbrains.python.psi.impl.PyFunctionBuilder) IncorrectOperationException(com.intellij.util.IncorrectOperationException) UsageInfo(com.intellij.usageView.UsageInfo)

Aggregations

AbstractVariableData (com.intellij.refactoring.util.AbstractVariableData)5 RefactoringElementListenerComposite (com.intellij.refactoring.listeners.RefactoringElementListenerComposite)1 RefactoringEventData (com.intellij.refactoring.listeners.RefactoringEventData)1 UsageInfo (com.intellij.usageView.UsageInfo)1 IncorrectOperationException (com.intellij.util.IncorrectOperationException)1 HashMap (com.intellij.util.containers.hash.HashMap)1 PyFunctionBuilder (com.jetbrains.python.psi.impl.PyFunctionBuilder)1 NotNull (org.jetbrains.annotations.NotNull)1