/**
* 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.declaration.CtClass;
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.CtTypeReference;
import spoon.template.Substitution;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* The {@link CtMethod} sub-factory.
*/
public class MethodFactory extends ExecutableFactory {
/**
* Creates a new method sub-factory.
*
* @param factory
* the parent factory
*/
public MethodFactory(Factory factory) {
super(factory);
}
/**
* Creates a method.
*
* @param target
* the class where the method is inserted
* @param modifiers
* the modifiers
* @param returnType
* the method's return type
* @param name
* the method's name
* @param parameters
* the parameters
* @param thrownTypes
* the thrown types
* @param body
* the method's body
*/
public <R, B extends R> CtMethod<R> create(CtClass<?> target, Set<ModifierKind> modifiers, CtTypeReference<R> returnType, String name, List<CtParameter<?>> parameters,
Set<CtTypeReference<? extends Throwable>> thrownTypes, CtBlock<B> body) {
CtMethod<R> method = create(target, modifiers, returnType, name, parameters, thrownTypes);
method.setBody(body);
return method;
}
/**
* Creates a method by copying an existing method.
*
* @param <T>
* the type of the method
* @param target
* the target type where the new method has to be inserted to
* @param source
* the source method to be copied
* @param redirectReferences
* tells if all the references to the owning type of the source
* method should be redirected to the target type (true is
* recommended for most uses)
* @return the newly created method
*/
public <T> CtMethod<T> create(CtType<?> target, CtMethod<T> source, boolean redirectReferences) {
CtMethod<T> newMethod = source.clone();
if (redirectReferences && (source.getDeclaringType() != null)) {
Substitution.redirectTypeReferences(newMethod, source.getDeclaringType().getReference(), target.getReference());
}
target.addMethod(newMethod);
return newMethod;
}
/**
* Creates an empty method.
*
* @param target
* the class where the method is inserted
* @param modifiers
* the modifiers
* @param returnType
* the method's return type
* @param name
* the method's name
* @param parameters
* the parameters
* @param thrownTypes
* the thrown types
*/
public <T> CtMethod<T> create(CtType<?> target, Set<ModifierKind> modifiers, CtTypeReference<T> returnType, String name, List<CtParameter<?>> parameters,
Set<CtTypeReference<? extends Throwable>> thrownTypes) {
CtMethod<T> method = factory.Core().createMethod();
if (modifiers != null) {
method.setModifiers(modifiers);
}
method.setType(returnType);
method.setSimpleName(name);
if (parameters != null) {
method.setParameters(parameters);
}
if (thrownTypes != null) {
method.setThrownTypes(thrownTypes);
}
target.addMethod(method);
return method;
}
/**
* Creates a method reference.
*/
public <T> CtExecutableReference<T> createReference(CtMethod<T> m) {
return factory.Executable().createReference(m);
}
/**
* Creates a method reference from an actual method.
*/
@SuppressWarnings("unchecked")
public <T> CtExecutableReference<T> createReference(Method method) {
return createReference(factory.Type().createReference(method.getDeclaringClass()), (CtTypeReference<T>) factory.Type().createReference(method.getReturnType()), method.getName(),
factory.Type().createReferences(Arrays.asList(method.getParameterTypes())).toArray(new CtTypeReference<?>[0]));
}
/**
* Gets all the main methods stored in this factory.
*/
public Collection<CtMethod<Void>> getMainMethods() {
Collection<CtMethod<Void>> methods = new ArrayList<>();
for (CtType<?> t : factory.Type().getAll()) {
if (t instanceof CtClass) {
CtMethod<Void> m = ((CtClass<?>) t).getMethod(factory.Type().createReference(void.class), "main", factory.Type().createArrayReference(factory.Type().createReference(String.class)));
if ((m != null) && m.getModifiers().contains(ModifierKind.STATIC)) {
methods.add(m);
}
}
}
return methods;
}
}