/** * Copyright (C) 2006-2017 INRIA and contributors * Spoon - http://spoon.gforge.inria.fr/ * * 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.reflect.factory; import spoon.reflect.code.CtBlock; import spoon.reflect.code.CtLambda; import spoon.reflect.declaration.CtAnonymousExecutable; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtConstructor; import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtParameter; import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.ModifierKind; import spoon.reflect.reference.CtExecutableReference; import spoon.reflect.reference.CtParameterReference; import spoon.reflect.reference.CtTypeReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; import static spoon.reflect.ModelElementContainerDefaultCapacities.PARAMETERS_CONTAINER_DEFAULT_CAPACITY; /** * The {@link CtExecutable} sub-factory. */ public class ExecutableFactory extends SubFactory { /** * Creates a new executable sub-factory. * * @param factory * the parent factory */ public ExecutableFactory(Factory factory) { super(factory); } /** * Creates an anonymous executable (initializer block) in a target class). */ public CtAnonymousExecutable createAnonymous(CtClass<?> target, CtBlock<Void> body) { CtAnonymousExecutable a = factory.Core().createAnonymousExecutable(); target.addAnonymousExecutable(a); a.setBody(body); return a; } /** * Creates a new parameter. */ public <T> CtParameter<T> createParameter(CtExecutable<?> parent, CtTypeReference<T> type, String name) { CtParameter<T> parameter = factory.Core().createParameter(); parameter.setType(type); parameter.setSimpleName(name); if (parent != null) { parent.addParameter(parameter); } return parameter; } /** * Creates a parameter reference from an existing parameter. * * @param <T> * the parameter's type * @param parameter * the parameter */ public <T> CtParameterReference<T> createParameterReference(CtParameter<T> parameter) { CtParameterReference<T> ref = factory.Core().createParameterReference(); if (parameter.getParent() != null) { ref.setDeclaringExecutable(factory.Executable().createReference((CtExecutable<?>) parameter.getParent())); } ref.setSimpleName(parameter.getSimpleName()); ref.setType(parameter.getType()); return ref; } /** * Creates an executable reference from an existing executable. */ public <T> CtExecutableReference<T> createReference(CtExecutable<T> e) { CtExecutableReference<T> er = createReferenceInternal(e); er.setParent(e); return er; } private <T> CtExecutableReference<T> createReferenceInternal(CtExecutable<T> e) { CtTypeReference<?> refs[] = new CtTypeReference[e.getParameters().size()]; int i = 0; for (CtParameter<?> param : e.getParameters()) { refs[i++] = param.getType() != null ? param.getType().clone() // With a lambda and in noclasspath (when the type of // parameters isn't specified), we assume Object. : factory.Type().OBJECT.clone(); } String executableName = e.getSimpleName(); if (e instanceof CtMethod) { boolean isStatic = ((CtMethod) e).hasModifier(ModifierKind.STATIC); return createReference(((CtMethod<T>) e).getDeclaringType().getReference(), isStatic, ((CtMethod<T>) e).getType().clone(), executableName, refs); } else if (e instanceof CtLambda) { CtMethod<T> lambdaMethod = ((CtLambda) e).getOverriddenMethod(); return createReference(e.getParent(CtType.class).getReference(), lambdaMethod == null ? null : lambdaMethod.getType(), executableName, refs); } else if (e instanceof CtAnonymousExecutable) { return createReference(((CtAnonymousExecutable) e).getDeclaringType().getReference(), e.getType().clone(), executableName); } // constructor return createReference(((CtConstructor<T>) e).getDeclaringType().getReference(), ((CtConstructor<T>) e).getType().clone(), CtExecutableReference.CONSTRUCTOR_NAME, refs); } /** * Creates an executable reference. * * @param declaringType * reference to the declaring type * @param type * the executable's type * @param methodName * simple name * @param parameterTypes * list of parameter's types */ public <T> CtExecutableReference<T> createReference(CtTypeReference<?> declaringType, CtTypeReference<T> type, String methodName, CtTypeReference<?>... parameterTypes) { return createReference(declaringType, false, type, methodName, parameterTypes); } /** * Creates an executable reference. * * @param declaringType * reference to the declaring type * @param isStatic * if this reference references a static executable * @param type * the return type of the executable * @param methodName * simple name * @param parameterTypes * list of parameter's types */ public <T> CtExecutableReference<T> createReference(CtTypeReference<?> declaringType, boolean isStatic, CtTypeReference<T> type, String methodName, CtTypeReference<?>... parameterTypes) { return createReference(declaringType, isStatic, type, methodName, Arrays.asList(parameterTypes)); } /** * Creates an executable reference. * * @param declaringType * reference to the declaring type * @param isStatic * if this reference references a static executable * @param type * the return type of the executable * @param methodName * simple name * @param parameterTypes * list of parameter's types */ public <T> CtExecutableReference<T> createReference(CtTypeReference<?> declaringType, boolean isStatic, CtTypeReference<T> type, String methodName, List<CtTypeReference<?>> parameterTypes) { CtExecutableReference<T> methodRef = factory.Core().createExecutableReference(); methodRef.setStatic(isStatic); methodRef.setDeclaringType(declaringType); methodRef.setSimpleName(methodName); methodRef.setType(type); List<CtTypeReference<?>> l = new ArrayList<>(parameterTypes); methodRef.setParameters(l); return methodRef; } /** * Creates an executable reference. * * @param declaringType * reference to the declaring type * @param type * the return type of the executable * @param methodName * simple name * @param parameterTypes * list of parameter's types */ public <T> CtExecutableReference<T> createReference(CtTypeReference<?> declaringType, CtTypeReference<T> type, String methodName, List<CtTypeReference<?>> parameterTypes) { CtExecutableReference<T> methodRef = factory.Core().createExecutableReference(); methodRef.setDeclaringType(declaringType); methodRef.setSimpleName(methodName); methodRef.setType(type); List<CtTypeReference<?>> l = new ArrayList<>(parameterTypes); methodRef.setParameters(l); return methodRef; } /** * Creates an executable reference from its signature, as defined by the * executable reference's toString. */ public <T> CtExecutableReference<T> createReference(String signature) { CtExecutableReference<T> executableRef = factory.Core().createExecutableReference(); String type = signature.substring(0, signature.indexOf(" ")); String declaringType = signature.substring(signature.indexOf(" ") + 1, signature.indexOf(CtExecutable.EXECUTABLE_SEPARATOR)); String executableName = signature.substring(signature.indexOf(CtExecutable.EXECUTABLE_SEPARATOR) + 1, signature.indexOf("(")); executableRef.setSimpleName(executableName); executableRef.setDeclaringType(factory.Type().createReference(declaringType)); CtTypeReference<T> typeRef = factory.Type().createReference(type); executableRef.setType(typeRef); String parameters = signature.substring(signature.indexOf("(") + 1, signature.indexOf(")")); List<CtTypeReference<?>> params = new ArrayList<>(PARAMETERS_CONTAINER_DEFAULT_CAPACITY); StringTokenizer t = new StringTokenizer(parameters, ","); while (t.hasMoreTokens()) { String paramType = t.nextToken(); params.add(factory.Type().createReference(paramType)); } executableRef.setParameters(params); return executableRef; } }