Package ro.redeul.google.go.inspection.fix

Source Code of ro.redeul.google.go.inspection.fix.CreateFunctionFix

package ro.redeul.google.go.inspection.fix;

import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import ro.redeul.google.go.editor.TemplateUtil;
import ro.redeul.google.go.lang.psi.GoFile;
import ro.redeul.google.go.lang.psi.expressions.GoExpr;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteral;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralFunction;
import ro.redeul.google.go.lang.psi.expressions.primary.GoCallOrConvExpression;
import ro.redeul.google.go.lang.psi.toplevel.GoFunctionDeclaration;
import ro.redeul.google.go.lang.psi.typing.GoType;
import ro.redeul.google.go.lang.psi.typing.GoTypeFunction;
import ro.redeul.google.go.lang.psi.typing.GoTypes;
import ro.redeul.google.go.util.GoUtil;

import java.util.ArrayList;
import java.util.List;

import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.findParentOfType;

public class CreateFunctionFix extends LocalQuickFixAndIntentionActionOnPsiElement {

    private PsiFile workingFile = null;

    public CreateFunctionFix(@Nullable PsiElement element) {
        super(element);
    }


    public CreateFunctionFix(PsiElement element, PsiElement resolve) {
        super(element);
    }

    public CreateFunctionFix(PsiElement element, PsiFile workingFile) {
        super(element);
        this.workingFile = workingFile;
    }

    /**
     * Helper method to generate function arguments type, based on param being passed to the function
     *
     * @param e          -> parent -> GoCallOrConvExpression
     * @param stringList List<String>
     * @return the generated arugment list ex: arg0 int, arg1 string
     */
    @Nullable
    public static String InspectionGenFuncArgs(PsiElement e, List<String> stringList) {
        StringBuilder stringBuilder = new StringBuilder();
        int arg = 0;
        final GoFile currentFile = (GoFile) e.getContainingFile();


        if (GoUtil.isFunctionNameIdentifier(e)) {
            GoCallOrConvExpression callOrConvExpression = findParentOfType(e, GoCallOrConvExpression.class);
            stringBuilder.append("(");
            for (GoExpr argument : callOrConvExpression.getArguments()) {
                if (arg != 0)
                    stringBuilder.append(',');

                stringBuilder.append(String.format("$v%d$ ", arg));
                stringList.add(String.format("arg%d", arg));

                PsiElement firstChildExp = argument.getFirstChild();
                GoType[] goTypes = argument.getType();

                if (goTypes.length > 0 && goTypes[0] != null) {
                    GoType goType = goTypes[0];
                    stringBuilder.append(GoTypes.getRepresentation(goType, currentFile));

                } else if (firstChildExp instanceof GoLiteral) {
                    /*
                     * Resolves the type of a literal
                     */
                    stringBuilder.append(((GoLiteral) firstChildExp).getType().name().toLowerCase());
                } else {

                    /*
                     * This block try to resolve the return type of a closure being called on the paramenter list
                     * ex: unresolvedFn(func()int{return 25*4}())
                     * will generate:
                     * func unresolvedFn(arg0 int){}
                     * @note i think any one will do that, but we never know :D
                     */
                    PsiElement firstChild = firstChildExp.getFirstChild();
                    if (firstChild instanceof GoLiteralFunction) {

                        GoType[] returnType = ((GoLiteralFunction) firstChild).getReturnTypes();
                        if (returnType.length > 0) {
                            stringBuilder.append("<berila>");
                        } else {
                            stringBuilder.append("interface{}");
                        }
                    } else if (firstChild instanceof GoLiteral) {
                        GoLiteral.Type type = ((GoLiteral) firstChild).getType();
                        //Fix TEST PR ##321 this only happens on test. i don't know why
                        if (type == GoLiteral.Type.Float || type == GoLiteral.Type.ImaginaryFloat) {
                            stringBuilder.append("float32");
                        } else {
                            stringBuilder.append(type.name().toLowerCase());
                        }
                    } else {
                        stringBuilder.append("interface{}");
                    }
                }
                arg++;
            }
            stringBuilder.append(")");
        } else {
            /*
             * Try to resolve the type declaration for the generated function based on called function
             * ex: when http.HandleFunc("/",myIndexHandle)
             * will generate:
             *          func myIndexHandle(arg0 http.ResponseWriter, arg1 *http.Request){}
             */

            GoCallOrConvExpression callExpression = findParentOfType(e, GoCallOrConvExpression.class);
            GoType[] type = callExpression.getBaseExpression().getType();

            if ( type.length != 1 || ! (type[0] instanceof GoTypeFunction) )
                return "";

            GoTypeFunction function = (GoTypeFunction) type[0];

            int pos = -1;
            for (GoExpr expr : callExpression.getArguments()) {
                pos++;
                if ( expr.getTextOffset() == e.getTextOffset() && expr.getTextLength() == e.getTextLength() )
                    break;
            }

            GoType desiredType = function.getParameterType(pos);

            if ( desiredType instanceof GoTypeFunction ) {
                GoTypeFunction typeFunction = (GoTypeFunction) desiredType;
                int i = 0;

                stringBuilder.append("(");
                GoType parameterType = null;
                while ( (parameterType = typeFunction.getParameterType(i)) != null) {
                    stringList.add(String.format("arg%d", i));

                    if ( i > 0 )
                        stringBuilder.append(",");

                    stringBuilder.append(String.format("$v%d$ ", i));
                    stringBuilder.append(GoTypes.getRepresentation(parameterType, currentFile));
                    i++;
                }
                stringBuilder.append(")");

                GoType[] results = typeFunction.getResultTypes();
                if ( results.length > 1 ) stringBuilder.append("(");
                for (int i1 = 0; i1 < results.length; i1++) {
                    GoType goType = results[i1];
                    if( i1 > 0)
                        stringBuilder.append(",");
                    stringBuilder.append(GoTypes.getRepresentation(goType, currentFile));
                }
                if ( results.length > 1 ) stringBuilder.append(")");
            }
        }

        return stringBuilder.toString();
    }

