Package com.yiistorm.helpers

Source Code of com.yiistorm.helpers.PsiPhpHelper

package com.yiistorm.helpers;

import com.intellij.ide.util.gotoByName.GotoClassModel2;
import com.intellij.openapi.project.Project;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.PsiWhiteSpace;
import com.jetbrains.php.lang.parser.PhpElementTypes;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import org.apache.commons.lang.ArrayUtils;
import org.jetbrains.annotations.NotNull;

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

/**
* Class for managing and parsing Psi files for PHP
*
* @author Enrique Piatti
*/
public class PsiPhpHelper {

    public static final String LANGUAGE_PHP = "PHP";
    public static final String ASSIGNMENT_EXPRESSION = "Assignment expression";
    public static final String VARIABLE_DECLARATION = "Variable";
    public static final String VARIABLE = "variable";
    public static final String METHOD_REFERENCE = "Method reference";
    public static final String WHITE_SPACE = "WHITE_SPACE";
    public static final String ASSIGN = "assign";
    public static final String STATEMENT = "Statement";
    public static final String GROUP_STATEMENT = "Group statement";
    public static final String CLASS_METHOD = "Class method";
    public static final String CLASS = "Class";
    public static final String FILE = "FILE";
    public static final String ARROW = "arrow";
    public static final String COMMENT_BLOCK = "C style comment";
    public static final String COMMENT_LINE = "line comment";
    public static final String IDENTIFIER = "identifier";
    public static final String PARAMETER_LIST = "Parameter list";
    public static final String PARAMETER = "Parameter";
    public static final String STRING = "String";
    public static final String SINGLE_QUOTED_STRING = "single quoted string";
    public static final String DOUBLE_QUOTED_STRING = "double quoted string";
    public static final String EXTENDS_LIST = "Extends list";
    public static final String CLASS_REFERENCE = "Class reference";


    @NotNull
    private static String getElementType(PsiElement psiElement) {
        if (psiElement != null && psiElement.getNode() != null && psiElement.getNode().getElementType() != null) {
            return psiElement.getNode().getElementType().toString();
        }
        return "";
    }

    public static boolean isElementType(PsiElement psiElement, String type) {
        return isElementType(psiElement, new String[]{type});
    }

    public static boolean isElementType(PsiElement psiElement, String[] types) {
        if (psiElement != null && types != null) {
            String elementType = getElementType(psiElement);
            if (!elementType.isEmpty()) {
                for (String type : types) {
                    if (elementType.equals(type))
                        return true;
                }
            }
        }
        return false;
    }

    public static boolean isNotElementType(PsiElement psiElement, String[] types) {
        return !isElementType(psiElement, types);
    }

    public static boolean isNotElementType(PsiElement psiElement, String type) {
        return isNotElementType(psiElement, new String[]{type});
    }

    public static boolean isPhp(PsiElement psiElement) {
        return psiElement.getLanguage().getID().equals(LANGUAGE_PHP);
    }

    public static boolean isVariable(PsiElement psiElement) {
        String[] types = {VARIABLE_DECLARATION, VARIABLE};
        return isElementType(psiElement, types);
    }

    public static boolean isMethodRefence(PsiElement psiElement) {
        String[] types = {METHOD_REFERENCE};
        return isElementType(psiElement, types);
    }

    public static boolean isWhiteSpace(PsiElement psiElement) {
        String[] types = {WHITE_SPACE};
        return isElementType(psiElement, types);
    }

    public static boolean isIdentifier(PsiElement psiElement) {
        String[] types = {IDENTIFIER};
        return isElementType(psiElement, types);
    }

    public static boolean isNotWhiteSpaceOrComment(PsiElement psiElement) {
        String[] types = {WHITE_SPACE, COMMENT_BLOCK, COMMENT_LINE};
        return isNotElementType(psiElement, types);
    }

    public static boolean isAssignmentExpression(PsiElement psiElement) {
        String[] types = {ASSIGNMENT_EXPRESSION};
        return isElementType(psiElement, types);
    }

    public static boolean isAssign(PsiElement psiElement) {
        String[] types = {ASSIGN};
        return isElementType(psiElement, types);
    }

    public static boolean isStatement(PsiElement psiElement) {
        String[] types = {STATEMENT};
        return isElementType(psiElement, types);
    }

    public static boolean isClassMethod(PsiElement psiElement) {
        String[] types = {CLASS_METHOD};
        return isElementType(psiElement, types);
    }


