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

spoon.template.TemplateBuilder Maven / Gradle / Ivy

Go to download

Spoon is a tool for meta-programming, analysis and transformation of Java programs.

There is a newer version: 11.1.1-beta-14
Show newest version
/*
 * SPDX-License-Identifier: (MIT OR CECILL-C)
 *
 * Copyright (C) 2006-2023 INRIA and contributors
 *
 * Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) or the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
 */
package spoon.template;


import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import spoon.SpoonException;
import spoon.pattern.Pattern;
import spoon.pattern.PatternBuilderHelper;
import spoon.pattern.internal.node.ListOfNodes;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtTypeReference;
import spoon.support.template.Parameters;
import spoon.support.util.ImmutableMapImpl;

/**
 * Internal class used to provide pattern-based implementation of Template and TemplateMatcher
 */
class TemplateBuilder {

	/**
	 * Creates a {@link TemplateBuilder}, which builds {@link Pattern} from {@link Template}
	 * @param templateRoot the root element of {@link Template} model
	 * @param template a instance of the {@link Template}. It is needed here,
	 * 			because parameter value types influences which AST nodes will be the target of substitution
	 * @return {@link TemplateBuilder}
	 */
	public static TemplateBuilder createTemplateBuilder(CtElement templateRoot, Template template) {
		CtClass> templateType = Substitution.getTemplateCtClass(templateRoot.getFactory(), template);
		return createTemplateBuilder(templateRoot, templateType, template);
	}
	//needed to provide access to protected members
	private static class PatternBuilder extends spoon.pattern.PatternBuilder {

		PatternBuilder(List template) {
			super(template);
		}

		ListOfNodes getListOfNodes() {
			return new ListOfNodes(patternNodes.getNodes());
		}
	}

	/**
	 * Creates a {@link TemplateBuilder}, which builds {@link Pattern} from {@link Template}
	 * @param templateRoot the root element of {@link Template} model
	 * @param templateType {@link CtClass} model of `template`
	 * @param template a instance of the {@link Template}. It is needed here,
	 * 			because parameter value types influences which AST nodes will be the target of substitution
	 * @return
	 */
	public static TemplateBuilder createTemplateBuilder(CtElement templateRoot, CtClass templateType, Template template) {
		Factory f = templateRoot.getFactory();

		if (template != null && !templateType.getQualifiedName().equals(template.getClass().getName())) {
			throw new SpoonException("Unexpected template instance " + template.getClass().getName() + ". Expects " + templateType.getQualifiedName());
		}

		PatternBuilder pb;

		@SuppressWarnings("rawtypes")
		CtTypeReference templateParamRef = f.Type().createReference(TemplateParameter.class);
		if (templateType == templateRoot) {
			//templateRoot is a class which extends from Template. We have to remove all Templating stuff from the patter model
			PatternBuilderHelper tv = new PatternBuilderHelper(templateType);
			{
				tv.keepTypeMembers(typeMember -> {
					if (typeMember.getAnnotation(Parameter.class) != null) {
						//remove all type members annotated with @Parameter
						return false;
					}
					if (typeMember.getAnnotation(Local.class) != null) {
						//remove all type members annotated with @Local
						return false;
					}
					//remove all Fields of type TemplateParameter
					return !(typeMember instanceof CtField) || !((CtField) typeMember).getType().isSubtypeOf(templateParamRef);
				});
				//remove `... extends Template`, which doesn't have to be part of pattern model
				tv.removeSuperClass();
			}
			pb = new PatternBuilder(tv.getPatternElements());
		} else {
			pb = new PatternBuilder(Collections.singletonList(templateRoot));
		}
		Map templateParameters = template == null ? null : Parameters.getTemplateParametersAsMap(f, template);
		pb.setAutoSimplifySubstitutions(template == null ? false : template.withPartialEvaluation());
		pb.configurePatternParameters(pc -> {
			pc.byTemplateParameter(templateParameters);
			pc.byParameterValues(templateParameters);
		});

		return new TemplateBuilder(templateType, pb, template);
	}

	private Template template;
	private PatternBuilder patternBuilder;
	private CtClass templateType;

	private TemplateBuilder(CtClass templateType, PatternBuilder patternBuilder, Template template) {
		this.template = template;
		this.patternBuilder = patternBuilder;
		this.templateType = templateType;
	}

	/**
	 * @return a {@link Pattern} built by this {@link TemplateBuilder}
	 */
	public Pattern build() {
		return patternBuilder.build();
	}

	Pattern build(Consumer nodes) {
		nodes.accept(patternBuilder.getListOfNodes());
		return build();
	}

	/**
	 * @param addGeneratedBy true if "generated by" comments has to be added into code generated by {@link Pattern} made by this {@link TemplateBuilder}
	 * @return this to support fluent API
	 */
	public TemplateBuilder setAddGeneratedBy(boolean addGeneratedBy) {
		patternBuilder.setAddGeneratedBy(addGeneratedBy);
		return this;
	}

	/**
	 * @return Map of template parameters from `template`
	 */
	public Map getTemplateParameters() {
		return getTemplateParameters(null);
	}
	/**
	 * @param targetType the type which will receive the model generated using returned parameters
	 * @return Map of template parameters from `template`
	 */
	public Map getTemplateParameters(CtType targetType) {
		Factory f = templateType.getFactory();
		Map templateParametersAsMap = Parameters.getTemplateParametersAsMap(f, template);
		if (targetType != null) {
			templateParametersAsMap.put(spoon.pattern.PatternBuilder.TARGET_TYPE, targetType.getReference());
		}
		return templateParametersAsMap;
	}

	/**
	 * generates a new AST node made by cloning of `patternModel` and by substitution of parameters by their values
	 * @param targetType the CtType, which will receive the result of substitution
	 * @return a substituted element
	 */
	public  T substituteSingle(CtType targetType, Class itemType) {
		return (T) build().generator().generate(new ImmutableMapImpl(getTemplateParameters(targetType))).get(0);
	}
	/**
	 * generates a new AST nodes made by cloning of `patternModel` and by substitution of parameters by their values
	 * @param factory TODO
	 * @param targetType the CtType, which will receive the result of substitution
	 * @return List of substituted elements
	 */
	public  List substituteList(Factory factory, CtType targetType, Class itemType) {
		return build().generator().generate(getTemplateParameters(targetType));
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy