/**
*
*/
package it.xsemantics.example.fj.lookup;
import it.xsemantics.example.fj.fj.Class;
import it.xsemantics.example.fj.fj.Field;
import it.xsemantics.example.fj.fj.Member;
import it.xsemantics.example.fj.fj.Method;
import it.xsemantics.example.fj.util.ClassSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.xtext.EcoreUtil2;
/**
* @author Lorenzo Bettini
*
* Auxiliary functions for looking up into classes (e.g., all the fields
* of a class hierarchy)
*/
public class FjAuxiliaryFunctions {
/**
* Collects all the fields of a class (including the inherited ones, which
* will appear first in the list).
*
* @param cl
* @return the fields of a class (including the inherited ones)
*/
public List<Field> getFields(Class cl) {
if (cl == null)
return Collections.emptyList();
List<Field> fields = new LinkedList<Field>(selectFields(cl));
List<Class> superClasses = getSuperclasses(cl);
for (Class class1 : superClasses) {
fields.addAll(0, selectFields(class1));
}
return fields;
}
public List<Field> selectFields(Class cl) {
return EcoreUtil2.typeSelect(
cl.getMembers(), Field.class);
}
/**
* Collects all the methods of a class (including the inherited ones). In
* case of method overriding, makes sure to get the most redefined version.
*
* @param cl
* @return the methods of a class (including the inherited ones)
*/
public List<Method> getMethods(Class cl) {
if (cl == null)
return Collections.emptyList();
HashMap<String, Method> methodMap = new HashMap<String, Method>();
List<Method> methods = selectMethods(cl);
for (Method method : methods) {
methodMap.put(method.getName(), method);
}
List<Class> superClasses = getSuperclasses(cl);
for (Class class1 : superClasses) {
List<Method> currentClassMethods = selectMethods(class1);
for (Method method : currentClassMethods) {
// add it only if not already present
if (!methodMap.containsKey(method.getName()))
methodMap.put(method.getName(), method);
}
}
return new LinkedList<Method>(methodMap.values());
}
public List<Method> selectMethods(Class cl) {
return EcoreUtil2.typeSelect(
cl.getMembers(), Method.class);
}
/**
* Computes the superclasses of a given class (also avoids duplicates, in
* case of cyclic hierarchy). The implicit class Object is added
* automatically. The superclasses respect the hierarchy order, starting
* from the direct superclasses up to Object.
*
* When iterating over a class hierarchy, you should never iterate directly
* over the superclass of a given class since a (malformed) class hierarchy
* may contain a cycle and you'd end up looping. Thus, never do:
*
* <pre>
* Class current = cl;
* while (current != null) {
* ...
* current = current.getExtends();
* }
* </pre>
*
* Instead the classes returned by this method should be used to iterate
* over a class hierarchy.
*
* @param cl
* @return the superclasses of a given class (without duplicates)
*/
public List<Class> getSuperclasses(Class cl) {
List<Class> orderedSuperClasses = new LinkedList<Class>();
// only used to avoid loops.
ClassSet superClasses = new ClassSet();
Class current = cl.getSuperclass();
while (current != null) {
// avoid endless loops in case of cycles
if (superClasses.contains(current))
break;
superClasses.add(current);
orderedSuperClasses.add(current);
current = current.getSuperclass();
}
return orderedSuperClasses;
}
public List<Member> getMembers(Class cl) {
List<Member> allMembers = new LinkedList<Member>();
allMembers.addAll(getFields(cl));
allMembers.addAll(getMethods(cl));
return allMembers;
}
}