    public static boolean isString(PsiElement psiElement) {
        String[] types = {STRING, SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING};
        boolean isAnyString = isElementType(psiElement, types);
        if (!isAnyString) {
            PsiElement parent = psiElement.getParent();
            String[] typeString = {STRING};
            return isElementType(parent, typeString);
        }
        return true;
    }

    public static boolean isParameterList(PsiElement psiElement) {
        String[] types = {PARAMETER_LIST};
        return isElementType(psiElement, types);
    }

    public static String getVarName(PsiElement psiElement) {
        if (getElementType(psiElement).equals(VARIABLE)) {
            return psiElement.getText();    // with "$"
        } else if (getElementType(psiElement).equals(VARIABLE_DECLARATION)) {
            //return psiElement.getChildren()[0].getText();
            return psiElement.getText();
        }
        return null;
    }

    public static boolean isArrow(PsiElement psiElement) {
        String[] types = {ARROW};
        return isElementType(psiElement, types);
    }

    public static boolean hasChainedMethod(PsiElement psiElement) {
        PsiElement[] children = psiElement.getChildren();
        if (children.length > 0) {
            PsiElement child = children[0];
            while (child != null) {
                if (isArrow(child))
                    return true;
                child = child.getNextSibling();
            }
        }
        return false;
    }

    /**
     * @param psiMethodReference
     * @return
     */
    public static String getMethodName(PsiElement psiMethodReference) {
        if (isMethodRefence(psiMethodReference)) {
            PsiElement[] children = psiMethodReference.getChildren();
            if (children.length > 0) {

                // This fails because getChildren is not returning all the children !! why???
                for (PsiElement child : children) {
                    if (isIdentifier(child)) {
                        return child.getText();
                    }
                }

                // the identifier after the arrow is the method name
                // TODO add support for static methods
                PsiElement child = children[0];
                boolean prevSiblingWasArrow = false;
                while (child != null) {
                    // if previous element was an arrow, and the element is an identifier (this bypass whitespaces...)
                    if (prevSiblingWasArrow && isIdentifier(child)) {
                        // and the next element is a parenthesis (this bypass properties)
                        PsiElement nextSibling = child.getNextSibling();
                        if (nextSibling != null && nextSibling.getText().equals("(")) {
                            return child.getText();
                        }
                    } else {
                        if (isArrow(child)) {
                            prevSiblingWasArrow = true;
                        } else if (!(child instanceof PsiWhiteSpace)) {
                            // allow methods separated of the arrow by whitespaces
                            prevSiblingWasArrow = false;
                        }
                    }
                    child = child.getNextSibling();
                }
            }
        }
        return null;
    }


    public static List<PsiElement> getChainedMethodReferences(PsiElement psiElement) {
        if (psiElement == null) {
            return null;
        }
        List<PsiElement> methods = new ArrayList<PsiElement>();
        if (isMethodRefence(psiElement)) {
            methods.add(psiElement);
        }
        PsiElement childMethodReference = PsiPhpHelper.findFirstChildOfType(psiElement, METHOD_REFERENCE);
        while (childMethodReference != null) {
            methods.add(childMethodReference);
            childMethodReference = PsiPhpHelper.findFirstChildOfType(childMethodReference, METHOD_REFERENCE);
        }

        if (methods.size() > 0) {
            Collections.reverse(methods);
        }

        return methods;
    }

    public static List<String> getChainedMethodNames(PsiElement psiElement) {
        if (psiElement == null) {
            return null;
        }

        List<String> methodNames = new ArrayList<String>();

        List<PsiElement> methods = getChainedMethodReferences(psiElement);
        if (methods != null) {
            for (PsiElement methodReference : methods) {
                String methodName = getMethodName(methodReference);
                if (methodName != null) {
                    methodNames.add(methodName);
                }
            }
        }

        return methodNames;

    }

    public static String getLastChainedMethodName(PsiElement psiElement) {
        List<String> methods = getChainedMethodNames(psiElement);
        if (methods != null && methods.size() > 0) {
            return methods.get(methods.size() - 1);
        }
        return null;
    }


    public static PsiElement findFirstChildOfType(PsiElement psiElement, String type) {
        PsiElement[] children = psiElement.getChildren();
        if (children.length > 0) {
            for (PsiElement child : children) {
                //  System.err.println(child.getNode().getElementType().toString() + " VVV " + child.getText());
                if (isElementType(child, new String[]{type})) {
                    return child;
                }
            }
        }
        return null;
    }


