Search in sources :

Example 6 with PyFunctionBuilder

use of com.jetbrains.python.psi.impl.PyFunctionBuilder in project intellij-community by JetBrains.

the class PyOverrideImplementUtil method buildOverriddenFunction.

private static PyFunctionBuilder buildOverriddenFunction(PyClass pyClass, PyFunction baseFunction, boolean implement) {
    final boolean overridingNew = PyNames.NEW.equals(baseFunction.getName());
    assert baseFunction.getName() != null;
    PyFunctionBuilder pyFunctionBuilder = new PyFunctionBuilder(baseFunction.getName(), baseFunction);
    final PyDecoratorList decorators = baseFunction.getDecoratorList();
    boolean baseMethodIsStatic = false;
    if (decorators != null) {
        if (decorators.findDecorator(PyNames.CLASSMETHOD) != null) {
            pyFunctionBuilder.decorate(PyNames.CLASSMETHOD);
        } else if (decorators.findDecorator(PyNames.STATICMETHOD) != null) {
            baseMethodIsStatic = true;
            pyFunctionBuilder.decorate(PyNames.STATICMETHOD);
        } else if (decorators.findDecorator(PyNames.PROPERTY) != null || decorators.findDecorator(PyNames.ABSTRACTPROPERTY) != null) {
            pyFunctionBuilder.decorate(PyNames.PROPERTY);
        }
    }
    final LanguageLevel level = LanguageLevel.forElement(pyClass);
    PyAnnotation anno = baseFunction.getAnnotation();
    if (anno != null && level.isAtLeast(LanguageLevel.PYTHON30)) {
        pyFunctionBuilder.annotation(anno.getText());
    }
    final TypeEvalContext context = TypeEvalContext.userInitiated(baseFunction.getProject(), baseFunction.getContainingFile());
    final List<PyParameter> baseParams = PyUtil.getParameters(baseFunction, context);
    for (PyParameter parameter : baseParams) {
        final PyNamedParameter namedParameter = parameter.getAsNamed();
        if (namedParameter != null) {
            final StringBuilder parameterBuilder = new StringBuilder();
            if (namedParameter.isPositionalContainer()) {
                parameterBuilder.append("*");
            } else if (namedParameter.isKeywordContainer()) {
                parameterBuilder.append("**");
            }
            parameterBuilder.append(namedParameter.getName());
            final PyAnnotation annotation = namedParameter.getAnnotation();
            if (annotation != null && level.isAtLeast(LanguageLevel.PYTHON30)) {
                parameterBuilder.append(annotation.getText());
            }
            final PyExpression defaultValue = namedParameter.getDefaultValue();
            if (defaultValue != null) {
                parameterBuilder.append("=");
                parameterBuilder.append(defaultValue.getText());
            }
            pyFunctionBuilder.parameter(parameterBuilder.toString());
        } else {
            pyFunctionBuilder.parameter(parameter.getText());
        }
    }
    PyClass baseClass = baseFunction.getContainingClass();
    assert baseClass != null;
    StringBuilder statementBody = new StringBuilder();
    boolean hadStar = false;
    List<String> parameters = new ArrayList<>();
    for (PyParameter parameter : baseParams) {
        final PyNamedParameter pyNamedParameter = parameter.getAsNamed();
        if (pyNamedParameter != null) {
            String repr = pyNamedParameter.getRepr(false);
            parameters.add(hadStar && !pyNamedParameter.isKeywordContainer() ? pyNamedParameter.getName() + "=" + repr : repr);
            if (pyNamedParameter.isPositionalContainer()) {
                hadStar = true;
            }
        } else if (parameter instanceof PySingleStarParameter) {
            hadStar = true;
        } else {
            parameters.add(parameter.getText());
        }
    }
    if (PyNames.TYPES_INSTANCE_TYPE.equals(baseClass.getQualifiedName()) || raisesNotImplementedError(baseFunction) || implement) {
        statementBody.append(PyNames.PASS);
    } else {
        if (!PyNames.INIT.equals(baseFunction.getName()) && context.getReturnType(baseFunction) != PyNoneType.INSTANCE || overridingNew) {
            statementBody.append("return ");
        }
        if (baseClass.isNewStyleClass(context)) {
            statementBody.append(PyNames.SUPER);
            statementBody.append("(");
            final LanguageLevel langLevel = ((PyFile) pyClass.getContainingFile()).getLanguageLevel();
            if (!langLevel.isPy3K()) {
                final String baseFirstName = !baseParams.isEmpty() ? baseParams.get(0).getName() : null;
                final String firstName = baseFirstName != null ? baseFirstName : PyNames.CANONICAL_SELF;
                PsiElement outerClass = PsiTreeUtil.getParentOfType(pyClass, PyClass.class, true, PyFunction.class);
                String className = pyClass.getName();
                final List<String> nameResult = Lists.newArrayList(className);
                while (outerClass != null) {
                    nameResult.add(0, ((PyClass) outerClass).getName());
                    outerClass = PsiTreeUtil.getParentOfType(outerClass, PyClass.class, true, PyFunction.class);
                }
                StringUtil.join(nameResult, ".", statementBody);
                statementBody.append(", ").append(firstName);
            }
            statementBody.append(").").append(baseFunction.getName()).append("(");
            // type.__new__ is explicitly decorated as @staticmethod in our stubs, but not in real Python code
            if (parameters.size() > 0 && !(baseMethodIsStatic || overridingNew)) {
                parameters.remove(0);
            }
        } else {
            statementBody.append(getReferenceText(pyClass, baseClass)).append(".").append(baseFunction.getName()).append("(");
        }
        StringUtil.join(parameters, ", ", statementBody);
        statementBody.append(")");
    }
    pyFunctionBuilder.statement(statementBody.toString());
    return pyFunctionBuilder;
}
Also used : TypeEvalContext(com.jetbrains.python.psi.types.TypeEvalContext) PyFunctionBuilder(com.jetbrains.python.psi.impl.PyFunctionBuilder) PsiElement(com.intellij.psi.PsiElement)

