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

spoon.template.Substitution Maven / Gradle / Ivy

/* 
 * Spoon - http://spoon.gforge.inria.fr/
 * Copyright (C) 2006 INRIA Futurs 
 * 
 * This software is governed by the CeCILL-C License under French law and
 * abiding by the rules of distribution of free software. You can use, modify 
 * and/or redistribute the software under the terms of the CeCILL-C license as 
 * circulated by CEA, CNRS and INRIA at http://www.cecill.info. 
 * 
 * This program 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 CeCILL-C License for more details.
 *  
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL-C license and that you accept its terms.
 */

package spoon.template;

import java.util.List;

import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtStatement;
import spoon.reflect.declaration.CtAnonymousExecutable;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtSimpleType;
import spoon.reflect.declaration.CtType;
import spoon.reflect.reference.CtPackageReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.ReferenceTypeFilter;
import spoon.support.template.Parameters;
import spoon.support.template.SubstitutionVisitor;

/**
 * This class defines the substitution API for templates (see {@link Template}).
 */
public abstract class Substitution {

	private Substitution() {
	}

	/**
	 * Inserts all the methods, fields, constructors, initialization blocks (if
	 * target is a class), inner types, and super interfaces (except
	 * {@link Template}) from a given template by substituting all the template
	 * parameters by their values. Members annotated with
	 * {@link spoon.template.Local} or {@link Parameter} are not inserted.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the source template
	 */
	public static  void insertAll(CtType targetType,
			T template) {

		CtClass templateClass = targetType.getFactory().Class()
				.get(template.getClass());
		// insert all the interfaces
		for (CtTypeReference t : templateClass.getSuperInterfaces()) {
			if (!t.equals(targetType.getFactory().Type()
					.createReference(Template.class))) {
				CtTypeReference t1 = t;
				// substitute ref if needed
				if (Parameters.getNames(templateClass).contains(
						t.getSimpleName())) {
					Object o = Parameters.getValue(template, t.getSimpleName(),
							null);
					if (o instanceof CtTypeReference) {
						t1 = (CtTypeReference) o;
					} else if (o instanceof Class) {
						t1 = targetType.getFactory().Type()
								.createReference((Class) o);
					} else if (o instanceof String) {
						t1 = targetType.getFactory().Type()
								.createReference((String) o);
					}
				}
				if (!t1.equals(targetType.getReference())) {
					Class c = null;
					try {
						c = t1.getActualClass();
					} catch (Exception e) {
						// swallow it
					}
					if (c != null && c.isInterface()) {
						targetType.addSuperInterface(t1);
					}
					if (c == null) {
						targetType.addSuperInterface(t1);
					}
				}
			}
		}
		// insert all the methods
		for (CtMethod m : templateClass.getMethods()) {
			if (m.getAnnotation(Local.class) != null)
				continue;
			if (m.getAnnotation(Parameter.class) != null)
				continue;
			insertMethod(targetType, template, m);
		}
		// insert all the constructors
		if (targetType instanceof CtClass) {
			for (CtConstructor c : templateClass.getConstructors()) {
				if (c.isImplicit())
					continue;
				if (c.getAnnotation(Local.class) != null)
					continue;
				insertConstructor((CtClass) targetType, template, c);
			}
		}
		// insert all the initialization blocks (only for classes)
		if (targetType instanceof CtClass) {
			for (CtAnonymousExecutable e : templateClass
					.getAnonymousExecutables()) {
				((CtClass) targetType).addAnonymousExecutable(substitute(
						targetType, template, e));
			}
		}
		// insert all the fields
		for (CtField f : templateClass.getFields()) {
			if (f.getAnnotation(Local.class) != null)
				continue;
			if (Parameters.isParameterSource(f.getReference()))
				continue;

			insertField(targetType, template, f);
		}
		// insert all the inner types
		for (CtSimpleType t : templateClass.getNestedTypes()) {
			if (t.getAnnotation(Local.class) != null)
				continue;
			CtSimpleType result = substitute(templateClass, template, t);
			targetType.addNestedType(result);
		}

	}

	/**
	 * Inserts all the super interfaces (except {@link Template}) from a given
	 * template by substituting all the template parameters by their values.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the source template
	 */
	public static void insertAllSuperInterfaces(CtType targetType,
			Template template) {

		CtClass sourceClass = targetType.getFactory()
				.Class().get(template.getClass());
		// insert all the interfaces
		for (CtTypeReference t : sourceClass.getSuperInterfaces()) {
			if (!t.equals(targetType.getFactory().Type()
					.createReference(Template.class))) {
				CtTypeReference t1 = t;
				// substitute ref if needed
				if (Parameters.getNames(sourceClass)
						.contains(t.getSimpleName())) {
					Object o = Parameters.getValue(template, t.getSimpleName(),
							null);
					if (o instanceof CtTypeReference) {
						t1 = (CtTypeReference) o;
					} else if (o instanceof Class) {
						t1 = targetType.getFactory().Type()
								.createReference((Class) o);
					} else if (o instanceof String) {
						t1 = targetType.getFactory().Type()
								.createReference((String) o);
					}
				}
				if (!t1.equals(targetType.getReference())) {
					Class c = t1.getActualClass();
					if (c != null && c.isInterface()) {
						targetType.addSuperInterface(t1);
					}
					if (c == null) {
						targetType.addSuperInterface(t1);
					}
				}
			}
		}
	}

	/**
	 * Inserts all the methods from a given template by substituting all the
	 * template parameters by their values. Members annotated with
	 * {@link spoon.template.Local} or {@link Parameter} are not inserted.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the source template
	 */
	public static void insertAllMethods(CtType targetType, Template template) {

		CtClass sourceClass = targetType.getFactory().Class()
				.get(template.getClass());
		// insert all the methods
		for (CtMethod m : sourceClass.getMethods()) {
			if (m.getAnnotation(Local.class) != null)
				continue;
			if (m.getAnnotation(Parameter.class) != null)
				continue;
			insertMethod(targetType, template, m);
		}
	}

	/**
	 * Inserts all the fields from a given template by substituting all the
	 * template parameters by their values. Members annotated with
	 * {@link spoon.template.Local} or {@link Parameter} are not inserted.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the source template
	 */
	public static void insertAllFields(CtType targetType, Template template) {

		CtClass sourceClass = targetType.getFactory().Class()
				.get(template.getClass());
		// insert all the fields
		for (CtField f : sourceClass.getFields()) {
			if (f.getAnnotation(Local.class) != null)
				continue;
			if (Parameters.isParameterSource(f.getReference()))
				continue;

			insertField(targetType, template, f);
		}
	}

	/**
	 * Inserts all constructors and initialization blocks from a given template
	 * by substituting all the template parameters by their values. Members
	 * annotated with {@link spoon.template.Local} or {@link Parameter} are not
	 * inserted.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the source template
	 */
	public static void insertAllConstructors(CtType targetType,
			Template template) {

		CtClass sourceClass = targetType.getFactory().Class()
				.get(template.getClass());
		// insert all the constructors
		if (targetType instanceof CtClass) {
			for (CtConstructor c : sourceClass.getConstructors()) {
				if (c.isImplicit())
					continue;
				if (c.getAnnotation(Local.class) != null)
					continue;
				insertConstructor((CtClass) targetType, template, c);
			}
		}
		// insert all the initialization blocks (only for classes)
		if (targetType instanceof CtClass) {
			for (CtAnonymousExecutable e : sourceClass
					.getAnonymousExecutables()) {
				CtAnonymousExecutable e2 = substitute(targetType, template, e);
				((CtClass) targetType).addAnonymousExecutable(e2);
				// e2.setParent(targetType);
			}
		}
	}