    public static PsiElement findNextSiblingOfType(PsiElement psiElement, String type) {
        String[] types = {type};
        return findNextSiblingOfType(psiElement, types);
    }

    public static PsiElement findNextSiblingOfType(PsiElement psiElement, String[] types) {
        PsiElement siblingElement = psiElement.getNextSibling();
        while (siblingElement != null && isNotElementType(siblingElement, types)) {
            siblingElement = siblingElement.getNextSibling();
        }
        return siblingElement;
    }

    public static PsiElement findPrevSiblingOfType(PsiElement psiElement, String type) {
        String[] types = {type};
        return findPrevSiblingOfType(psiElement, types);
    }

    public static PsiElement findPrevSiblingOfType(PsiElement psiElement, String[] types) {
        PsiElement siblingElement = psiElement.getPrevSibling();
        while (siblingElement != null && isNotElementType(siblingElement, types)) {
            siblingElement = siblingElement.getPrevSibling();
            //     System.err.println(siblingElement.getNode().getElementType().toString() + " <<< " + siblingElement.getText());
        }
        return siblingElement;
    }

    public static PsiElement findFirstParentOfType(PsiElement psiElement, String type) {
        String[] types = {type};
        return findFirstParentOfType(psiElement, types);
    }

    public static PsiElement findFirstParentOfType(PsiElement psiElement, String[] types) {
        return findFirstParentOfType(psiElement, types, null);
    }

    public static PsiElement findFirstParentOfType(PsiElement psiElement, String type, String limitType) {
        String[] types = {type};
        String[] limits = {limitType};
        return findFirstParentOfType(psiElement, types, limits);
    }

    public static PsiElement findFirstParentOfType(PsiElement psiElement, String[] types, String[] limitTypes) {
        if (psiElement != null) {
            PsiElement parentElement = psiElement.getParent();
            boolean isRequestingSecuredLimits = false;
            if (limitTypes != null && limitTypes.length > 0) {
                for (String limit : limitTypes) {
                    if (limit.equals(FILE) || limit.equals(CLASS) || limit.equals(GROUP_STATEMENT)) {
                        isRequestingSecuredLimits = true;
                        break;
                    }
                }
            }
            if (!isRequestingSecuredLimits) {
                String[] securityLimits = {FILE, CLASS, GROUP_STATEMENT};
                limitTypes = (String[]) ArrayUtils.addAll(limitTypes, securityLimits);
            }

            while (parentElement != null && isNotElementType(parentElement, types)) {
                if (limitTypes != null) {
                    if (isElementType(parentElement, limitTypes))
                        return null;
                }
                parentElement = parentElement.getParent();
            }
            return parentElement;
        }
        return null;

    }


    /**
     * The IDE is not returning the full list of children sometimes when using "PsiElemetn.getChildren()" I don'w know why, this method fixes that
     *
     * @return
     */
    @NotNull
    public static List<PsiElement> getFullListOfChildren(PsiElement psiElement) {
        List<PsiElement> children = new ArrayList<PsiElement>();
        if (psiElement != null) {
            // this doesn't work as expected for example for a Method Reference it returns only Class reference and Parameter List
            // it doesn't return the scope resolution (or arrow), psiwhitespaces (if exists), identifier (method name), etc...
            // PsiElement[] children = psiElement.getChildren();
            PsiElement child = psiElement.getFirstChild();
            while (child != null) {
                children.add(child);
                child = child.getNextSibling();
            }
        }
        return children;
    }

    /**
     * this returns a list because could be more than one class with the same name
     *
     * @param className
     * @param project
     * @return
     */
    @NotNull
    public static List<PsiElement> getPsiElementsFromClassName(String className, Project project) {
        List<String> classes = new ArrayList<String>();
        classes.add(className);
        return getPsiElementsFromClassesNames(classes, project);
    }

    /**
     * useful for go to declaration using only the class name
     *
     * @param classes
     * @param project
     * @return
     */
    @NotNull
    public static List<PsiElement> getPsiElementsFromClassesNames(List<String> classes, Project project) {
        List<PsiElement> psiElements = new ArrayList<PsiElement>();
        if (classes != null && project != null) {
            GotoClassModel2 model = new GotoClassModel2(project);
            for (String className : classes) {
                Object[] elements = model.getElementsByName(className, true, className);
                if (elements != null && elements.length > 0) {
                    for (Object element : elements) {
                        if (element instanceof PsiElement) {
                            psiElements.add((PsiElement) element);

                        }
                    }
                }
            }

        }
        return psiElements;
    }


    @NotNull
    public static List<PsiElement> findMethodInClass(String methodName, String className, Project project) {
        return findMethodInClass(methodName, className, project, false);
    }

    @NotNull
    public static List<PsiElement> findMethodInClass(String methodName, String className, Project project, boolean inherited) {
        List<PsiElement> methods = new ArrayList<PsiElement>();
        if (methodName != null && className != null && !methodName.isEmpty() && !className.isEmpty()) {
            List<PsiElement> classes = getPsiElementsFromClassName(className, project);
            if (classes.size() > 0) {
                for (PsiElement psiClass : classes) {
                    PsiElement method = findMethodInClass(methodName, psiClass, inherited);
                    if (method != null) {
                        methods.add(method);
                    }
                }
            }
        }
        return methods;
    }


    public static PsiElement findMethodInClass(String methodName, PsiElement psiClass) {
        return findMethodInClass(methodName, psiClass, false);
    }

    public static PsiElement findMethodInClass(String methodName, PsiElement psiClass, boolean inherited) {
        if (methodName != null && !methodName.isEmpty() && psiClass != null) {
            PsiElement[] children = psiClass.getChildren();
            PsiElement extendsList = null;
            for (PsiElement child : children) {
                if (isClassMethod(child)) {
                    if (methodName.equals(((PsiNamedElement) child).getName())) {
                        return child;
                    }
                } else if (inherited && isElementType(child, EXTENDS_LIST)) {
                    extendsList = child;
                }
            }

            // postponed read of inherited methods so original methods have higher priority
            if (extendsList != null) {
                PsiElement[] extendsElements = extendsList.getChildren();
                for (PsiElement extendsElement : extendsElements) {
                    if (isElementType(extendsElement, CLASS_REFERENCE)) {
                        List<PsiElement> classes = getPsiElementsFromClassName(extendsElement.getText(), extendsElement.getProject());
                        for (PsiElement parentClass : classes) {
                            PsiElement method = findMethodInClass(methodName, parentClass, true);
                            if (method != null) {
                                return method;
                            }
                        }
                        break;
                    }
                }
            }

        }
        return null;
    }


    public static String getParentClassName(PsiElement child) {
        return getExtendsClassName(child);
    }

    public static String getSuperClassName(PsiElement child) {
        PsiElement superclass = PsiPhpHelper.getSuperClassElement(child);
        return superclass.getText();
    }

    public static PsiElement getSuperClassElement(PsiElement child) {
        String parent = getExtendsClassNameForClass(child);
        List<PsiElement> classes = getPsiElementsFromClassName(parent, child.getProject());
        if (classes.size() > 0) {
            for (PsiElement parentClass : classes) {
                return getSuperClassElement(parentClass);
            }
        }
        return child;
    }