Example 7 with PyFunctionBuilder

use of com.jetbrains.python.psi.impl.PyFunctionBuilder in project intellij-community by JetBrains.

the class PyOverrideImplementUtil method write.

private static void write(@NotNull final PyClass pyClass, @NotNull final List<PyMethodMember> newMembers, @NotNull final Editor editor, boolean implement) {
    final PyStatementList statementList = pyClass.getStatementList();
    final int offset = editor.getCaretModel().getOffset();
    PsiElement anchor = null;
    for (PyStatement statement : statementList.getStatements()) {
        if (statement.getTextRange().getStartOffset() < offset || (statement instanceof PyExpressionStatement && ((PyExpressionStatement) statement).getExpression() instanceof PyStringLiteralExpression)) {
            anchor = statement;
        }
    }
    PyFunction element = null;
    for (PyMethodMember newMember : newMembers) {
        PyFunction baseFunction = (PyFunction) newMember.getPsiElement();
        final PyFunctionBuilder builder = buildOverriddenFunction(pyClass, baseFunction, implement);
        PyFunction function = builder.addFunctionAfter(statementList, anchor, LanguageLevel.forElement(statementList));
        element = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(function);
    }
    PyPsiUtils.removeRedundantPass(statementList);
    if (element != null) {
        final PyStatementList targetStatementList = element.getStatementList();
        final int start = targetStatementList.getTextRange().getStartOffset();
        editor.getCaretModel().moveToOffset(start);
        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
        editor.getSelectionModel().setSelection(start, element.getTextRange().getEndOffset());
    }
}
Also used : PyFunctionBuilder(com.jetbrains.python.psi.impl.PyFunctionBuilder) PsiElement(com.intellij.psi.PsiElement)

Example 8 with PyFunctionBuilder

use of com.jetbrains.python.psi.impl.PyFunctionBuilder in project intellij-community by JetBrains.

the class PyConvertLambdaToFunctionIntention method doInvoke.

public void doInvoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
    PyLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyLambdaExpression.class);
    if (lambdaExpression != null) {
        String name = "function";
        while (IntroduceValidator.isDefinedInScope(name, lambdaExpression)) {
            name += "1";
        }
        PsiElement parent = lambdaExpression.getParent();
        if (parent instanceof PyAssignmentStatement) {
            name = ((PyAssignmentStatement) parent).getLeftHandSideExpression().getText();
        }
        if (name.isEmpty())
            return;
        PyExpression body = lambdaExpression.getBody();
        PyFunctionBuilder functionBuilder = new PyFunctionBuilder(name, lambdaExpression);
        for (PyParameter param : lambdaExpression.getParameterList().getParameters()) {
            functionBuilder.parameter(param.getText());
        }
        functionBuilder.statement("return " + body.getText());
        PyFunction function = functionBuilder.buildFunction(project, LanguageLevel.getDefault());
        final PyStatement statement = PsiTreeUtil.getParentOfType(lambdaExpression, PyStatement.class);
        if (statement != null) {
            final PsiElement statementParent = statement.getParent();
            if (statementParent != null)
                function = (PyFunction) statementParent.addBefore(function, statement);
        }
        function = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(function);
        if (parent instanceof PyAssignmentStatement) {
            parent.delete();
        } else {
            PsiFile parentScope = lambdaExpression.getContainingFile();
            final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(parentScope);
            PsiElement functionName = function.getNameIdentifier();
            functionName = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(functionName);
            lambdaExpression = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(lambdaExpression);
            ReferenceNameExpression refExpr = new ReferenceNameExpression(name);
            ((TemplateBuilderImpl) builder).replaceElement(lambdaExpression, name, refExpr, true);
            ((TemplateBuilderImpl) builder).replaceElement(functionName, name, name, false);
            int textOffSet = functionName.getTextOffset();
            editor.getCaretModel().moveToOffset(parentScope.getTextRange().getStartOffset());
            Template template = ((TemplateBuilderImpl) builder).buildInlineTemplate();
            TemplateManager.getInstance(project).startTemplate(editor, template);
            editor.getCaretModel().moveToOffset(textOffSet);
        }
    }
}
Also used : PyFunctionBuilder(com.jetbrains.python.psi.impl.PyFunctionBuilder) PsiFile(com.intellij.psi.PsiFile) PsiElement(com.intellij.psi.PsiElement)

Example 9 with PyFunctionBuilder

use of com.jetbrains.python.psi.impl.PyFunctionBuilder in project intellij-community by JetBrains.

the class UnresolvedRefCreateFunctionQuickFix method applyFix.

public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
    final PyCallExpression callExpr = myCallExpr.getElement();
    final PyReferenceExpression referenceExpr = myReferenceExpr.getElement();
    if (callExpr == null || !callExpr.isValid() || referenceExpr == null || !referenceExpr.isValid()) {
        return;
    }
    final PyFunctionBuilder functionBuilder = new PyFunctionBuilder(referenceExpr.getText(), callExpr);
    // if function is actually an argument of a call, don't use other arguments of the call to create parameter list of new function
    final PyArgumentList argumentList = callExpr.getArgumentList();
    if (argumentList != null && !PsiTreeUtil.isAncestor(argumentList, referenceExpr, false)) {
        for (PyExpression param : argumentList.getArguments()) {
            if (param instanceof PyKeywordArgument) {
                functionBuilder.parameter(((PyKeywordArgument) param).getKeyword());
            } else if (param instanceof PyReferenceExpression) {
                PyReferenceExpression refex = (PyReferenceExpression) param;
                functionBuilder.parameter(refex.getReferencedName());
            } else {
                functionBuilder.parameter("param");
            }
        }
    } else {
        functionBuilder.parameter("args");
    }
    PyFunction function = functionBuilder.buildFunction(project, LanguageLevel.getDefault());
    final InjectedLanguageManager instance = InjectedLanguageManager.getInstance(project);
    final PsiLanguageInjectionHost host = instance.getInjectionHost(callExpr);
    final PsiElement insertAnchor = host != null ? host : callExpr;
    final PyFunction parentFunction = PsiTreeUtil.getTopmostParentOfType(insertAnchor, PyFunction.class);
    if (parentFunction != null) {
        final PyClass parentClass = PsiTreeUtil.getTopmostParentOfType(parentFunction, PyClass.class);
        if (parentClass != null) {
            final PsiElement parent = parentClass.getParent();
            function = (PyFunction) parent.addBefore(function, parentClass);
        } else {
            final PsiElement parent = parentFunction.getParent();
            function = (PyFunction) parent.addBefore(function, parentFunction);
        }
    } else {
        final PyStatement statement = PsiTreeUtil.getTopmostParentOfType(insertAnchor, PyStatement.class);
        if (statement != null) {
            final PsiElement parent = statement.getParent();
            if (parent != null) {
                function = (PyFunction) parent.addBefore(function, statement);
            }
        }
    }
    function = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(function);
    final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(function);
    ParamHelper.walkDownParamArray(function.getParameterList().getParameters(), new ParamHelper.ParamVisitor() {

        public void visitNamedParameter(PyNamedParameter param, boolean first, boolean last) {
            builder.replaceElement(param, param.getName());
        }
    });
    builder.replaceElement(function.getStatementList(), PyNames.PASS);
    final FileEditor editor = FileEditorManager.getInstance(project).getSelectedEditor(insertAnchor.getContainingFile().getVirtualFile());
    if (!(editor instanceof TextEditor)) {
        return;
    }
    builder.run(((TextEditor) editor).getEditor(), false);
}
Also used : FileEditor(com.intellij.openapi.fileEditor.FileEditor) ParamHelper(com.jetbrains.python.psi.impl.ParamHelper) TemplateBuilder(com.intellij.codeInsight.template.TemplateBuilder) InjectedLanguageManager(com.intellij.lang.injection.InjectedLanguageManager) TextEditor(com.intellij.openapi.fileEditor.TextEditor) PyFunctionBuilder(com.jetbrains.python.psi.impl.PyFunctionBuilder) PsiLanguageInjectionHost(com.intellij.psi.PsiLanguageInjectionHost) PsiElement(com.intellij.psi.PsiElement)

