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

org.walkmod.javalang.compiler.reflection.AbstractCompatibleFunctionalPredicate 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.ParameterizedType;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
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.LambdaExpr;
import org.walkmod.javalang.ast.expr.MethodReferenceExpr;
import org.walkmod.javalang.compiler.ArrayFilter;
import org.walkmod.javalang.compiler.Predicate;
import org.walkmod.javalang.compiler.PreviousPredicateAware;
import org.walkmod.javalang.compiler.symbols.SymbolTable;
import org.walkmod.javalang.compiler.symbols.SymbolType;
import org.walkmod.javalang.visitors.VoidVisitor;

public abstract class AbstractCompatibleFunctionalPredicate implements
		PreviousPredicateAware {

	private VoidVisitor typeResolver;
	private List args;
	private T ctx = null;
	private SymbolType scope;
	private Map typeMapping;

	private Class[] params;
	private boolean isVarArgs;
	private SymbolTable symTable;
	private SymbolType[] calculatedTypeArgs;

	private AbstractCompatibleArgsPredicate previousPredicate;

	public AbstractCompatibleFunctionalPredicate(SymbolType scope,
			VoidVisitor typeResolver, List args, T ctx,
			SymbolTable symTable,
			AbstractCompatibleArgsPredicate previousPredicate,
			SymbolType[] calculatedTypeArgs) {
		this.typeResolver = typeResolver;
		this.args = args;
		this.ctx = ctx;
		this.scope = scope;
		this.symTable = symTable;
		this.previousPredicate = previousPredicate;
		this.calculatedTypeArgs = calculatedTypeArgs;
	}

	private void createEquivalenceMapping(
			java.lang.reflect.Type classToInspect,
			java.lang.reflect.Type receivedParameter,
			Map> equivalences) {

		if (classToInspect instanceof Class) {
			Class clazz1 = (Class) classToInspect;
			TypeVariable[] params1 = clazz1.getTypeParameters();
			if (receivedParameter instanceof Class) {
				Class clazz2 = (Class) receivedParameter;
				TypeVariable[] params2 = clazz2.getTypeParameters();
				for (int i = 0; i < params1.length; i++) {
					createEquivalenceMapping(params1[i], params2[i],
							equivalences);
				}
			} else if (receivedParameter instanceof ParameterizedType) {
				ParameterizedType ptype = (ParameterizedType) receivedParameter;
				java.lang.reflect.Type[] typeArgs = ptype
						.getActualTypeArguments();
				for (int i = 0; i < params1.length; i++) {
					createEquivalenceMapping(params1[i], typeArgs[i],
							equivalences);
				}
			}
		} else if (classToInspect instanceof TypeVariable) {
			TypeVariable tv1 = (TypeVariable) classToInspect;
			if (receivedParameter instanceof TypeVariable) {
				TypeVariable tv2 = (TypeVariable) receivedParameter;
				List list = equivalences.get(tv2.getName());
				if (list == null) {
					list = new LinkedList();
				}
				list.add(tv1.getName());
				equivalences.put(tv2.getName(), list);
			} else if (receivedParameter instanceof WildcardType) {
				WildcardType wildcard = (WildcardType) receivedParameter;
				java.lang.reflect.Type[] bounds = wildcard.getUpperBounds();
				for (int i = 0; i < bounds.length; i++) {
					createEquivalenceMapping(classToInspect, bounds[i],
							equivalences);
				}
				bounds = wildcard.getLowerBounds();
				for (int i = 0; i < bounds.length; i++) {
					createEquivalenceMapping(classToInspect, bounds[i],
							equivalences);
				}
			}
		}

	}

	public Map createMapping(Class classToInspect,
			java.lang.reflect.Type interfaceToInspect, SymbolType inferredArg,
			Class declaringClass) throws Exception {
		Map typeMapping = new HashMap();

		// infers the type mapping of the scope
		GenericsBuilderFromClassParameterTypes builder = new GenericsBuilderFromClassParameterTypes(
				typeMapping, scope, symTable);
		builder.build(declaringClass);
		typeMapping = builder.getTypeMapping();

		// we want to infer the type mapping of the class that contains the
		// method that
		// is represented by a lambda expression using the type variables that
		// appear in the generic parameter
		Map update = new HashMap();

		Map> equivalences = new HashMap>();
		createEquivalenceMapping(classToInspect, interfaceToInspect,
				equivalences);
		Set keys = equivalences.keySet();

		for (String key : keys) {
			if (typeMapping.containsKey(key)) {
				List list = equivalences.get(key);
				for (String key2 : list) {
					update.put(key2, typeMapping.get(key));
				}
			}
		}

		keys = typeMapping.keySet();
		for (String key : keys) {
			if (!equivalences.containsKey(key)) {
				update.put(key, typeMapping.get(key));
			}
		}

		if (inferredArg != null) {
			// acording the template variables of the representative class,
			// which are the corresponding SymbolTypes?
			Map paramsTypeMapping = new HashMap();
			SymbolType.valueOf(classToInspect, inferredArg, paramsTypeMapping,
					null);

			// we delete the inferred Object classes
			Map subset = new HashMap();
			keys = paramsTypeMapping.keySet();
			for (String key : keys) {
				SymbolType st1 = paramsTypeMapping.get(key);
				Class clazz = st1.getClazz();
				if (!Object.class.equals(clazz)) {
					subset.put(key, st1);
				}

			}
			// we override the values defined by the generics that the scope
			// gives.
			update.putAll(subset);

		}

		return update;
	}

	public boolean filter(LambdaExpr lambda, Class interfaceToInspect,
			java.lang.reflect.Type equivalentTypeToInspect,
			SymbolType inferredArg, ClassdeclaringClass) throws Exception {

		boolean found = false;

		Method[] methods = interfaceToInspect.getMethods();

		ArrayFilter filter = new ArrayFilter(methods);

		Map typeMapping = createMapping(interfaceToInspect,
				equivalentTypeToInspect, inferredArg, declaringClass);
		CompatibleLambdaArgsPredicate predArgs = new CompatibleLambdaArgsPredicate(
				lambda);
		predArgs.setTypeMapping(typeMapping);

		filter.appendPredicate(
				new LambdaParamsTypeResolver(lambda, typeResolver, typeMapping))
				.appendPredicate(new AbstractMethodsPredicate())
				.appendPredicate(predArgs)
				.appendPredicate(
						new CompatibleLambdaResultPredicate(lambda,
								typeResolver, ctx, typeMapping, symTable));
		found = filter.filterOne() != null;
		return found;
	}

	public boolean filter(MethodReferenceExpr methodRef,
			Class interfaceToInspect,
			java.lang.reflect.Type equivalentTypeToInspect,
			SymbolType inferredArg, Class declaringClass) throws Exception {

		boolean found = false;
		Map aux = createMapping(interfaceToInspect,
				equivalentTypeToInspect, inferredArg, declaringClass);
		if (typeMapping != null) {
			aux.putAll(typeMapping);
		}
		CompatibleMethodReferencePredicate predArgs = new CompatibleMethodReferencePredicate(
				methodRef, typeResolver, ctx, aux, symTable);

		Set methodsSet = MethodInspector.getVisibleMethods(interfaceToInspect, symTable.getType("this").getClazz());
		Method[] methods = new Method[methodsSet.size()];
		methodsSet.toArray(methods);
		
		ArrayFilter filter = new ArrayFilter(methods);
		filter.appendPredicate(new AbstractMethodsPredicate());
		filter.appendPredicate(predArgs);
		found = filter.filterOne() != null;

		return found;
	}

	public boolean filter(Method method) throws Exception {
		return filter(method.getGenericParameterTypes(), method.getDeclaringClass());
	}
	public boolean filter(Constructor method) throws Exception {
		return filter(method.getGenericParameterTypes(), method.getDeclaringClass());
	}
	
	public boolean filter(java.lang.reflect.Type[] genericTypes, Class declaringClass) throws Exception {

		boolean found = false;
		boolean containsLambda = false;
		SymbolType[] inferredTypes = null;
		if (previousPredicate != null) {
			inferredTypes = previousPredicate.getInferredMethodArgs();
		}
		if (args != null && !args.isEmpty()) {
			Iterator it = args.iterator();
			int i = 0;
			while (it.hasNext() && !found) {
				SymbolType argType = null;
				if (inferredTypes != null) {
					argType = inferredTypes[i];
				}
				Expression current = it.next();
				if (current instanceof LambdaExpr
						|| current instanceof MethodReferenceExpr) {

					containsLambda = true;
					Class interfaceToInspect = null;

					if (inferredTypes[i].getClazz().isInterface()) {
						interfaceToInspect = inferredTypes[i].getClazz();

					} else if (isVarArgs && i == params.length - 1) {
						Class componentType = inferredTypes[i].getClazz();
						if (componentType.isInterface()) {
							interfaceToInspect = componentType;
						}
					}
					if (interfaceToInspect != null) {
						if (current instanceof LambdaExpr) {
							found = filter((LambdaExpr) current,
									interfaceToInspect, genericTypes[i],
									argType,declaringClass);
							if (found) {
								calculatedTypeArgs[i] = (SymbolType) current
										.getSymbolData();
							}
						} else {
							found = filter((MethodReferenceExpr) current,
									interfaceToInspect, genericTypes[i],
									argType, declaringClass);
							if (found) {
								calculatedTypeArgs[i] = (SymbolType) current
										.getSymbolData();
							}
						}
					}

				}
				if (i < params.length - 1) {
					i++;
				}

			}
		}

		return (found && containsLambda) || !containsLambda;
	}

	public void setTypeMapping(Map typeMapping) {
		this.typeMapping = typeMapping;
	}

	public Class[] getParams() {
		return params;
	}

	public void setParams(Class[] params) {
		this.params = params;
	}

	public boolean isVarArgs() {
		return isVarArgs;
	}

	public void setVarArgs(boolean isVarArgs) {
		this.isVarArgs = isVarArgs;
	}

	public void setPreviousPredicate(Predicate pred) {
		if (pred instanceof AbstractCompatibleArgsPredicate) {
			this.previousPredicate = (AbstractCompatibleArgsPredicate) pred;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy