package fr.inria.diversify.constantgenertor;
import fr.inria.diversify.util.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
/**
* User: Simon
* Date: 31/03/15
* Time: 11:01
*/
public class FindValue {
protected int MAX_OBJECT_CREATION_BY_CLASS = 100;
protected int MAX_OBJECT_CREATION_BY_VALUES = 10;
protected int MAX_OBJECT_CREATION_SIZE = 10;
protected Map<Object, Set<ObjectCreation>> valuesToObjectCreation;
protected Map<Class, Set<ObjectCreation>> typeToObjectCreation;
protected Map<Constructor, Set<Class>> typeNeedC;
protected Map<Method, Set<Class>> typeNeedM;
protected Queue<Object> executableToProcess;
protected Set<Integer> alreadySee;
private Set<Method> methodFilter;
public FindValue() throws NoSuchMethodException {
initMethodFilter();
typeNeedC = new HashMap<>();
typeNeedM = new HashMap<>();
executableToProcess = new ArrayDeque<>();
typeToObjectCreation = new HashMap<>();
valuesToObjectCreation = new HashMap<>();
alreadySee = new HashSet<>();
}
public void init(Set<Class<?>> classes) {
for(Class cl : classes) {
for (Constructor constructor : cl.getConstructors()) {
if(!Modifier.isAbstract(constructor.getDeclaringClass().getModifiers())) {
Set<Class> types = new HashSet<>();
Collections.addAll(types, constructor.getParameterTypes());
typeNeedC.put(constructor, types);
executableToProcess.add(constructor);
}
}
}
}
public void foo() {
while(!executableToProcess.isEmpty()) {
Object exe = executableToProcess.poll();
if(exe instanceof Constructor) {
findNewNew((Constructor) exe);
} else {
findNewValue((ObjectCreation) exe);
}
}
}
protected void info() {
Log.info("queue size: {}, nb type of object: {}", executableToProcess.size(), typeToObjectCreation.size());
}
public void infoEnd() {
Log.info("infoEnd");
Log.info("queue size: {}, nb type of object: {}", executableToProcess.size(), typeToObjectCreation.size());
for(Object key : valuesToObjectCreation.keySet()) {
if(valuesToObjectCreation.get(key) != null) {
if (key != null) {
Log.info("type: {}, value: {}:, nb: {}", key.getClass().getSimpleName(), key, valuesToObjectCreation.get(key).size());
} else {
Log.info("value: {}:, nb: {}", key, valuesToObjectCreation.get(key).size());
}
}
}
valuesToObjectCreation.keySet().stream()
.forEach(key -> Log.info("type: {}, value: {}:, nb: {}",key, key.getClass(), valuesToObjectCreation.get(key).size()));
}
protected void findNewValue(ObjectCreation objectCreation) {
for (Method method : objectCreation.getMethods()) {
if (Modifier.isPublic(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers()) && !methodFilter.contains(method)) {
MethodCall methodCall = buildMethod(objectCreation.getDynamicType(), method);
if (methodCall != null && addNewValue(methodCall)) {
try {
Log.debug("{} : {}", methodCall, methodCall.buildObject());
} catch (Throwable e) {}
updateExecutableToProcess(methodCall);
info();
}
}
}
}
protected boolean addNewValue(ObjectCreation objectCreation) {
try {
Class dynamicType = objectCreation.getDynamicType();
if (objectCreation.size() < MAX_OBJECT_CREATION_SIZE
&& !alreadySee.contains(objectCreation.hashCode())
&& objectCreation.buildWithoutException()) {
alreadySee.add(objectCreation.hashCode());
if (!typeToObjectCreation.containsKey(dynamicType)) {
typeToObjectCreation.put(dynamicType, new HashSet<>());
}
Set<ObjectCreation> types = typeToObjectCreation.get(dynamicType);
if (!valuesToObjectCreation.containsKey(objectCreation.getValue())) {
valuesToObjectCreation.put(objectCreation.getValue(), new HashSet<>());
}
Set<ObjectCreation> values = valuesToObjectCreation.get(objectCreation.getValue());
if (MAX_OBJECT_CREATION_BY_VALUES < values.size()) {
return false;
} else {
values.add(objectCreation);
if (MAX_OBJECT_CREATION_BY_CLASS < types.size()) {
types.remove(randomPick(types));
}
return types.add(objectCreation);
}
} else {
alreadySee.add(objectCreation.hashCode());
return false;
}
} catch (Exception e) {
alreadySee.add(objectCreation.hashCode());
return false;
}
}
protected MethodCall buildMethod(Class targetType, Method method) {
ObjectCreation[] args = new ObjectCreation[method.getParameterCount()];
if(typeToObjectCreation.containsKey(targetType) ) {
ObjectCreation target = randomPick(typeToObjectCreation.get(targetType));
MethodCall methodCall = new MethodCall(target, method, args);
int i = 0;
for (; i < method.getParameterCount(); i++) {
Class type = method.getParameterTypes()[i];
Set<ObjectCreation> set = typeToObjectCreation.get(type);
if (set != null && !set.isEmpty()) {
args[i] = randomPick(set);
} else {
break;
}
}
if (i == args.length) {
return methodCall;
}
}
return null;
}
protected void findNewNew(Constructor constructor) {
ObjectCreation newCall = buildConstructor(constructor);
if(newCall != null && addNewValue(newCall)) {
try {
Log.debug("{} : {}", newCall, newCall.buildObject());
} catch (Throwable e) {}
updateExecutableToProcess(newCall);
info();
}
}
protected NewCall buildConstructor(Constructor constructor) {
ObjectCreation[] args = new ObjectCreation[constructor.getParameterCount()];
int i = 0;
NewCall newCall = new NewCall(constructor, args);
for(; i < constructor.getParameterCount(); i++) {
Class type = constructor.getParameterTypes()[i];
Set<ObjectCreation> set = typeToObjectCreation.get(type);
if(set != null && !set.isEmpty()) {
args[i] = randomPick(set);
} else {
break;
}
}
if(i == args.length) {
return newCall;
}
return null;
}
protected void updateExecutableToProcess(ObjectCreation objectCreation) {
Class dynamicType = objectCreation.getDynamicType();
for(Constructor constructor : typeNeedC.keySet()) {
if(typeNeedC.get(constructor).contains(dynamicType)) {
executableToProcess.add(constructor);
}
}
for (Method method : dynamicType.getMethods()) {
if(Modifier.isPublic(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers()) && !methodFilter.contains(method)) {
Set<Class> types = new HashSet<>();
types.add(dynamicType);
Collections.addAll(types, method.getParameterTypes());
typeNeedM.put(method, types);
}
}
if(!(dynamicType.equals(void.class) || dynamicType.equals(Void.class))
&& Modifier.isPublic(dynamicType.getModifiers())) {
executableToProcess.add(objectCreation);
}
}
protected void initMethodFilter() throws NoSuchMethodException {
methodFilter = new HashSet<>();
methodFilter.add(Object.class.getMethod("hashCode"));
// Collections.addAll(methodFilter, Object.class.getMethods());
}
protected ObjectCreation randomPick(Set<ObjectCreation> objectCreations) {
return objectCreations.stream().findFirst().orElse(null);
}
}