Example 10 with PyFunctionBuilder

use of com.jetbrains.python.psi.impl.PyFunctionBuilder in project intellij-community by JetBrains.

the class PyExtractMethodUtil method generateMethodFromElements.

@NotNull
private static PyFunction generateMethodFromElements(@NotNull final Project project, @NotNull final String methodName, @NotNull final AbstractVariableData[] variableData, @NotNull final List<PsiElement> elementsRange, @Nullable PyUtil.MethodFlags flags, boolean isAsync) {
    assert !elementsRange.isEmpty() : "Empty statements list was selected!";
    final PyFunctionBuilder builder = new PyFunctionBuilder(methodName, elementsRange.get(0));
    if (isAsync) {
        builder.makeAsync();
    }
    addDecorators(builder, flags);
    addFakeParameters(builder, variableData);
    final PyFunction method = builder.buildFunction(project, LanguageLevel.forElement(elementsRange.get(0)));
    final PyStatementList statementList = method.getStatementList();
    for (PsiElement element : elementsRange) {
        if (element instanceof PsiWhiteSpace) {
            continue;
        }
        statementList.add(element);
    }
    // remove last instruction
    final PsiElement child = statementList.getFirstChild();
    if (child != null) {
        child.delete();
    }
    PsiElement last = statementList;
    while (last != null) {
        last = last.getLastChild();
        if (last instanceof PsiWhiteSpace) {
            last.delete();
        }
    }
    return method;
}
Also used : PyFunctionBuilder(com.jetbrains.python.psi.impl.PyFunctionBuilder) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

PyFunctionBuilder (com.jetbrains.python.psi.impl.PyFunctionBuilder)12 PsiElement (com.intellij.psi.PsiElement)7 NotNull (org.jetbrains.annotations.NotNull)4 IncorrectOperationException (com.intellij.util.IncorrectOperationException)3 PsiFile (com.intellij.psi.PsiFile)2 PyType (com.jetbrains.python.psi.types.PyType)2 TypeEvalContext (com.jetbrains.python.psi.types.TypeEvalContext)2 TemplateBuilder (com.intellij.codeInsight.template.TemplateBuilder)1 InjectedLanguageManager (com.intellij.lang.injection.InjectedLanguageManager)1 FileEditor (com.intellij.openapi.fileEditor.FileEditor)1 TextEditor (com.intellij.openapi.fileEditor.TextEditor)1 PsiLanguageInjectionHost (com.intellij.psi.PsiLanguageInjectionHost)1 RefactoringElementListenerComposite (com.intellij.refactoring.listeners.RefactoringElementListenerComposite)1 AbstractVariableData (com.intellij.refactoring.util.AbstractVariableData)1 UsageInfo (com.intellij.usageView.UsageInfo)1 HashMap (com.intellij.util.containers.hash.HashMap)1 PyInspectionExtension (com.jetbrains.python.inspections.PyInspectionExtension)1 ParamHelper (com.jetbrains.python.psi.impl.ParamHelper)1 PyClassType (com.jetbrains.python.psi.types.PyClassType)1 PyModuleType (com.jetbrains.python.psi.types.PyModuleType)1