    public static boolean isExtendsSuperclass(PsiElement child, String superclass) {
        if (child == null) {
            return false;
        }

        try {
            PhpClass[] supers = ((PhpClass) child).getSupers();
            String className = ((PhpClass) child).getName().toLowerCase();
            if (className.equals(superclass.toLowerCase())) {
                return true;
            }
            for (PhpClass cl : supers) {
                if (cl.getName().toLowerCase().equals(superclass.toLowerCase())) {
                    return true;
                }
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    public static String getExtendsClassName(PsiElement child) {
        PsiElement psiClass = getClassElement(child);
        if (psiClass != null) {
            PsiElement[] children = psiClass.getChildren();
            for (PsiElement psiClassChild : children) {
                if (isElementType(psiClassChild, EXTENDS_LIST)) {
                    PsiElement[] extendsElements = psiClassChild.getChildren();
                    for (PsiElement extendsElement : extendsElements) {
                        if (isElementType(extendsElement, CLASS_REFERENCE)) {
                            return extendsElement.getText();

                        }
                    }
                    break;
                }
            }
        }
        return null;
    }

    public static String getExtendsClassNameForClass(PsiElement psiClass) {
        if (psiClass != null) {
            PsiElement[] children = psiClass.getChildren();
            for (PsiElement psiClassChild : children) {
                if (isElementType(psiClassChild, EXTENDS_LIST)) {
                    PsiElement[] extendsElements = psiClassChild.getChildren();
                    for (PsiElement extendsElement : extendsElements) {
                        if (isElementType(extendsElement, CLASS_REFERENCE)) {
                            return extendsElement.getText();

                        }
                    }
                    break;
                }
            }
        }
        return null;
    }


    public static PsiElement getparentClassElement(PsiElement child) {
        return getExtendsClassElement(child);
    }

    /**
     * returns the first class element (is possible to have more than one psiClass for the same class name but this only returns the first)
     *
     * @param child
     * @return
     */
    public static PsiElement getExtendsClassElement(PsiElement child) {
        String extendsClassName = getExtendsClassName(child);
        if (extendsClassName != null) {
            List<PsiElement> classes = getPsiElementsFromClassName(extendsClassName, child.getProject());
            for (PsiElement parentClass : classes) {
                return parentClass;
            }
        }
        return null;
    }

    public static PsiElement getClassElement(PsiElement child) {
        PsiElement[] elc = child.getContainingFile().getChildren();
        if (elc.length > 0 && elc[0] != null) {
            for (PsiElement element : elc[0].getChildren()) {
                if (PlatformPatterns.psiElement().withElementType(PhpElementTypes.CLASS).accepts(element)) {
                    return element;
                }
            }
        }
        return null;
    }

    public static String getClassName(PsiElement child) {
        PsiElement psiClass = getClassElement(child);
        if (psiClass != null) {
            PsiElement classNameElement = findNextSiblingOfType(psiClass.getFirstChild(), IDENTIFIER);
            if (classNameElement != null) {
                return classNameElement.getText();
            }
        }
        return null;
    }

    public static String getClassIdentifierName(PsiElement psiClass) {
        if (psiClass != null) {
            PsiElement classNameElement = findNextSiblingOfType(psiClass.getFirstChild(), IDENTIFIER);
            if (classNameElement != null) {
                return classNameElement.getText();
            }
        }
        return null;
    }


    @NotNull
    public static List<PsiNamedElement> getAllMethodsFromClass(@NotNull PsiElement psiClass, boolean includeInherited) {
        List<PsiNamedElement> methods = new ArrayList<PsiNamedElement>();
        PsiElement[] children = psiClass.getChildren();   // getFullListOfChildren

        PsiElement extendsList = null;

        for (PsiElement child : children) {
            if (isClassMethod(child)) {
                methods.add((PsiNamedElement) child);
            } else if (includeInherited && isElementType(child, EXTENDS_LIST)) {
                extendsList = child;
            }
        }

        // postponed read of inherited methods so the original methos are first on the list
        if (extendsList != null) {
            PsiElement[] extendsElements = extendsList.getChildren();
            for (PsiElement extendsElement : extendsElements) {
                if (isElementType(extendsElement, CLASS_REFERENCE)) {
                    List<PsiElement> classes = getPsiElementsFromClassName(extendsElement.getText(), extendsElement.getProject());
                    for (PsiElement parentClass : classes) {
                        methods.addAll(getAllMethodsFromClass(parentClass, true));
                    }
                    break;
                }
            }
        }

        return methods;
    }

    public static boolean isMethodProtected(@NotNull PsiElement psiMethod) {
        return psiMethod.getText().startsWith("protected");
    }

    public static boolean isMethodPublic(@NotNull PsiElement psiMethod) {
        return psiMethod.getText().startsWith("public");
    }

    public static boolean isMethodPrivate(@NotNull PsiElement psiMethod) {
        return psiMethod.getText().startsWith("private");
    }


    @NotNull
    public static List<PsiElement> getMethodParameters(@NotNull PsiElement psiMethod) {
        List<PsiElement> params = new ArrayList<PsiElement>();
        PsiElement parameterList = findFirstChildOfType(psiMethod, PARAMETER_LIST);
        if (parameterList != null) {
            PsiElement[] parameters = parameterList.getChildren();
            for (PsiElement parameter : parameters) {
                if (isElementType(parameter, PARAMETER)) {
                    params.add(parameter);
//                    PsiElement[] parameterChildren = parameter.getChildren();
//                    for(PsiElement child : parameterChildren){
//                        if(isElementType(child, VARIABLE)){
//                            params.add(child.getText());
//                        }
//                    }
                }
            }
        }
        return params;
    }

    public static String getParameterName(@NotNull PsiElement parameter) {
        List<PsiElement> parameterChildren = PsiPhpHelper.getFullListOfChildren(parameter); // parameter.getChildren();
        if (parameterChildren.size() > 0) {
            for (PsiElement child : parameterChildren) {
                if (isElementType(child, VARIABLE)) {
                    return child.getText();
                }
            }
        }
        return null;
    }

}
TOP

Related Classes of com.yiistorm.helpers.PsiPhpHelper

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.