	/**
	 * Generates a constructor from a template method by substituting all the
	 * template parameters by their values.
	 * 
	 * @param targetClass
	 *            the target class where to insert the generated constructor
	 * @param template
	 *            the template instance that holds the source template method
	 *            and that defines the parameter values
	 * @param sourceMethod
	 *            the source template method
	 * @return the generated method
	 */
	public static  CtConstructor insertConstructor(
			CtClass targetClass, Template template, CtMethod sourceMethod) {

		if (targetClass instanceof CtInterface)
			return null;
		CtConstructor newConstructor = targetClass.getFactory()
				.Constructor().create(targetClass, sourceMethod);
		newConstructor = substitute(targetClass, template, newConstructor);
		targetClass.addConstructor(newConstructor);
		// newConstructor.setParent(targetClass);
		return newConstructor;
	}

	/**
	 * Generates a method from a template method by substituting all the
	 * template parameters by their values.
	 * 
	 * @param targetType
	 *            the target type where to insert the generated method
	 * @param template
	 *            the template instance that holds the source template method
	 *            and that defines the parameter values
	 * @param sourceMethod
	 *            the source template method
	 * @return the generated method
	 */
	public static  CtMethod insertMethod(CtType targetType,
			Template template, CtMethod sourceMethod) {

		CtMethod newMethod = substitute(targetType, template, sourceMethod);
		if (targetType instanceof CtInterface)
			newMethod.setBody(null);
		targetType.addMethod(newMethod);
		// newMethod.setParent(targetType);
		return newMethod;
	}

	/**
	 * Generates a constructor from a template constructor by substituting all
	 * the template parameters by their values.
	 * 
	 * @param targetClass
	 *            the target class where to insert the generated constructor
	 * @param template
	 *            the template instance that holds the source template
	 *            constructor and that defines the parameter values
	 * @param sourceConstructor
	 *            the source template constructor
	 * @return the generated constructor
	 */
	@SuppressWarnings("unchecked")
	public static  CtConstructor insertConstructor(
			CtClass targetClass, Template template,
			CtConstructor sourceConstructor) {

		CtConstructor newConstrutor = substitute(targetClass, template,
				(CtConstructor) sourceConstructor);
		// remove the implicit constructor if clashing
		if (newConstrutor.getParameters().isEmpty()) {
			CtConstructor c = targetClass.getConstructor();
			if (c != null && c.isImplicit())
				targetClass.getConstructors().remove(c);
		}
		targetClass.addConstructor(newConstrutor);
		// newConstrutor.setParent(targetClass);
		return newConstrutor;
	}

	/**
	 * Gets a body from a template executable with all the template parameters
	 * substituted.
	 * 
	 * @param targetClass
	 *            the target class
	 * @param template
	 *            the template that holds the executable
	 * @param executableName
	 *            the source executable template
	 * @param parameterTypes
	 *            the parameter types of the source executable
	 * @return the body expression of the source executable template with all
	 *         the template parameters substituted
	 */
	public static CtBlock substituteMethodBody(CtClass targetClass,
			Template template, String executableName,
			CtTypeReference... parameterTypes) {
		CtClass sourceClass = targetClass.getFactory().Class()
				.get(template.getClass());
		CtExecutable sourceExecutable = executableName.equals(template
				.getClass().getSimpleName()) ? sourceClass
				.getConstructor(parameterTypes) : sourceClass.getMethod(
				executableName, parameterTypes);
		return substitute(targetClass, template, sourceExecutable.getBody());
	}

	/**
	 * Gets a statement from a template executable with all the template
	 * parameters substituted.
	 * 
	 * @param targetClass
	 *            the target class
	 * @param template
	 *            the template that holds the executable
	 * @param statementIndex
	 *            the statement index in the executable's body
	 * @param executableName
	 *            the source executable template
	 * @param parameterTypes
	 *            the parameter types of the source executable
	 * @return the body expression of the source executable template with all
	 *         the template parameters substituted
	 */
	public static CtStatement substituteStatement(CtClass targetClass,
			Template template, int statementIndex, String executableName,
			CtTypeReference... parameterTypes) {
		CtClass sourceClass = targetClass.getFactory().Class()
				.get(template.getClass());
		CtExecutable sourceExecutable = executableName.equals(template
				.getClass().getSimpleName()) ? sourceClass
				.getConstructor(parameterTypes) : sourceClass.getMethod(
				executableName, parameterTypes);
		return substitute(targetClass, template, sourceExecutable.getBody()
				.getStatement(statementIndex));
	}

