All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.walkmod.javalang.compiler.analyze.OverrideAnalyzer Maven / Gradle / Ivy

There is a newer version: 2.3.7
Show newest version
package org.walkmod.javalang.compiler.analyze;

import org.walkmod.javalang.ast.MethodSymbolData;
import org.walkmod.javalang.ast.SymbolData;
import org.walkmod.javalang.ast.body.MethodDeclaration;
import org.walkmod.javalang.ast.body.ModifierSet;
import org.walkmod.javalang.ast.body.Parameter;
import org.walkmod.javalang.compiler.reflection.ClassInspector;
import org.walkmod.javalang.compiler.reflection.MethodInspector;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 *
 */
public class OverrideAnalyzer {

    /**
     * Returns if a method declaration overrides or implements another method.
     * @param md the method declaration
     * @return true if method declaration overrides or implements another method
     * */
    public static boolean isMethodOverride(MethodDeclaration md) {
        return collectOverriddenMethods(md, null);
    }

    /**
     * Returns the methods overridden by given method declaration
     * @param md the method declaration
     * @return the methods overridden by given method declaration
     * */
    public static List findOverriddenMethods(MethodDeclaration md) {
        final List methods = new ArrayList();
        collectOverriddenMethods(md, methods);
        return methods.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(methods);
    }

    /**
     * Returns if any of the overriddenMethods overrides an specific method declaration.
     * @param md the method declaration
    * @param overriddenMethods if != null add all methods to collection otherwise return on first match
    * @return true if at least one method of the overriddenMethods overrides an specific method declaration.
    */
    private static boolean collectOverriddenMethods(MethodDeclaration md,
            /* Nullable */ List overriddenMethods) {
        final MethodSymbolData sdata = md.getSymbolData();

        if (sdata == null || isStatic(sdata.getMethod()) || isPrivate(sdata.getMethod())) {
            return false;
        } else {
            boolean result = false;

            final Class declaringClass = sdata.getMethod().getDeclaringClass();
            final Class parentClass = declaringClass.getSuperclass();
            final Class[] interfaces = declaringClass.getInterfaces();

            if (parentClass != null || interfaces.length > 0) {
                final SymbolData[] args = getParameterSymbolData(md);

                List> scopesToCheck = new LinkedList>();
                if (parentClass != null) {
                    scopesToCheck.add(parentClass);
                }
                for (int i = 0; i < interfaces.length; i++) {
                    scopesToCheck.add(interfaces[i]);
                }
                final Iterator> it = scopesToCheck.iterator();
                while (it.hasNext() && !result) {
                    final Class clazzToAnalyze = it.next();

                    final Method foundMethod = MethodInspector.findMethod(clazzToAnalyze, args, md.getName());
                    if (foundMethod != null) {
                        if (foundMethod.getDeclaringClass().isAssignableFrom(clazzToAnalyze)) {
                            List types = ClassInspector.getInterfaceOrSuperclassImplementations(declaringClass,
                                    clazzToAnalyze);
                            Class returnType = null;
                            if (types != null && !types.isEmpty()) {
                                if (types.get(0) instanceof Class) {
                                    returnType = (Class) types.get(0);
                                }
                            }

                            if (matchesReturnAndParameters(foundMethod, returnType, args)) {
                                if (overriddenMethods != null) {
                                    overriddenMethods.add(foundMethod);
                                } else {
                                    result = true;
                                }
                            }
                        }
                    }
                }
            }
            return overriddenMethods != null ? !overriddenMethods.isEmpty() : result;
        }
    }

    private static SymbolData[] getParameterSymbolData(MethodDeclaration md) {
        // it should be initialized after resolving the method
        List params = md.getParameters();
        SymbolData[] args;
        if (params != null) {
            args = new SymbolData[params.size()];
            int i = 0;
            for (Parameter param : params) {
                args[i] = param.getType().getSymbolData();
                i++;
            }
        } else {
            args = new SymbolData[0];
        }
        return args;
    }

    private static boolean matchesReturnAndParameters(Method m, /* @Nullable */ Class returnType,
            SymbolData[] args) {
        Type[] parameterTypes = m.getGenericParameterTypes();
        int modifiers = m.getModifiers();
        boolean valid = ModifierSet.isPublic(modifiers) || ModifierSet.isProtected(modifiers);
        for (int i = 0; i < parameterTypes.length && valid; i++) {
            final Type parameterType = parameterTypes[i];
            final SymbolData arg = args[i];
            if (parameterType instanceof Class) {
                valid = (arg.getClazz().getName().equals(((Class) parameterType).getName()));
            } else if (parameterType instanceof TypeVariable) {
                TypeVariable tv = (TypeVariable) parameterType;
                if (returnType != null) {
                    TypeVariable[] tvs = returnType.getTypeParameters();
                    int pos = -1;
                    for (int k = 0; k < tvs.length && pos == -1; k++) {
                        if (tvs[k].getName().equals(tv.getName())) {
                            pos = k;
                        }
                    }
                    if (pos > -1) {
                        Type[] bounds = tvs[pos].getBounds();
                        for (int k = 0; k < bounds.length && valid; k++) {
                            if (bounds[k] instanceof Class) {
                                valid = arg.getClazz().isAssignableFrom((Class) bounds[k]);
                            }
                        }
                    }
                }
            } else if (parameterType instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) parameterType;
                valid = arg.getClazz().isAssignableFrom((Class) pt.getRawType());
            }
        }
        return valid;
    }

    private static boolean isStatic(Method m) {
        return Modifier.isStatic(m.getModifiers());
    }

    private static boolean isPrivate(Method m) {
        return Modifier.isPrivate(m.getModifiers());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy