Package fr.adrienbrault.idea.symfony2plugin

Source Code of fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil

package fr.adrienbrault.idea.symfony2plugin;

import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.MethodReference;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
* @author Adrien Brault <adrien.brault@gmail.com>
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class Symfony2InterfacesUtil {

    public boolean isContainerGetCall(PsiElement e) {
        return isCallTo(e, new Method[] {
            getInterfaceMethod(e.getProject(), "\\Symfony\\Component\\DependencyInjection\\ContainerInterface", "get"),
            getClassMethod(e.getProject(), "\\Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "get"),
        });
    }

    public boolean isContainerGetCall(Method e) {
        return isCallTo(e, new Method[] {
            getInterfaceMethod(e.getProject(), "\\Symfony\\Component\\DependencyInjection\\ContainerInterface", "get"),
            getClassMethod(e.getProject(), "\\Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "get"),
        });
    }

    public boolean isTemplatingRenderCall(PsiElement e) {
        return isCallTo(e, new Method[] {
            getInterfaceMethod(e.getProject(), "\\Symfony\\Component\\Templating\\EngineInterface", "render"),
            getInterfaceMethod(e.getProject(), "\\Symfony\\Component\\Templating\\StreamingEngineInterface", "stream"),
            getInterfaceMethod(e.getProject(), "\\Symfony\\Bundle\\FrameworkBundle\\Templating\\EngineInterface", "renderResponse"),
            getClassMethod(e.getProject(), "\\Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "render"),
            getClassMethod(e.getProject(), "\\Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "renderView"),
            getClassMethod(e.getProject(), "\\Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "stream"),
        });
    }

    public boolean isTranslatorCall(PsiElement e) {
        return isCallTo(e, new Method[] {
                getInterfaceMethod(e.getProject(), "\\Symfony\\Component\\Translation\\TranslatorInterface", "trans"),
                getInterfaceMethod(e.getProject(), "\\Symfony\\Component\\Translation\\TranslatorInterface", "transChoice"),
        });
    }

    public boolean isGetRepositoryCall(Method e) {
        return isCallTo(e, new Method[] {
            getInterfaceMethod(e.getProject(), "\\Doctrine\\Common\\Persistence\\ManagerRegistry", "getRepository"),
            getInterfaceMethod(e.getProject(), "\\Doctrine\\Common\\Persistence\\ObjectManager", "getRepository"),
        });
    }

    public boolean isObjectRepositoryCall(Method e) {
        return isCallTo(e, new Method[] {
            getInterfaceMethod(e.getProject(), "\\Doctrine\\Common\\Persistence\\ObjectRepository", "find"),
            getInterfaceMethod(e.getProject(), "\\Doctrine\\Common\\Persistence\\ObjectRepository", "findOneBy"),
            getInterfaceMethod(e.getProject(), "\\Doctrine\\Common\\Persistence\\ObjectRepository", "findAll"),
            getInterfaceMethod(e.getProject(), "\\Doctrine\\Common\\Persistence\\ObjectRepository", "findBy"),
        });
    }

    public boolean isFormBuilderFormTypeCall(PsiElement e) {
        List<Method> methods = getCallToSignatureInterfaceMethods(e, getFormBuilderInterface());
        return isCallTo(e, methods.toArray( new Method[methods.size()]));
    }

    protected boolean isCallTo(PsiElement e, Method expectedMethod) {
        return isCallTo(e, new Method[] { expectedMethod });
    }

    protected boolean isCallTo(PsiElement e, Method[] expectedMethods) {
        return isCallTo(e, expectedMethods, 1);
    }

    protected boolean isCallTo(Method e, Method[] expectedMethods) {

        PhpClass methodClass = e.getContainingClass();
        if(methodClass == null) {
            return false;
        }

        for (Method expectedMethod : expectedMethods) {

            // @TODO: its stuff from beginning times :)
            if(expectedMethod == null) {
                continue;
            }

            PhpClass containingClass = expectedMethod.getContainingClass();
            if (containingClass != null && expectedMethod.getName().equals(e.getName()) && isInstanceOf(methodClass, containingClass)) {
                return true;
            }
        }

        return false;
    }


    protected boolean isCallTo(PsiElement e, Method[] expectedMethods, int deepness) {
        if (!(e instanceof MethodReference)) {
            return false;
        }

        MethodReference methodRef = (MethodReference) e;

        // resolve is also called on invalid php code like "use <xxx>"
        // so double check the method name before resolve the method
        if(!isMatchingMethodName(methodRef, expectedMethods)) {
            return false;
        }

        PsiReference psiReference = methodRef.getReference();
        if (null == psiReference) {
            return false;
        }

        Method method = getMultiResolvedMethod(psiReference);
        if (method == null) {
            return false;
        }

        PhpClass methodClass = method.getContainingClass();
        if(methodClass == null) {
            return false;
        }

        for (Method expectedMethod : expectedMethods) {

            // @TODO: its stuff from beginning times :)
            if(expectedMethod == null) {
                continue;
            }

            PhpClass containingClass = expectedMethod.getContainingClass();
            if (null != containingClass && expectedMethod.getName().equals(method.getName()) && isInstanceOf(methodClass, containingClass)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Single resolve doesnt work if we have non unique class names in project context,
     * so try a multiResolve and use first matched method
     */
    @Nullable
    protected static Method getMultiResolvedMethod(PsiReference psiReference) {

        // class be unique in normal case, so try this first
        PsiElement resolvedReference = psiReference.resolve();
        if (resolvedReference instanceof Method) {
            return (Method) resolvedReference;
        }

        // try multiResolve if class exists twice in project
        if(psiReference instanceof PsiPolyVariantReference) {
            for(ResolveResult resolveResult : ((PsiPolyVariantReference) psiReference).multiResolve(false)) {
                PsiElement element = resolveResult.getElement();
                if(element instanceof Method) {
                    return (Method) element;
                }
            }
        }

        return null;
    }

    protected boolean isMatchingMethodName(MethodReference methodRef, Method[] expectedMethods) {
        for (Method expectedMethod : Arrays.asList(expectedMethods)) {
            if(expectedMethod != null && expectedMethod.getName().equals(methodRef.getName())) {
                return true;
            }
        }

        return false;
    }

    @Deprecated
    @Nullable
    public static String getFirstArgumentStringValue(MethodReference e) {
        String stringValue = null;

        PsiElement[] parameters = e.getParameters();
        if (parameters.length > 0 && parameters[0] instanceof StringLiteralExpression) {
            stringValue = ((StringLiteralExpression) parameters[0]).getContents();
        }

        return stringValue;
    }

    @Nullable
    protected Method getInterfaceMethod(Project project, String interfaceFQN, String methodName) {

        Collection<PhpClass> interfaces = PhpIndex.getInstance(project).getInterfacesByFQN(interfaceFQN);

        if (interfaces.size() < 1) {
            return null;
        }

        return findClassMethodByName(interfaces.iterator().next(), methodName);
    }

    @Nullable
    protected Method getClassMethod(Project project, String classFQN, String methodName) {
        return PhpElementsUtil.getClassMethod(project, classFQN, methodName);
    }

    @Nullable
    protected Method findClassMethodByName(PhpClass phpClass, String methodName) {
        return PhpElementsUtil.getClassMethod(phpClass, methodName);
    }

    protected boolean isImplementationOfInterface(PhpClass phpClass, PhpClass phpInterface) {
        if (phpClass == phpInterface) {
            return true;
        }

        for (PhpClass implementedInterface : phpClass.getImplementedInterfaces()) {
            if (isImplementationOfInterface(implementedInterface, phpInterface)) {
                return true;
            }
        }

        if (null == phpClass.getSuperClass()) {
            return false;
        }

        return isImplementationOfInterface(phpClass.getSuperClass(), phpInterface);
    }

    public boolean isInstanceOf(PhpClass subjectClass, String expectedClass) {

        PhpClass instanceClass = PhpElementsUtil.getClassInterface(subjectClass.getProject(), expectedClass);

        if(instanceClass == null) {
            return false;
        }

        return isInstanceOf(subjectClass, instanceClass);

    }

    public boolean isInstanceOf(Project project, String subjectClass, String expectedClass) {

        PhpClass subjectPhpClass = PhpElementsUtil.getClassInterface(project, subjectClass);
        if(subjectPhpClass == null) {
            return false;
        }

        return isInstanceOf(subjectPhpClass, expectedClass);

    }

    public boolean isInstanceOf(@NotNull PhpClass subjectClass, @NotNull PhpClass expectedClass) {
        if (subjectClass == expectedClass) {
            return true;
        }

        if (expectedClass.isInterface()) {
            return isImplementationOfInterface(subjectClass, expectedClass);
        }

        if (null == subjectClass.getSuperClass()) {
            return false;
        }

        return isInstanceOf(subjectClass.getSuperClass(), expectedClass);
    }

    public boolean isCallTo(MethodReference e, String ClassInterfaceName, String methodName) {
        return isCallTo((PsiElement) e, ClassInterfaceName, methodName);
    }

    /**
     * @deprecated isCallTo with MethodReference
     */
    public boolean isCallTo(PsiElement e, String ClassInterfaceName, String methodName) {

        // we need a full fqn name
        if(ClassInterfaceName.contains("\\") && !ClassInterfaceName.startsWith("\\")) {
            ClassInterfaceName = "\\" + ClassInterfaceName;
        }

        return isCallTo(e, new Method[] {
            getInterfaceMethod(e.getProject(), ClassInterfaceName, methodName),
            getClassMethod(e.getProject(), ClassInterfaceName, methodName),
        });
    }

    public boolean isCallTo(Method e, String ClassInterfaceName, String methodName) {

        // we need a full fqn name
        if(ClassInterfaceName.contains("\\") && !ClassInterfaceName.startsWith("\\")) {
            ClassInterfaceName = "\\" + ClassInterfaceName;
        }

        return isCallTo(e, new Method[] {
            getInterfaceMethod(e.getProject(), ClassInterfaceName, methodName),
            getClassMethod(e.getProject(), ClassInterfaceName, methodName),
        });
    }

    private List<Method> getCallToSignatureInterfaceMethods(PsiElement e, Collection<MethodMatcher.CallToSignature> signatures) {
        List<Method> methods = new ArrayList<Method>();
        for(MethodMatcher.CallToSignature signature: signatures) {
            Method method = getInterfaceMethod(e.getProject(), signature.getInstance(), signature.getMethod());
            if(method != null) {
                methods.add(method);
            }
        }
        return methods;
    }

    public static Collection<MethodMatcher.CallToSignature> getFormBuilderInterface() {
        Collection<MethodMatcher.CallToSignature> signatures = new ArrayList<MethodMatcher.CallToSignature>();

        signatures.add(new MethodMatcher.CallToSignature("\\Symfony\\Component\\Form\\FormBuilderInterface", "add"));
        signatures.add(new MethodMatcher.CallToSignature("\\Symfony\\Component\\Form\\FormBuilderInterface", "create"));
        signatures.add(new MethodMatcher.CallToSignature("\\Symfony\\Component\\Form\\FormInterface", "add"));
        signatures.add(new MethodMatcher.CallToSignature("\\Symfony\\Component\\Form\\FormInterface", "create"));

        return signatures;
    }

}
TOP

Related Classes of fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil

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.