Clover coverage report - DynamicJava Test Coverage (dynamicjava-20120303-r5436)
Coverage timestamp: Sat Mar 3 2012 03:02:19 CST
file stats: LOC: 251   Methods: 22
NCLOC: 169   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SymbolUtil.java 68.1% 65.9% 72.7% 67.3%
coverage coverage
 1    package edu.rice.cs.dynamicjava.symbol;
 2   
 3    import java.lang.reflect.Array;
 4    import edu.rice.cs.plt.lambda.Lambda;
 5    import edu.rice.cs.plt.lambda.Thunk;
 6    import edu.rice.cs.plt.iter.IterUtil;
 7    import edu.rice.cs.plt.reflect.JavaVersion;
 8    import edu.rice.cs.plt.reflect.ReflectUtil;
 9    import edu.rice.cs.plt.reflect.ReflectException;
 10   
 11    import edu.rice.cs.dynamicjava.symbol.type.*;
 12   
 13    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 14   
 15    public class SymbolUtil {
 16   
 17    /**
 18    * Produces a list of classes enclosing the given class, from the most outer to the most inner.
 19    * The length of the list is at least 1 (the last element of the list is always {@code c}).
 20    * Note that classes that <em>indirectly</em> enclose this class, such as a class containing
 21    * a method that declares this class, are not included in the result.
 22    */
 23  9025 public static Iterable<DJClass> outerClassChain(DJClass c) {
 24  9025 Iterable<DJClass> result = IterUtil.singleton(c);
 25  9025 DJClass outer = c.declaringClass();
 26  0 while (outer != null) { result = IterUtil.compose(outer, result); outer = outer.declaringClass(); }
 27  9025 return result;
 28    }
 29   
 30    /** Produce the first element of the class's {@code outerClassChain()}. */
 31  0 public static DJClass outermostClass(DJClass c) {
 32  0 DJClass result = c;
 33  0 DJClass outer = c.declaringClass();
 34  0 while (outer != null) { result = outer; outer = outer.declaringClass(); }
 35  0 return result;
 36    }
 37   
 38    /**
 39    * Determine whether {@code inner} is non-statically nested within {@code outer}. This is the
 40    * case iff {@code outer} appears in {@code inner}'s outer class chain, and the next class
 41    * in the chain is not declared static, or {@code outer} equals {@code inner}.
 42    */
 43  22 public static boolean dynamicallyEncloses(DJClass outer, DJClass inner) {
 44  22 DJClass c = inner;
 45  22 boolean nextIsStatic = false;
 46  22 while (c != null) {
 47  22 if (c.equals(outer)) { return !nextIsStatic; }
 48  0 nextIsStatic = c.isStatic();
 49  0 c = c.declaringClass();
 50    }
 51  0 return false;
 52    }
 53   
 54    /**
 55    * Determine the most deeply-nested dynamically-enclosing class of {@code c}.
 56    * The result is {@code null} if {code c} is a top-level class or is declared in a strictly
 57    * static context. On the other hand, for generality, if class A has non-static inner class B, which
 58    * in turn declares static class C, the result for C is A, not {@code null} or {@code B}
 59    * (such declarations are not allowed in Java, and have limited syntactic support).
 60    */
 61  1972 public static DJClass dynamicOuterClass(DJClass c) {
 62  1972 DJClass inner = c;
 63  0 while (inner != null && inner.isStatic()) { inner = inner.declaringClass(); }
 64  1972 return (inner == null) ? null : inner.declaringClass();
 65    }
 66   
 67    /**
 68    * Determine the type of an enclosing object of a value of the given type. The result is a
 69    * parameterization of {@code dynamicOuterClass(t.ofClass())}, where the parameters are drawn
 70    * from {@code t}, or {@code null} if there is no such class.
 71    */
 72  700 public static ClassType dynamicOuterClassType(ClassType t) {
 73  700 final DJClass outer = dynamicOuterClass(t.ofClass());
 74  700 if (outer == null) { return null; }
 75    else {
 76  0 return t.apply(new TypeAbstractVisitor<ClassType>() {
 77  0 public ClassType defaultCase(Type t) { throw new RuntimeException(); }
 78  0 @Override public ClassType forSimpleClassType(SimpleClassType t) {
 79  0 return new SimpleClassType(outer);
 80    }
 81  0 @Override public ClassType forRawClassType(RawClassType t) {
 82  0 Iterable<VariableType> outerParams = allTypeParameters(outer);
 83  0 if (IterUtil.isEmpty(outerParams)) { return new SimpleClassType(outer); }
 84  0 else { return new RawClassType(outer); }
 85    }
 86  0 @Override public ClassType forParameterizedClassType(ParameterizedClassType t) {
 87  0 Iterable<VariableType> outerParams = allTypeParameters(outer);
 88  0 if (IterUtil.isEmpty(outerParams)) { return new SimpleClassType(outer); }
 89    else {
 90  0 Iterable<Type> targs = IterUtil.truncate(t.typeArguments(), IterUtil.sizeOf(outerParams));
 91  0 return new ParameterizedClassType(outer, targs);
 92    }
 93    }
 94    });
 95    }
 96    }
 97   
 98    /**
 99    * Determine all the in-scope type parameters of {@code c}, ordered outermost to innermost.
 100    * A type parameter is in scope if it belongs to a dynamically enclosing class of {@code c}.
 101    */
 102  8506 public static Iterable<VariableType> allTypeParameters(DJClass c) {
 103  8506 Iterable<VariableType> result = IterUtil.empty();
 104  8506 Iterable<VariableType> enclosing = IterUtil.empty();
 105  8506 for (DJClass cl : outerClassChain(c)) {
 106  8506 if (!cl.isStatic()) { result = IterUtil.compose(result, enclosing); }
 107    // if cl is static, we ignore the params of the immediately enclosing class
 108  8506 enclosing = cl.declaredTypeParameters();
 109    }
 110  8506 result = IterUtil.compose(result, enclosing); // always include c's vars
 111  8506 return result;
 112    }
 113   
 114    /**
 115    * Produce a short name for the given class -- including all outer class names, but excluding
 116    * the package name. Anonymous classes are written "(anonymous Foo)", where Foo is the shortName
 117    * of the extended type.
 118    */
 119  142 public static String shortName(DJClass c) {
 120  142 StringBuilder result = new StringBuilder();
 121  142 boolean first = true;
 122  142 for (DJClass outer : outerClassChain(c)) {
 123  0 if (!first) { result.append('.'); }
 124  142 first = false;
 125  142 if (outer.isAnonymous()) {
 126  0 result.append("(anonymous ");
 127  0 Iterable<Type> supers = outer.declaredSupertypes();
 128  0 try {
 129  0 ClassType superClassT = (ClassType) IterUtil.first(supers);
 130  0 result.append(shortName(superClassT.ofClass()));
 131    }
 132  0 catch (RuntimeException e) { result.append("Object"); }
 133  0 result.append(')');
 134    }
 135  142 else { result.append(outer.declaredName()); }
 136    }
 137  142 return result.toString();
 138    }
 139   
 140   
 141    /** Create the type corresponding to {@code this} within the body of {@code c} */
 142  1483 public static ClassType thisType(DJClass c) {
 143  1483 Iterable<VariableType> vars = allTypeParameters(c);
 144  1056 if (IterUtil.isEmpty(vars)) { return new SimpleClassType(c); }
 145  427 else { return new ParameterizedClassType(c, vars); }
 146    }
 147   
 148    /**
 149    * Create an appropriate DJClass for the given Class, based on the available reflection APIs.
 150    * If Java 5 is available, returns a {@link Java5Class}. Otherwise, returns a {@link JavaClass}.
 151    */
 152  112 public static DJClass wrapClass(Class<?> c) {
 153  112 if (JavaVersion.CURRENT.supports(JavaVersion.JAVA_5)) {
 154  112 try {
 155  112 return (DJClass) ReflectUtil.loadObject(DJClass.class.getClassLoader(),
 156    "edu.rice.cs.dynamicjava.symbol.Java5Class", c);
 157    }
 158  0 catch (ReflectException e) { throw new RuntimeException("Unable to create a Java5Class"); }
 159    }
 160  0 else { return new JavaClass(c); }
 161    }
 162   
 163    /**
 164    * Create an appropriate Library for the given ClassLoader, based on the available reflection APIs.
 165    * If Java 5 is available, returns a {@link Java5Library}. Otherwise, returns a {@link JavaLibrary}.
 166    */
 167  183 public static Library classLibrary(ClassLoader loader) {
 168  183 if (JavaVersion.CURRENT.supports(JavaVersion.JAVA_5)) {
 169  183 try {
 170  183 return (Library) ReflectUtil.loadObject(Library.class.getClassLoader(), Java5Library.class.getName(),
 171    new Class<?>[]{ ClassLoader.class }, loader);
 172    }
 173    catch (ReflectException e) {
 174  0 debug.log(e);
 175  0 throw new RuntimeException("Unable to create a Java5Library");
 176    }
 177    }
 178  0 else { return new JavaLibrary(loader); }
 179    }
 180   
 181    /**
 182    * Convert a {@code Class} object representing a primitive type to the corresponding
 183    * {@link Type}. The class {@code void.class} is also handled.
 184    * @throws IllegalArgumentException If {@code !c.isPrimitive()}.
 185    */
 186  970 public static Type typeOfPrimitiveClass(Class<?> c) {
 187  181 if (c.equals(boolean.class)) { return TypeSystem.BOOLEAN; }
 188  549 else if (c.equals(int.class)) { return TypeSystem.INT; }
 189  84 else if (c.equals(double.class)) { return TypeSystem.DOUBLE; }
 190  13 else if (c.equals(char.class)) { return TypeSystem.CHAR; }
 191  76 else if (c.equals(void.class)) { return TypeSystem.VOID; }
 192  10 else if (c.equals(long.class)) { return TypeSystem.LONG; }
 193  5 else if (c.equals(byte.class)) { return TypeSystem.BYTE; }
 194  5 else if (c.equals(short.class)) { return TypeSystem.SHORT; }
 195  47 else if (c.equals(float.class)) { return TypeSystem.FLOAT; }
 196  0 else { throw new IllegalArgumentException("Unrecognized primitive: " + c); }
 197    }
 198   
 199    /**
 200    * Create a type corresponding to an arbitrary reflection class, which may represent
 201    * a primitive, an array, or a class/interface. Class types are created by invoking
 202    * {@link #wrapClass} and passing the result to {@link TypeSystem#makeClassType}.
 203    */
 204  0 public static Type typeOfGeneralClass(Class<?> c, TypeSystem ts) {
 205  0 if (c.isPrimitive()) { return typeOfPrimitiveClass(c); }
 206  0 else if (c.isArray()) { return new SimpleArrayType(typeOfGeneralClass(c.getComponentType(), ts)); }
 207  0 else { return ts.makeClassType(wrapClass(c)); }
 208    }
 209   
 210   
 211  77 public static Thunk<Class<?>> arrayClassThunk(final Thunk<Class<?>> element) {
 212  77 return new Thunk<Class<?>>() {
 213  67 public Class<?> value() { return Array.newInstance(element.value(), 0).getClass(); }
 214    };
 215    }
 216   
 217    /**
 218    * Get the initial (zero) value of a field with the given class. May be an array or primitive;
 219    * if void, the result is {@code null}.
 220    */
 221  469 public static Object initialValue(Class<?> c) {
 222  469 if (c.isPrimitive()) {
 223  49 if (c.equals(boolean.class)) { return Boolean.FALSE; }
 224  72 else if (c.equals(int.class)) { return Integer.valueOf(0); }
 225  7 else if (c.equals(double.class)) { return Double.valueOf(0.0); }
 226  5 else if (c.equals(char.class)) { return Character.valueOf('\u0000'); }
 227  143 else if (c.equals(void.class)) { return null; }
 228  3 else if (c.equals(long.class)) { return Long.valueOf(0l); }
 229  3 else if (c.equals(byte.class)) { return Byte.valueOf((byte) 0); }
 230  3 else if (c.equals(short.class)) { return Short.valueOf((short) 0); }
 231  15 else if (c.equals(float.class)) { return Float.valueOf(0.0f); }
 232  0 else { throw new IllegalArgumentException("Unrecognized primitive: " + c); }
 233    }
 234  169 else { return null; }
 235    }
 236   
 237  2348 public static Iterable<Type> parameterTypes(Function f) {
 238  2348 return IterUtil.map(f.parameters(), TYPE_OF_VARIABLE);
 239    }
 240   
 241    private static final Lambda<Variable, Type> TYPE_OF_VARIABLE = new Lambda<Variable, Type>() {
 242  2094 public Type value(Variable v) { return v.type(); }
 243    };
 244   
 245    /** Test whether the function's last parameter has a VarargArrayType type. */
 246  10 public static boolean isVararg(Function f) {
 247  10 Iterable<LocalVariable> params = f.parameters();
 248  10 return !IterUtil.isEmpty(params) && (IterUtil.last(params).type() instanceof VarargArrayType);
 249    }
 250   
 251    }