    @NotNull
    @Override
    public String getText() {
        return "Create function \"" + getStartElement().getText() + "\"";
    }

    @NotNull
    @Override
    public String getFamilyName() {
        return "Variable Declaration";
    }


    @Override
    public void invoke(@NotNull final Project project,
                       @NotNull PsiFile file,
                       @Nullable("is null when called from inspection") Editor editor,
                       @NotNull final PsiElement startElement, @NotNull PsiElement endElement) {
        final PsiElement e;
        int insertPoint;
        final PsiFile wFile;
        ArrayList<String> arguments = new ArrayList<String>();
        final String fnArguments = InspectionGenFuncArgs(startElement, arguments);
        if (workingFile == null) {
            wFile = file;
            e = startElement;
            GoFunctionDeclaration fd = findParentOfType(e, GoFunctionDeclaration.class);
            while (fd instanceof GoLiteralFunction) {
                fd = findParentOfType(fd.getParent(), GoFunctionDeclaration.class);
            }


            if (fd != null) {
                insertPoint = fd.getTextRange().getEndOffset();
            } else {
                insertPoint = file.getTextRange().getEndOffset();
            }

        } else {
            e = startElement.getLastChild();
            insertPoint = workingFile.getTextLength();
            FileEditorManager.getInstance(project).openFile(workingFile.getVirtualFile(), true, true);
            wFile = this.workingFile;
        }


        Document doc = PsiDocumentManager.getInstance(project).getDocument(wFile);
        if (doc == null) {
            return;
        }

        if (((GoFile) wFile).getPackageName().equals("")) {
            String packStr = String.format("\npackage %s", startElement.getFirstChild().getText());
            doc.insertString(insertPoint, packStr);
            insertPoint += packStr.length();
        }

        TemplateImpl template = TemplateUtil.createTemplate(String.format("\n\nfunc %s%s { \n$v%d$$END$\n}", e.getText(), fnArguments, arguments.size()));
        arguments.add("//TODO: implements " + e.getText());
        TemplateUtil.runTemplate(editor, insertPoint, arguments, template);
    }

    private static final String TEMPLATE = "" +
            "" +
            "func $functionName$()#if($returnCount > 1)()#end {" +
            "   $END$" +
            "#if($returnCount > 0)  return#{else}}#end";
}
TOP

Related Classes of ro.redeul.google.go.inspection.fix.CreateFunctionFix

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.