	/**
	 * Gets a default expression from a template field with all the template
	 * parameters substituted.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the template that holds the field
	 * @param fieldName
	 *            the template source field
	 * @return the expression of the template source field with all the template
	 *         parameters substituted
	 */

	public static CtExpression substituteFieldDefaultExpression(
			CtSimpleType targetType, Template template, String fieldName) {
		CtClass sourceClass = targetType.getFactory().Class()
				.get(template.getClass());
		CtField sourceField = sourceClass.getField(fieldName);
		return substitute(targetType, template,
				sourceField.getDefaultExpression());
	}

	/**
	 * Substitutes all the template parameters in a random piece of code.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the template instance
	 * @param code
	 *            the code
	 * @return the code where all the template parameters has been substituted
	 *         by their values
	 */
	public static  E substitute(
			CtSimpleType targetType, Template template, E code) {
		if (code == null)
			return null;
		if (targetType == null)
			throw new RuntimeException("target is null in substitution");
		E result = targetType.getFactory().Core().clone(code);
		new SubstitutionVisitor(targetType.getFactory(), targetType, template)
				.scan(result);
		return result;
	}

	/**
	 * Substitutes all the template parameters in the first template element
	 * annotated with an instance of the given annotation type.
	 * 
	 * @param targetType
	 *            the target type
	 * @param template
	 *            the template instance
	 * @param annotationType
	 *            the annotation type
	 * @return the element where all the template parameters has be substituted
	 *         by their values
	 */
	// public static  E substitute(
	// CtSimpleType targetType, Template template,
	// Class annotationType) {
	// CtClass c = targetType.getFactory().Class
	// .get(template.getClass());
	// E element = (E) c.getAnnotatedChildren(annotationType).get(0);
	// if (element == null)
	// return null;
	// if (targetType == null)
	// throw new RuntimeException("target is null in substitution");
	// E result = CtCloner.clone(element);
	// new SubstitutionVisitor(targetType.getFactory(), targetType, template)
	// .scan(result);
	// return result;
	// }
	/**
	 * Substitutes all the template parameters in a given template type and
	 * returns the resulting type.
	 * 
	 * @param template
	 *            the template instance (holds the parameter values)
	 * @param templateType
	 *            the template type
	 * @return a copy of the template type where all the parameters has been
	 *         substituted
	 */
	public static > T substitute(Template template,
			T templateType) {
		T result = templateType.getFactory().Core().clone(templateType);
		result.setPositions(null);
		// result.setParent(templateType.getParent());
		new SubstitutionVisitor(templateType.getFactory(), result, template)
				.scan(result);
		return result;
	}

	/**
	 * Generates a field (and its initialization expression) from a template
	 * field by substituting all the template parameters by their values.
	 * 
	 * @param 
	 *            the type of the field
	 * @param targetType
	 *            the target type where the field is inserted
	 * @param template
	 *            the template that defines the source template field
	 * @param sourceField
	 *            the source template field
	 * @return the inserted field
	 */
	public static  CtField insertField(CtType targetType,
			Template template, CtField sourceField) {
		CtField field = substitute(targetType, template, sourceField);
		targetType.addField(field);
		// field.setParent(targetType);
		return field;
	}

	/**
	 * A helper method that recursively redirects all the type references from a
	 * source type to a target type in the given element.
	 */
	public static void redirectTypeReferences(CtElement element,
			CtTypeReference source, CtTypeReference target) {

		List> refs = Query.getReferences(element,
				new ReferenceTypeFilter>(
						CtTypeReference.class));

		String srcName = source.getQualifiedName();
		String targetName = target.getSimpleName();
		CtPackageReference targetPackage = target.getPackage();

		for (CtTypeReference ref : refs) {
			if (ref.getQualifiedName().equals(srcName)) {
				ref.setSimpleName(targetName);
				ref.setPackage(targetPackage);
			}
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy