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

org.walkmod.javalang.compiler.reflection.CompatibleMethodReferencePredicate Maven / Gradle / Ivy

There is a newer version: 2.3.10
Show newest version
/*
 * Copyright (C) 2015 Raquel Pau and Albert Coroleu.
 * 
 * Walkmod is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * 
 * Walkmod is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with Walkmod. If
 * not, see .
 */
package org.walkmod.javalang.compiler.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.walkmod.javalang.ast.expr.Expression;
import org.walkmod.javalang.ast.expr.MethodReferenceExpr;
import org.walkmod.javalang.ast.expr.SuperExpr;
import org.walkmod.javalang.compiler.ArrayFilter;
import org.walkmod.javalang.compiler.Predicate;
import org.walkmod.javalang.compiler.symbols.ReferenceType;
import org.walkmod.javalang.compiler.symbols.SymbolTable;
import org.walkmod.javalang.compiler.symbols.SymbolType;
import org.walkmod.javalang.visitors.VoidVisitor;

public class CompatibleMethodReferencePredicate extends CompatibleArgsPredicate implements Predicate {

    private MethodReferenceExpr expression = null;

    private VoidVisitor typeResolver;

    private A ctx;

    private SymbolType sd;

    private List methodCallCandidates = null;

    private SymbolTable symTable;

    private Class thisClass;

    private Method[] methodsArray = null;

    public CompatibleMethodReferencePredicate(MethodReferenceExpr expression, VoidVisitor typeResolver, A ctx,
            Map mapping, SymbolTable symTable) {
        this.expression = expression;
        this.typeResolver = typeResolver;
        this.symTable = symTable;
        this.ctx = ctx;
        setTypeMapping(mapping);
        thisClass = symTable.getType("this").getClazz();
    }

