Clover coverage report - DynamicJava Test Coverage (dynamicjava-20130622-r5436)
Coverage timestamp: Sat Jun 22 2013 03:01:29 CDT
file stats: LOC: 333   Methods: 50
NCLOC: 260   Classes: 4
 
 Source file Conditionals Statements Methods TOTAL
Java5Class.java 64.3% 77.7% 78% 74.7%
coverage coverage
 1    package edu.rice.cs.dynamicjava.symbol;
 2   
 3    import java.lang.reflect.*;
 4    import java.util.List;
 5    import java.util.ArrayList;
 6    import edu.rice.cs.plt.lambda.Lambda;
 7    import edu.rice.cs.plt.lambda.Thunk;
 8    import edu.rice.cs.plt.lambda.LazyThunk;
 9    import edu.rice.cs.plt.lambda.Predicate;
 10    import edu.rice.cs.plt.iter.IterUtil;
 11    import edu.rice.cs.plt.recur.PrecomputedRecursionStack;
 12    import edu.rice.cs.plt.reflect.ReflectUtil;
 13    import edu.rice.cs.plt.tuple.Wrapper;
 14   
 15    import edu.rice.cs.dynamicjava.symbol.type.*;
 16    import edu.rice.cs.dynamicjava.symbol.type.Type; // resolves ambiguity with java.lang.reflect.Type
 17   
 18    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 19   
 20    /** DJClass implementation that wraps a Java 5 reflection Class object. To prevent linkage
 21    * errors, this class should only be dynamically loaded if it's possible that the target platform
 22    * does not support the Java 5 APIs.
 23    */
 24    public class Java5Class extends JavaClass {
 25   
 26  33035 public Java5Class(Class<?> c) { super(c); }
 27   
 28  139 @Override public String declaredName() {
 29  139 if (_c.isAnonymousClass()) {
 30  0 throw new IllegalArgumentException("Anonymous class has no declared name");
 31    }
 32  139 else { return _c.getSimpleName(); }
 33    }
 34   
 35  0 @Override public Access.Module accessModule() {
 36  0 Class<?> result = _c;
 37  0 Class<?> outer = result.getEnclosingClass();
 38  0 while (outer != null) { result = outer; outer = result.getEnclosingClass(); }
 39  0 return new Java5Class(result);
 40    }
 41   
 42  9151 @Override public DJClass declaringClass() {
 43  9151 Class<?> outer = _c.getDeclaringClass();
 44  9151 return (outer == null) ? null : new Java5Class(outer);
 45    }
 46   
 47    /** List all type variables declared by this class (but not by its enclosing classes) */
 48  7034 @Override public Iterable<VariableType> declaredTypeParameters() {
 49  7034 return IterUtil.mapSnapshot(IterUtil.asIterable(_c.getTypeParameters()), CONVERT_VAR);
 50    }
 51   
 52    /** List the declared supertypes of this class */
 53  24247 @Override public Iterable<Type> declaredSupertypes() {
 54  24247 Type superC = immediateSuperclass();
 55  24247 Iterable<Type> superIs = IterUtil.mapSnapshot(IterUtil.asIterable(_c.getGenericInterfaces()), CONVERT_TYPE);
 56  24247 return superC == null ? superIs : IterUtil.compose(superC, superIs);
 57    }
 58   
 59  20 @Override public Iterable<DJField> declaredFields() {
 60    // CONVERT_FIELD is shadowed here to create a Java5Field
 61  20 return IterUtil.mapSnapshot(IterUtil.asIterable(_c.getDeclaredFields()), CONVERT_FIELD);
 62    }
 63   
 64  484 @Override public Iterable<DJConstructor> declaredConstructors() {
 65    // CONVERT_CONSTRUCTOR is shadowed here to create a Java5Constructor
 66  484 return IterUtil.mapSnapshot(IterUtil.asIterable(_c.getDeclaredConstructors()), CONVERT_CONSTRUCTOR);
 67    }
 68   
 69  745 @Override public Iterable<DJMethod> declaredMethods() {
 70    // CONVERT_METHOD is shadowed here to create a Java5Method
 71  745 Iterable<Method> ms = IterUtil.filter(IterUtil.asIterable(_c.getDeclaredMethods()), IS_NOT_BRIDGE);
 72  745 return IterUtil.mapSnapshot(ms, CONVERT_METHOD);
 73    }
 74   
 75    private static final Predicate<Method> IS_NOT_BRIDGE = new Predicate<Method>() {
 76  9125 public boolean contains(Method m) { return !m.isBridge(); }
 77    };
 78   
 79  580 @Override public Iterable<DJClass> declaredClasses() {
 80    // CONVERT_CLASS is shadowed here to create a Java5Class
 81  580 return IterUtil.mapSnapshot(IterUtil.asIterable(_c.getDeclaredClasses()), CONVERT_CLASS);
 82    }
 83   
 84   
 85    /**
 86    * Return the type bound to {@code super} in the context of this class, or
 87    * {@code null} if {@code super} is not defined
 88    */
 89  24247 @Override public Type immediateSuperclass() {
 90  24247 java.lang.reflect.Type superT = _c.getGenericSuperclass();
 91  24247 return (superT == null) ? null : CONVERT_TYPE.value(superT);
 92    }
 93   
 94  0 @Override public String toString() { return "Java5Class(" + _c.getName() + ")"; }
 95   
 96   
 97  49199 private static Type convertType(java.lang.reflect.Type refT,
 98    PrecomputedRecursionStack<java.lang.reflect.Type, Type> stack) {
 99  30596 if (refT instanceof Class<?>) { return classAsType((Class<?>) refT); }
 100  18603 else if (refT instanceof ParameterizedType) {
 101  9634 return convertParameterizedType((ParameterizedType) refT, stack);
 102    }
 103  8969 else if (refT instanceof java.lang.reflect.TypeVariable<?>) {
 104  8948 return convertTypeVariable((java.lang.reflect.TypeVariable<?>) refT, stack);
 105    }
 106  21 else if (refT instanceof java.lang.reflect.WildcardType) {
 107  7 return convertWildcard((java.lang.reflect.WildcardType) refT, stack);
 108    }
 109  14 else if (refT instanceof GenericArrayType) {
 110  14 Type elementType = convertType(((GenericArrayType) refT).getGenericComponentType(), stack);
 111  14 return new SimpleArrayType(elementType);
 112    }
 113  0 else { throw new IllegalArgumentException("Unrecognized java.lang.reflect.Type"); }
 114    }
 115   
 116  22115 private static Iterable<Type> convertTypes(java.lang.reflect.Type[] refTs,
 117    final PrecomputedRecursionStack<java.lang.reflect.Type, Type> stack) {
 118  22115 return IterUtil.mapSnapshot(IterUtil.asIterable(refTs), new Lambda<java.lang.reflect.Type, Type>() {
 119  22108 public Type value(java.lang.reflect.Type t) { return convertType(t, stack); }
 120    });
 121    }
 122   
 123    /** Convert a class object to a type */
 124  30614 private static Type classAsType(Class<?> c) {
 125  439 if (c.isPrimitive()) { return SymbolUtil.typeOfPrimitiveClass(c); }
 126  18 else if (c.isArray()) { return new SimpleArrayType(classAsType(c.getComponentType())); }
 127    else {
 128  30157 DJClass djc = new Java5Class(c);
 129    // This logic is performed here, rather than deferring to SymbolUtil.allTypeParameters(djc),
 130    // in order to avoid a potential infinite loop: to create a type for c, we would first have
 131    // to create the types of the parameters, which may in turn refer to c.
 132  30157 Class<?> outer = c;
 133  30157 boolean innerIsStatic = false;
 134  30157 while (outer != null) {
 135  9634 if (!innerIsStatic && outer.getTypeParameters().length > 0) { return new RawClassType(djc); }
 136  20523 innerIsStatic = Modifier.isStatic(outer.getModifiers());
 137  20523 outer = outer.getDeclaringClass();
 138    }
 139    // djc has no type parameters
 140  20523 return new SimpleClassType(djc);
 141    }
 142    }
 143   
 144  9634 private static Type convertParameterizedType(ParameterizedType paramT,
 145    final PrecomputedRecursionStack<java.lang.reflect.Type, Type> stack) {
 146    // assumes getRawType and getOwnerType return class types
 147  9634 ClassType rawT = (ClassType) convertType(paramT.getRawType(), stack);
 148  9634 ClassType ownerT = (paramT.getOwnerType() == null) ? null : (ClassType) convertType(paramT.getOwnerType(), stack);
 149  9634 ClassType enclosingT = rawT.ofClass().isStatic() ? SymbolUtil.dynamicOuterClassType(ownerT) : ownerT;
 150   
 151  9634 Iterable<? extends Type> outerArgs = IterUtil.empty();
 152  9634 boolean raw = false; // true iff an enclosing type is raw, and so this type must also be raw
 153  9634 if (enclosingT != null) {
 154  0 Iterable<? extends Type> ts = enclosingT.apply(new TypeAbstractVisitor<Iterable<? extends Type>>() {
 155  0 @Override public Iterable<? extends Type> forSimpleClassType(SimpleClassType enclosingT) {
 156  0 return IterUtil.empty();
 157    }
 158  0 @Override public Iterable<? extends Type> forRawClassType(RawClassType enclosingT) { return null; }
 159  0 @Override public Iterable<? extends Type> forParameterizedClassType(ParameterizedClassType enclosingT) {
 160  0 return enclosingT.typeArguments();
 161    }
 162    });
 163  0 if (ts == null) { raw = true; }
 164  0 else { outerArgs = ts; }
 165    }
 166   
 167  9634 Iterable<Type> directArgs = convertTypes(paramT.getActualTypeArguments(), stack);
 168  9634 final Iterable<Type> targs = IterUtil.compose(outerArgs, directArgs);
 169  9634 Type result = rawT.apply(new TypeAbstractVisitor<Type>() {
 170   
 171  0 public Type defaultCase(Type t) {
 172    // We should do this check even if "raw" is true (meaning that we'll return "rawT", not "result")
 173  0 throw new IllegalArgumentException("Raw type for ParameterizedType must be a raw class type");
 174    }
 175   
 176  9634 @Override public Type forRawClassType(RawClassType t) {
 177  9634 return new ParameterizedClassType(t.ofClass(), targs);
 178    }
 179   
 180  0 @Override public Type forSimpleClassType(SimpleClassType t) {
 181  0 if (!IterUtil.isEmpty(targs)) {
 182  0 throw new IllegalArgumentException("Type arguments on ParameterizedType are not necessary");
 183    }
 184  0 return t;
 185    }
 186   
 187    });
 188  9634 return raw ? rawT : result;
 189    }
 190   
 191  12469 private static VariableType convertTypeVariable(final java.lang.reflect.TypeVariable<?> refV,
 192    final PrecomputedRecursionStack<java.lang.reflect.Type, Type> stack) {
 193  12469 final BoundedSymbol bounds = new BoundedSymbol(refV, refV.getName());
 194  12469 final VariableType var = new VariableType(bounds);
 195  12469 Thunk<VariableType> setBounds = new Thunk<VariableType>() {
 196  12467 public VariableType value() {
 197  12467 Type upper;
 198  12467 Iterable<Type> uppers = convertTypes(refV.getBounds(), stack);
 199  0 if (IterUtil.isEmpty(uppers)) { upper = TypeSystem.OBJECT; }
 200  12467 else if (IterUtil.sizeOf(uppers) == 1) { upper = IterUtil.first(uppers); }
 201  0 else { upper = new IntersectionType(uppers); }
 202  12467 bounds.initializeUpperBound(upper);
 203  12467 bounds.initializeLowerBound(TypeSystem.NULL);
 204  12467 return var;
 205    }
 206    };
 207  12469 return (VariableType) stack.apply(setBounds, var, refV);
 208    }
 209   
 210  7 private static Type convertWildcard(final java.lang.reflect.WildcardType refW,
 211    final PrecomputedRecursionStack<java.lang.reflect.Type, Type> stack) {
 212  7 final BoundedSymbol bounds = new BoundedSymbol(refW);
 213  7 final Wildcard wild = new Wildcard(bounds);
 214  7 Thunk<Type> setBounds = new Thunk<Type>() {
 215  7 public Type value() {
 216  7 Type upper;
 217  7 Iterable<Type> uppers = convertTypes(refW.getUpperBounds(), stack);
 218  0 if (IterUtil.isEmpty(uppers)) { upper = TypeSystem.OBJECT; }
 219  7 else if (IterUtil.sizeOf(uppers) == 1) { upper = IterUtil.first(uppers); }
 220  0 else { upper = new IntersectionType(uppers); }
 221  7 bounds.initializeUpperBound(upper);
 222  7 Type lower;
 223  7 Iterable<Type> lowers = convertTypes(refW.getLowerBounds(), stack);
 224  7 if (IterUtil.isEmpty(lowers)) { lower = TypeSystem.NULL; }
 225  0 else if (IterUtil.sizeOf(lowers) == 1) { lower = IterUtil.first(lowers); }
 226  0 else { throw new IllegalArgumentException("Wildcard with multiple lower bounds"); }
 227  7 bounds.initializeLowerBound(lower);
 228  7 return wild;
 229    }
 230    };
 231  7 return stack.apply(setBounds, wild, refW);
 232    }
 233   
 234    private static Lambda<java.lang.reflect.Type, Type> CONVERT_TYPE =
 235    new Lambda<java.lang.reflect.Type, Type>() {
 236  17443 public Type value(java.lang.reflect.Type t) {
 237    // must use .equals, not ==: see java java.lang.reflect.TypeVariable javadocs
 238  17443 PrecomputedRecursionStack<java.lang.reflect.Type, Type> stack =
 239    PrecomputedRecursionStack.make(Wrapper.<java.lang.reflect.Type>factory());
 240  17443 return convertType(t, stack);
 241    }
 242    };
 243   
 244   
 245    private static final Lambda<TypeVariable<?>, VariableType> CONVERT_VAR =
 246    new Lambda<TypeVariable<?>, VariableType>() {
 247  3521 public VariableType value(TypeVariable<?> var) {
 248    // must use .equals, not ==: see java java.lang.reflect.TypeVariable javadocs
 249  3521 PrecomputedRecursionStack<java.lang.reflect.Type, Type> stack =
 250    PrecomputedRecursionStack.make(Wrapper.<java.lang.reflect.Type>factory());
 251  3521 return convertTypeVariable(var, stack);
 252    }
 253    };
 254   
 255    @SuppressWarnings("unchecked") // java.lang.Class methods return (raw) type Class[] in Java 5 (fixed in Java 6)
 256    private static final Lambda<Class, DJClass> CONVERT_CLASS = new Lambda<Class, DJClass>() {
 257  0 public DJClass value(Class c) { return new Java5Class(c); }
 258    };
 259   
 260    /** Non-static because Java5Field is non-static. */
 261    private final Lambda<Field, DJField> CONVERT_FIELD = new Lambda<Field, DJField>() {
 262  58 public DJField value(Field f) { return new Java5Field(f); }
 263    };
 264   
 265    /** Non-static because Java5Constructor is non-static. */
 266    @SuppressWarnings("unchecked") // java.lang.Class methods return (raw) type Constructor[] in Java 5 (fixed in Java 6)
 267    private final Lambda<Constructor, DJConstructor> CONVERT_CONSTRUCTOR =
 268    new Lambda<Constructor, DJConstructor>() {
 269  1148 public DJConstructor value(Constructor k) { return new Java5Constructor(k); }
 270    };
 271   
 272    /** Non-static because Java5Method is non-static. */
 273    private final Lambda<Method, DJMethod> CONVERT_METHOD = new Lambda<Method, DJMethod>() {
 274  9076 public DJMethod value(Method m) { return new Java5Method(m); }
 275    };
 276   
 277    private class Java5Field extends JavaField {
 278  58 public Java5Field(Field f) { super(f); }
 279  2 @Override public Type type() { return CONVERT_TYPE.value(_f.getGenericType()); }
 280  0 @Override public String toString() { return "Java5Field(" + declaredName() + ")"; }
 281    }
 282   
 283    private class Java5Constructor extends JavaConstructor {
 284  1148 public Java5Constructor(Constructor<?> k) { super(k); }
 285  1434 @Override public Iterable<VariableType> typeParameters() {
 286  1434 return IterUtil.mapSnapshot(IterUtil.asIterable(_k.getTypeParameters()), CONVERT_VAR);
 287    }
 288  452 @Override public Iterable<Type> thrownTypes() {
 289  452 return IterUtil.mapSnapshot(IterUtil.asIterable(_k.getGenericExceptionTypes()), CONVERT_TYPE);
 290    }
 291  1148 protected Thunk<Iterable<LocalVariable>> makeParamThunk() {
 292  1148 return paramFactory(_k.getGenericParameterTypes(), _k.isVarArgs());
 293    }
 294  0 @Override public String toString() { return "Java5Constructor(" + declaredName() + ")"; }
 295    }
 296   
 297    private class Java5Method extends JavaMethod {
 298  9076 public Java5Method(Method m) { super(m); }
 299  429 @Override public Type returnType() { return CONVERT_TYPE.value(_m.getGenericReturnType()); }
 300  697 @Override public Iterable<VariableType> typeParameters() {
 301  697 return IterUtil.mapSnapshot(IterUtil.asIterable(_m.getTypeParameters()), CONVERT_VAR);
 302    }
 303  132 @Override public Iterable<Type> thrownTypes() {
 304  132 return IterUtil.mapSnapshot(IterUtil.asIterable(_m.getGenericExceptionTypes()), CONVERT_TYPE);
 305    }
 306  9076 protected Thunk<Iterable<LocalVariable>> makeParamThunk() {
 307  9076 return paramFactory(_m.getGenericParameterTypes(), _m.isVarArgs());
 308    }
 309  0 @Override public String toString() { return "Java5Method(" + declaredName() + ")"; }
 310    }
 311   
 312  10224 private static Thunk<Iterable<LocalVariable>> paramFactory(final java.lang.reflect.Type[] ts,
 313    final boolean isVarargs) {
 314  10224 return LazyThunk.make(new Thunk<Iterable<LocalVariable>>() {
 315  1469 public Iterable<LocalVariable> value() {
 316  1469 List<LocalVariable> result = new ArrayList<LocalVariable>(ts.length);
 317    // TODO: can we access better information about the parameters -- names, final declarations?
 318  1469 for (int i = 0; i < ts.length; i++) {
 319  1453 Type t = CONVERT_TYPE.value(ts[i]);
 320  1453 if (isVarargs && i == ts.length-1 && t instanceof SimpleArrayType) {
 321  26 t = new VarargArrayType(((SimpleArrayType) t).ofType());
 322    }
 323  1453 result.add(new LocalVariable("a" + (i+1), t, false));
 324    }
 325    // Must wrap result in something that implements Iterable for Retroweaver compatibility:
 326    // normally, it's not a problem; but erasure inserts casts to the thunk's parameter type,
 327    // is translated to the Retroweaver Iterable type.
 328  1469 return IterUtil.asSizedIterable(result);
 329    }
 330    });
 331    }
 332   
 333    }