package org.xpect.scoping;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmFeature;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.xpect.AbstractComponent;
import org.xpect.Assignment;
import org.xpect.Component;
import org.xpect.XjmContribution;
import org.xpect.XpectJavaModel;
import org.xpect.XpectTest;
import org.xpect.setup.XpectSetupComponent;
import org.xpect.setup.XpectSetupRoot;
import org.xpect.util.JvmTypesUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
public class ComponentUtil {
private final XpectJavaModel xjm;
public ComponentUtil(XpectJavaModel xjm) {
super();
this.xjm = xjm;
}
private Set<JvmDeclaredType> getCompatibleContributions(Set<JvmDeclaredType> types) {
Set<JvmDeclaredType> result = Sets.newHashSet();
Set<JvmDeclaredType> inactive = Sets.newHashSet();
Iterable<XjmContribution> contributions = xjm.getContributions(XpectSetupComponent.class);
CONT: for (XjmContribution contribution : contributions) {
JvmDeclaredType jvmClass = contribution.getJvmClass();
if (contribution.isActive()) {
Set<JvmType> superTypes = JvmTypesUtil.getSelfAndAllSuperTypes(jvmClass);
for (JvmType superType : superTypes)
if (superType instanceof JvmDeclaredType && types.contains(superType)) {
result.add(jvmClass);
continue CONT;
}
} else {
inactive.add(jvmClass);
}
}
for (JvmDeclaredType type : types)
if (!type.isAbstract() && type instanceof JvmGenericType && !((JvmGenericType) type).isInterface() && !inactive.contains(type))
result.add(type);
return result;
}
private void collectAdders(JvmType type, List<JvmOperation> ops) {
if (type instanceof JvmDeclaredType && !type.eIsProxy())
for (JvmFeature feat : ((JvmDeclaredType) type).getAllFeatures())
if (feat instanceof JvmOperation && "add".equals(feat.getSimpleName()))
ops.add((JvmOperation) feat);
}
private Set<JvmDeclaredType> getFirstParameterTypes(List<JvmOperation> ops) {
Set<JvmDeclaredType> result = Sets.newHashSet();
for (JvmOperation op : ops)
if (op.getParameters().size() == 1) {
JvmTypeReference paramType = op.getParameters().get(0).getParameterType();
if (paramType != null && !paramType.eIsProxy()) {
JvmType type = paramType.getType();
if (type instanceof JvmDeclaredType && !type.eIsProxy())
result.add((JvmDeclaredType) type);
}
}
return result;
}
public Set<JvmDeclaredType> getValidRootTypes() {
Iterable<XjmContribution> contributions = xjm.getContributions(XpectSetupRoot.class);
List<JvmOperation> ops = Lists.newArrayList();
for (XjmContribution contribution : contributions)
if (contribution.isActive()) {
JvmDeclaredType jvmClass = contribution.getJvmClass();
collectAdders(jvmClass, ops);
}
Set<JvmDeclaredType> firstParameterTypes = getFirstParameterTypes(ops);
Set<JvmDeclaredType> compatibleContributions = getCompatibleContributions(firstParameterTypes);
return compatibleContributions;
}
public Set<JvmDeclaredType> getValidTypes(Assignment assignment) {
List<JvmOperation> ops = Lists.newArrayList();
JvmOperation operation = assignment.getDeclaredTarget();
if (operation != null) {
if (operation.eIsProxy())
return Collections.emptySet();
ops.add(operation);
} else {
AbstractComponent container = assignment.getInstance();
if (container instanceof Component) {
JvmDeclaredType type = ((Component) container).getComponentClass();
if (type != null && !type.eIsProxy())
collectAdders(type, ops);
return getCompatibleContributions(getFirstParameterTypes(ops));
} else if (container instanceof XpectTest) {
return getValidRootTypes();
} else
return Collections.emptySet();
}
return getCompatibleContributions(getFirstParameterTypes(ops));
}
}