    @Override
    public boolean filter(T elem) throws Exception {
        int elemParameterCount = 0;
        Type[] genericParameterTypes = null;
        Class declaringClass = null;
        if (elem instanceof Method) {
            elemParameterCount = ((Method) elem).getParameterTypes().length;
            genericParameterTypes = ((Method) elem).getGenericParameterTypes();
            declaringClass = ((Method) elem).getDeclaringClass();
        } else if (elem instanceof Constructor) {
            elemParameterCount = ((Constructor) elem).getParameterTypes().length;
            genericParameterTypes = ((Constructor) elem).getGenericParameterTypes();
            declaringClass = ((Constructor) elem).getDeclaringClass();
        } else {
            return false;
        }
        Object equivalentMethod = null;

        sd = (SymbolType) expression.getScope().getSymbolData();
        if (sd == null) {
            expression.getScope().accept(typeResolver, ctx);
            sd = (SymbolType) expression.getScope().getSymbolData();

            if (!expression.getIdentifier().equals("new")) {

                if (methodsArray == null) {
                    Set methods = MethodInspector.getVisibleMethods(sd.getClazz(), thisClass);
                    methodsArray = new Method[methods.size()];
                    methods.toArray(methodsArray);
                    ExecutableSorter sorter = new ExecutableSorter();

                    List sortedMethods = sorter.sort(methodsArray, null);
                    sortedMethods.toArray(methodsArray);
                }

                ArrayFilter filter = new ArrayFilter(methodsArray);

                filter.appendPredicate(new MethodsByNamePredicate(expression.getIdentifier()));
                methodCallCandidates = filter.filter();
            }

        }
        boolean found = false;
        if (!expression.getIdentifier().equals("new")) {
            Iterator it = methodCallCandidates.iterator();

            while (it.hasNext() && !found) {

                Method md = it.next();
                int mdParameterCount = md.getParameterTypes().length;

                Map typeMapping = getTypeMapping();
                FunctionalGenericsBuilder builder =
                        new FunctionalGenericsBuilder(md, typeResolver, typeMapping);
                builder.build(expression);
                SymbolType[] args = builder.getArgs();
                if (!Modifier.isStatic(md.getModifiers())) {

                    if (mdParameterCount == elemParameterCount - 1) {
                        // may be, just taking into account the type variables,
                        // it matches
                        SymbolType[] genericArgs = new SymbolType[genericParameterTypes.length];
                        boolean allAreGenerics = true;
                        for (int i = 0; i < genericParameterTypes.length && allAreGenerics; i++) {
                            if (genericParameterTypes[i] instanceof TypeVariable) {
                                TypeVariable td = (TypeVariable) genericParameterTypes[i];
                                genericArgs[i] = typeMapping.get(td.getName());
                                allAreGenerics = genericArgs[i] != null;
                            } else {
                                allAreGenerics = false;
                            }
                        }
                        if (allAreGenerics) {
                            setTypeArgs(genericArgs);
                            found = super.filter(elem);
                        } else {
                            // the implicit parameter is an argument of the
                            // invisible
                            // lambda
                            SymbolType[] staticArgs = new SymbolType[args.length + 1];
                            for (int i = 0; i < args.length; i++) {
                                staticArgs[i + 1] = args[i];
                            }
                            staticArgs[0] = (SymbolType) sd;
                            args = staticArgs;
                            setTypeArgs(args);
                            found = super.filter(elem);
                        }

                    } else {

                        Expression scope = expression.getScope();

                        SymbolType stype = (SymbolType) scope.getSymbolData();
                        boolean isField = stype.getField() != null;
                        boolean isVariable = false;
                        boolean isSuper = scope instanceof SuperExpr;
                        if (!isField && !isSuper) {
                            String name = scope.toString();
                            isVariable = (symTable.findSymbol(name, ReferenceType.VARIABLE) != null);
                        }
                        // it is a variable
                        if ((isField || isVariable || isSuper) && mdParameterCount == elemParameterCount) {
                            setTypeArgs(args);
                            found = super.filter(elem);

                        }
                    }

                } else if (mdParameterCount == elemParameterCount) {
                    setTypeArgs(args);
                    found = super.filter(elem);
                }
                if (found) {
                    equivalentMethod = md;
                }

            }
        } else {
            Constructor[] constructors = sd.getClazz().getDeclaredConstructors();

            for (int i = 0; i < constructors.length && !found; i++) {

                FunctionalGenericsBuilder builder =
                        new FunctionalGenericsBuilder(constructors[i], typeResolver,
                                getTypeMapping());
                builder.build(expression);

                SymbolType[] args = builder.getArgs();
                setTypeArgs(args);

                found = super.filter(elem);
                if (found) {
                    equivalentMethod = constructors[i];
                }
            }
        }
        if (found && elem instanceof Method) {

            Map mapping = getTypeMapping();
            SymbolType realResultType = null;
            if (equivalentMethod instanceof Method) {

                // R apply(T t); -> Quote::parse ( T= String y R = Quote)
                realResultType = SymbolType.valueOf((Method) equivalentMethod, mapping);

                java.lang.reflect.Type genericReturnType = ((Method) elem).getGenericReturnType();
                resolveTypeMapping(genericReturnType, realResultType, mapping);
            }
            realResultType = SymbolType.valueOf(declaringClass, mapping);
            expression.setSymbolData(realResultType);

            SymbolType st = SymbolType.valueOf((Method) elem, mapping);
            expression.setReferencedMethodSymbolData(st);
            expression.setReferencedArgsSymbolData(getTypeArgs());
        }
        return found;
    }

    private void resolveTypeMapping(java.lang.reflect.Type type, SymbolType reference,
            Map mapping) {

        if (type instanceof TypeVariable) {
            TypeVariable tv = (TypeVariable) type;
            SymbolType st = mapping.get(tv.getName());
            if (st == null || "java.lang.Object".equals(st.getName())) {
                mapping.put(tv.getName(), reference);
            } else {
                mapping.put(tv.getName(), (SymbolType) reference.merge(st));
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy