Clover coverage report - DynamicJava Test Coverage (dynamicjava-20130518-r5436)
Coverage timestamp: Sat May 18 2013 03:01:28 CDT
file stats: LOC: 522   Methods: 82
NCLOC: 411   Classes: 6
 
 Source file Conditionals Statements Methods TOTAL
TreeClass.java 38% 62.4% 76.8% 59.4%
coverage coverage
 1    package edu.rice.cs.dynamicjava.symbol;
 2   
 3    import java.util.Collections;
 4    import java.util.List;
 5    import java.util.LinkedList;
 6    import edu.rice.cs.plt.lambda.Thunk;
 7    import edu.rice.cs.plt.lambda.LazyThunk;
 8    import edu.rice.cs.plt.lambda.Box;
 9    import edu.rice.cs.plt.tuple.Option;
 10    import edu.rice.cs.plt.tuple.Pair;
 11    import edu.rice.cs.plt.iter.IterUtil;
 12   
 13    import koala.dynamicjava.tree.*;
 14    import koala.dynamicjava.tree.tiger.*;
 15    import koala.dynamicjava.tree.visitor.*;
 16    import koala.dynamicjava.interpreter.NodeProperties;
 17    import koala.dynamicjava.interpreter.error.ExecutionError;
 18   
 19    import edu.rice.cs.dynamicjava.symbol.type.Type;
 20    import edu.rice.cs.dynamicjava.symbol.type.ClassType;
 21    import edu.rice.cs.dynamicjava.symbol.type.VariableType;
 22    import edu.rice.cs.dynamicjava.symbol.type.SimpleClassType;
 23    import edu.rice.cs.dynamicjava.Options;
 24    import edu.rice.cs.dynamicjava.interpreter.TreeClassLoader;
 25    import edu.rice.cs.dynamicjava.interpreter.RuntimeBindings;
 26    import edu.rice.cs.dynamicjava.interpreter.EvaluatorException;
 27    import edu.rice.cs.dynamicjava.interpreter.CheckerException;
 28    import edu.rice.cs.plt.lambda.WrappedException;
 29   
 30    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 31   
 32    /**
 33    * <p>A DJClass wrapper for a parsed class or interface declaration.</p>
 34    * <p>A DJClass object must be available before any types can be created in terms of the class.
 35    * Thus all class declarations introduced in some scope must have corresponding DJClasses before
 36    * processing the supertypes and type parameters, etc., of those declarations. Here we handle
 37    * much of this process by recursively creating all members of the given class at the time of
 38    * creation, and tagging the declarations with these new objects. The members of the resulting DJClass
 39    * are immediately available; type parameters and supertypes are initialized with stub Object types
 40    * until the actual types can be resolved (note that, until actual types are resolved, the results
 41    * of a member lookup on a TreeClass will be incorrect; but, as complex dependencies sometimes exist
 42    * between name and supertype resolution, this stub information is sometimes useful).
 43    */
 44    public class TreeClass implements DJClass {
 45   
 46    private static final Type RUNTIME_BINDINGS_TYPE =
 47    new SimpleClassType(SymbolUtil.wrapClass(RuntimeBindings.class));
 48   
 49    private final String _fullName;
 50    private final DJClass _declaring; // may be null
 51    private final Access.Module _accessModule;
 52    private final Node _ast;
 53    private final ModifierSet _mods;
 54    private final Thunk<Class<?>> _loaded;
 55    private final List<TreeConstructor> _constructors;
 56    private final List<TreeField> _fields;
 57    private final List<TreeMethod> _methods;
 58    private final List<TreeClass> _classes;
 59    private final Options _opt;
 60   
 61    /**
 62    * All the class's declared members are indexed, and the FIELD, METHOD, and DJ_CLASS properties are set
 63    * (applied recursively).
 64    * @param fullName The fully-qualified name of the class, as in {@link Class#getName}.
 65    * @param declaring The declaring class of this class, or null if it appears at a top level or local
 66    * scope.
 67    * @param accessModule The access module for this class, or null if it is its own access module
 68    * @param ast The parsed declaration of this class. Must be a TypeDeclaration, AnonymousAllocation,
 69    * or AnonymousInnerAllocation.
 70    * @param loader A class loader for compiling and loading this class. Note that the loader must
 71    * be defined to allow transitive loading of all referenced classes.
 72    */
 73  89 public TreeClass(String fullName, DJClass declaring, Access.Module accessModule, final Node ast,
 74    final TreeClassLoader loader, Options opt) {
 75  89 _fullName = fullName;
 76  89 _declaring = declaring;
 77  89 _accessModule = (accessModule == null) ? this : accessModule;
 78  89 _ast = ast;
 79  89 if (_ast instanceof TypeDeclaration) { _mods = ((TypeDeclaration) _ast).getModifiers(); }
 80  0 else { _mods = ModifierSet.make(); }
 81  89 _loaded = LazyThunk.make(new Thunk<Class<?>>() {
 82  35 public Class<?> value() {
 83  35 try { return loader.loadClass(_fullName); }
 84  0 catch (ClassNotFoundException e) { throw new RuntimeException("Error loading class", e); }
 85    // LinkageError indicates there's something wrong with the compiled class
 86    catch (LinkageError e) {
 87    // bugfix for bug 2674112: Error loading class in Interpreter
 88    // maybe this isn't the best place
 89  0 if (e instanceof IllegalAccessError) {
 90    // catch this particular error and provide a better error message
 91  0 String msg = e.getMessage();
 92  0 final String PREFIX = "class ";
 93  0 final String[] INFIX = new String[] { " cannot access its superclass ",
 94    " cannot access its superinterface " };
 95  0 final String[] ERROR_MSGS = new String[] { "class.cannot.access.superclass",
 96    "class.cannot.access.superinterface" };
 97  0 if (msg.startsWith(PREFIX)) {
 98  0 for (int i=0; i<INFIX.length; ++i) {
 99  0 final String infix = INFIX[i];
 100  0 int infixPos = msg.indexOf(infix);
 101  0 if ((infixPos>=0) && (infixPos>=PREFIX.length())) {
 102  0 String className0 = msg.substring(PREFIX.length(), infixPos).trim();
 103  0 String className1 = msg.substring(infixPos+infix.length()).trim();
 104  0 koala.dynamicjava.interpreter.NodeProperties.setErrorStrings(ast, className0, className1);
 105  0 ExecutionError ee = new ExecutionError(ERROR_MSGS[i], ast);
 106  0 throw new WrappedException(new CheckerException(ee));
 107    }
 108    }
 109    }
 110    }
 111  0 throw new RuntimeException("Error loading class", e);
 112    }
 113    }
 114    });
 115  89 _constructors = new LinkedList<TreeConstructor>();
 116  89 _fields = new LinkedList<TreeField>();
 117  89 _methods = new LinkedList<TreeMethod>();
 118  89 _classes = new LinkedList<TreeClass>();
 119  89 _opt = opt;
 120  89 loader.registerTree(this);
 121  89 tagSignature();
 122  89 extractMembers(loader);
 123    }
 124   
 125    /** Set the TYPE and TYPE_VARIABLE properties of of non-anonymous classes' signatures to stub Object types. */
 126  89 private void tagSignature() {
 127  89 if (_ast instanceof TypeDeclaration) {
 128  89 TypeDeclaration td = (TypeDeclaration) _ast;
 129   
 130  89 List<TypeParameter> tparams = td.getTypeParams().unwrap(Collections.<TypeParameter>emptyList());
 131  89 for (TypeParameter p : tparams) {
 132  69 BoundedSymbol tempBounds = new BoundedSymbol(new Object(), p.getRepresentation(),
 133    TypeSystem.OBJECT, TypeSystem.NULL);
 134  69 NodeProperties.setTypeVariable(p, new VariableType(tempBounds));
 135    }
 136   
 137  89 if (td instanceof ClassDeclaration) {
 138  89 NodeProperties.setType(((ClassDeclaration) td).getSuperclass(), TypeSystem.OBJECT);
 139    }
 140  89 if (td.getInterfaces() != null) {
 141  1 for (ReferenceTypeName tn : td.getInterfaces()) { NodeProperties.setType(tn, TypeSystem.OBJECT); }
 142    }
 143    }
 144    }
 145   
 146  89 private void extractMembers(final TreeClassLoader loader) {
 147  89 Iterable<Node> members = IterUtil.empty();
 148  89 if (_ast instanceof TypeDeclaration) { members = ((TypeDeclaration) _ast).getMembers(); }
 149  0 else if (_ast instanceof AnonymousAllocation) {
 150  0 members = ((AnonymousAllocation) _ast).getMembers();
 151    }
 152  0 else if (_ast instanceof AnonymousInnerAllocation) {
 153  0 members = ((AnonymousInnerAllocation) _ast).getMembers();
 154    }
 155  89 for (Node n : members) {
 156  250 n.acceptVisitor(new AbstractVisitor<Void>() {
 157  0 @Override public Void defaultCase(Node n) { return null; /* ignore other declarations */ }
 158  0 @Override public Void visit(ClassDeclaration d) {
 159  0 TreeClass c = new TreeClass(_fullName + "$" + d.getName(), TreeClass.this, _accessModule, d, loader, _opt);
 160  0 NodeProperties.setDJClass(d, c);
 161  0 _classes.add(c);
 162  0 return null;
 163    }
 164  0 @Override public Void visit(InterfaceDeclaration d) {
 165  0 TreeClass c = new TreeClass(_fullName + "$" + d.getName(), TreeClass.this, _accessModule, d, loader, _opt);
 166  0 NodeProperties.setDJClass(d, c);
 167  0 _classes.add(c);
 168  0 return null;
 169    }
 170  69 @Override public Void visit(ConstructorDeclaration d) {
 171  69 TreeConstructor k = new ExplicitTreeConstructor(d);
 172  69 NodeProperties.setConstructor(d, k);
 173  69 _constructors.add(k);
 174  69 return null;
 175    }
 176  158 @Override public Void visit(MethodDeclaration d) {
 177  158 TreeMethod m = new TreeMethod(d);
 178  158 NodeProperties.setMethod(d, m);
 179  158 _methods.add(m);
 180  158 return null;
 181    }
 182  23 @Override public Void visit(FieldDeclaration d) {
 183  23 TreeField f = new TreeField(d);
 184  23 NodeProperties.setField(d, f);
 185  23 _fields.add(f);
 186  23 return null;
 187    }
 188    });
 189    }
 190  89 if (_constructors.isEmpty() && !(_ast instanceof InterfaceDeclaration)) {
 191  20 _constructors.add(new DefaultTreeConstructor());
 192    }
 193    }
 194   
 195  35 public Node declaration() { return _ast; }
 196   
 197  0 public String packageName() {
 198    // can't delegate to _accessModule, because it may be this
 199  0 int dot = _fullName.lastIndexOf('.');
 200  0 if (dot == -1) { return ""; }
 201  0 else { return _fullName.substring(0, dot); }
 202    }
 203   
 204    /** Produces the binary name for the given class (as in {@link Class#getName}) */
 205  227 public String fullName() { return _fullName; }
 206   
 207  2404 public boolean isAnonymous() { return !(_ast instanceof TypeDeclaration); }
 208   
 209  1605 public String declaredName() {
 210  1605 if (_ast instanceof TypeDeclaration) {
 211  1605 return ((TypeDeclaration) _ast).getName();
 212    }
 213  0 else { throw new IllegalArgumentException("Anonymous class has no declared name"); }
 214    }
 215   
 216  614 public boolean isInterface() { return _ast instanceof InterfaceDeclaration; }
 217   
 218  1573 public boolean isStatic() {
 219  1573 if (_declaring == null) { return false; }
 220  0 else { return _declaring.isInterface() || isInterface() || _ast instanceof EnumDeclaration || _mods.isStatic(); }
 221    }
 222  54 public boolean isAbstract() { return _mods.isAbstract(); }
 223  0 public boolean isFinal() { return _mods.isFinal(); }
 224  0 public Access accessibility() {
 225  0 return (_declaring != null && _declaring.isInterface()) ? Access.PUBLIC : extractAccessibility(_mods);
 226    }
 227  1042 public Access.Module accessModule() { return _accessModule; }
 228  7 public boolean hasRuntimeBindingsParams() { return true; }
 229   
 230    /** The class that declares this class, or {@code null} if this is declared at a top-level or local scope */
 231  3221 public DJClass declaringClass() { return _declaring; }
 232   
 233    /** List all type variables declared by this class */
 234  2484 public Iterable<VariableType> declaredTypeParameters() {
 235  2484 List<TypeParameter> paramAsts = Collections.emptyList();
 236  2484 if (_ast instanceof TypeDeclaration) {
 237  2484 paramAsts = ((TypeDeclaration) _ast).getTypeParams().unwrap(paramAsts);
 238    }
 239  2484 return IterUtil.mapSnapshot(paramAsts, NodeProperties.NODE_TYPE_VARIABLE);
 240    }
 241   
 242    /** List the declared supertypes of this class */
 243  1237 public Iterable<Type> declaredSupertypes() {
 244  1237 if (_ast instanceof ClassDeclaration) {
 245  1237 ClassDeclaration cd = (ClassDeclaration) _ast;
 246  1237 Iterable<Type> superIs;
 247  1207 if (cd.getInterfaces() == null) { superIs = IterUtil.empty(); }
 248  30 else { superIs = IterUtil.mapSnapshot(cd.getInterfaces(), NodeProperties.NODE_TYPE); }
 249  1237 return IterUtil.compose(NodeProperties.getType(cd.getSuperclass()), superIs);
 250    }
 251  0 else if (_ast instanceof InterfaceDeclaration) {
 252  0 InterfaceDeclaration id = (InterfaceDeclaration) _ast;
 253  0 if (id.getInterfaces() == null) { return IterUtil.empty(); }
 254  0 else { return IterUtil.mapSnapshot(id.getInterfaces(), NodeProperties.NODE_TYPE); }
 255    }
 256  0 else if (_ast instanceof AnonymousAllocation) {
 257  0 return IterUtil.singleton(NodeProperties.getType(((AnonymousAllocation) _ast).getCreationType()));
 258    }
 259  0 else if (_ast instanceof AnonymousInnerAllocation) {
 260  0 return IterUtil.singleton(NodeProperties.getSuperType(_ast));
 261    }
 262  0 else { throw new IllegalArgumentException("Unsupported class AST type"); }
 263    }
 264   
 265  328 public Iterable<DJField> declaredFields() { return IterUtil.<DJField>immutable(_fields); }
 266   
 267  100 public Iterable<DJConstructor> declaredConstructors() { return IterUtil.<DJConstructor>immutable(_constructors); }
 268   
 269  42 public Iterable<DJMethod> declaredMethods() { return IterUtil.<DJMethod>immutable(_methods); }
 270   
 271  639 public Iterable<DJClass> declaredClasses() { return IterUtil.<DJClass>immutable(_classes); }
 272   
 273    /**
 274    * @return The type bound to {@code super} in the context of this class, or
 275    * {@code null} if {@code super} is not defined
 276    */
 277  69 public Type immediateSuperclass() {
 278  69 if (_ast instanceof ClassDeclaration) {
 279    // ClassDeclaration provides the default java.lang.Object where there's no extends clause
 280  69 return NodeProperties.getType(((ClassDeclaration)_ast).getSuperclass());
 281    }
 282  0 else if (_ast instanceof InterfaceDeclaration) {
 283  0 return TypeSystem.OBJECT;
 284    }
 285  0 else if (_ast instanceof AnonymousAllocation) {
 286  0 Type result = NodeProperties.getType(((AnonymousAllocation) _ast).getCreationType());
 287  0 if (result instanceof ClassType && !((ClassType) result).ofClass().isInterface()) {
 288  0 return result;
 289    }
 290  0 else { return TypeSystem.OBJECT; }
 291    }
 292  0 else if (_ast instanceof AnonymousInnerAllocation) {
 293  0 return NodeProperties.getSuperType(_ast);
 294    }
 295  0 else { throw new IllegalArgumentException("Unsupported class AST type"); }
 296    }
 297   
 298    /**
 299    * Produce the runtime representation of the class (as in {@link ClassLoader#loadClass},
 300    * repeated invocations should produce the same object).
 301    */
 302  92 public Class<?> load() { return _loaded.value(); }
 303   
 304  0 public String toString() { return "TreeClass(" + _fullName + ")"; }
 305   
 306  72 public boolean equals(Object o) {
 307  60 if (this == o) { return true; }
 308  0 else if (!o.getClass().equals(getClass())) { return false; }
 309  12 else { return _ast == ((TreeClass) o)._ast; }
 310    }
 311   
 312  401 public int hashCode() { return getClass().hashCode() ^ System.identityHashCode(_ast); }
 313   
 314   
 315    private class TreeField implements DJField {
 316    private final FieldDeclaration _f;
 317    private final Thunk<DJField> _loaded;
 318  23 public TreeField(FieldDeclaration f) {
 319  23 _f = f;
 320  23 _loaded = LazyThunk.make(new Thunk<DJField>() {
 321  12 public DJField value() {
 322  12 DJClass c = SymbolUtil.wrapClass(TreeClass.this.load());
 323  12 for (DJField candidate : c.declaredFields()) {
 324  36 if (TreeField.this.declaredName().equals(candidate.declaredName())) {
 325  12 return candidate;
 326    }
 327    }
 328    // error: can't find it
 329  0 debug.logValues(new String[]{"name", "candidates"},
 330    TreeField.this.declaredName(), c.declaredFields());
 331  0 throw new RuntimeException("Can't find field in loaded class");
 332    }
 333    });
 334    }
 335  358 public String declaredName() { return _f.getName(); }
 336  0 public DJClass declaringClass() { return TreeClass.this; }
 337  138 public Type type() { return NodeProperties.getType(_f.getType()); }
 338  115 public boolean isFinal() { return _f.getModifiers().isFinal() || isInterface(); }
 339  69 public boolean isStatic() { return _f.getModifiers().isStatic() || isInterface(); }
 340  322 public Access accessibility() {
 341  322 return isInterface() ? Access.PUBLIC : extractAccessibility(_f.getModifiers());
 342    }
 343  0 public Access.Module accessModule() { return _accessModule; }
 344  69 public Option<Object> constantValue() {
 345  69 if (isFinal() && isStatic()) {
 346  0 Expression init = _f.getInitializer();
 347  0 if (init != null) {
 348  0 if (NodeProperties.hasValue(init)) { return Option.some(NodeProperties.getValue(init)); }
 349    // Since hasValue depends on the order of type checking, and the current order is
 350    // naive, also allow values for literals that haven't yet been checked
 351    // (this still produces incorrect results for non-literal, not-yet-checked constant expressions)
 352  0 else if (init instanceof Literal) { return Option.some(((Literal) init).getValue()); }
 353    }
 354    }
 355  69 return Option.none();
 356    }
 357  33 public Box<Object> boxForReceiver(Object receiver) {
 358  33 return _loaded.value().boxForReceiver(receiver);
 359    }
 360  0 public String toString() { return "TreeField(" + declaredName() + ")"; }
 361    }
 362   
 363   
 364    private abstract class TreeConstructor implements DJConstructor {
 365    private final Thunk<DJConstructor> _loaded;
 366    private final DJClass _outerClass;
 367   
 368  89 public TreeConstructor() {
 369  89 _loaded = LazyThunk.make(new Thunk<DJConstructor>() {
 370  32 public DJConstructor value() {
 371  32 Iterable<LocalVariable> params = TreeConstructor.this.parameters();
 372  32 if (_outerClass == null) {
 373  32 params = IterUtil.compose(new LocalVariable("", RUNTIME_BINDINGS_TYPE, false), params);
 374    }
 375  32 DJClass c = SymbolUtil.wrapClass(TreeClass.this.load());
 376  32 for (DJConstructor candidate : c.declaredConstructors()) {
 377  32 if (paramsMatch(params, candidate.parameters())) {
 378  32 return candidate;
 379    }
 380    }
 381    // error: can't find it
 382  0 debug.logValues(new String[]{"params", "candidates"}, params, c.declaredConstructors());
 383  0 throw new RuntimeException("Can't find constructor in loaded class");
 384    }
 385    });
 386  89 _outerClass = SymbolUtil.dynamicOuterClass(TreeClass.this);
 387    }
 388   
 389  1 public String declaredName() { return isAnonymous() ? "<anonymous>" : TreeClass.this.declaredName(); }
 390  0 public DJClass declaringClass() { return TreeClass.this; }
 391  0 public Access.Module accessModule() { return _accessModule; }
 392  100 public Type returnType() { return SymbolUtil.thisType(TreeClass.this); }
 393   
 394  7 public DJConstructor declaredSignature() { return this; }
 395  39 public Object evaluate(Object outer, Iterable<Object> args, RuntimeBindings bindings, Options options)
 396    throws EvaluatorException {
 397  39 if (_outerClass == null) { args = IterUtil.compose(bindings, args); }
 398  39 return _loaded.value().evaluate(outer, args, bindings, options);
 399    }
 400  0 public String toString() { return "TreeConstructor(" + declaredName() + ")"; }
 401    }
 402   
 403   
 404    private class DefaultTreeConstructor extends TreeConstructor {
 405  22 public Access accessibility() { return Access.PUBLIC; }
 406  44 public Iterable<VariableType> typeParameters() { return IterUtil.empty(); }
 407  38 public Iterable<LocalVariable> parameters() { return IterUtil.empty(); }
 408  22 public Iterable<Type> thrownTypes() { return IterUtil.empty(); }
 409    }
 410   
 411   
 412    private class ExplicitTreeConstructor extends TreeConstructor {
 413    private final ConstructorDeclaration _k;
 414  69 public ExplicitTreeConstructor(ConstructorDeclaration k) {
 415  69 _k = k;
 416    }
 417  124 public Access accessibility() { return extractAccessibility(_k.getModifiers()); }
 418  239 public Iterable<VariableType> typeParameters() {
 419  239 List<TypeParameter> paramAsts = _k.getTypeParams().unwrap(Collections.<TypeParameter>emptyList());
 420  239 return IterUtil.mapSnapshot(paramAsts, NodeProperties.NODE_TYPE_VARIABLE);
 421    }
 422  418 public Iterable<LocalVariable> parameters() {
 423  418 return IterUtil.mapSnapshot(_k.getParameters(), NodeProperties.NODE_VARIABLE);
 424    }
 425  146 public Iterable<Type> thrownTypes() {
 426  146 return IterUtil.mapSnapshot(_k.getExceptions(), NodeProperties.NODE_TYPE);
 427    }
 428    }
 429   
 430   
 431    private class TreeMethod implements DJMethod {
 432    private MethodDeclaration _m;
 433    private Thunk<DJMethod> _loaded;
 434   
 435  158 public TreeMethod(MethodDeclaration m) {
 436  158 _m = m;
 437  158 _loaded = LazyThunk.make(new Thunk<DJMethod>() {
 438  27 public DJMethod value() {
 439  27 Iterable<LocalVariable> params = TreeMethod.this.parameters();
 440  27 if (TreeMethod.this.isStatic()) {
 441  0 params = IterUtil.compose(new LocalVariable("", RUNTIME_BINDINGS_TYPE, false), params);
 442    }
 443  27 DJClass c = SymbolUtil.wrapClass(TreeClass.this.load());
 444  27 for (DJMethod candidate : c.declaredMethods()) {
 445  70 if (TreeMethod.this.declaredName().equals(candidate.declaredName()) &&
 446    paramsMatch(params, candidate.parameters())) {
 447  27 return candidate;
 448    }
 449    }
 450    // error: can't find it
 451  0 debug.logValues(new String[]{"name", "params", "candidates"},
 452    TreeMethod.this.declaredName(), params, c.declaredMethods());
 453  0 throw new RuntimeException("Can't find method in loaded class");
 454    }
 455    });
 456    }
 457   
 458  224 public String declaredName() { return _m.getName(); }
 459  0 public DJClass declaringClass() { return TreeClass.this; }
 460  138 public boolean isStatic() { return _m.getModifiers().isStatic(); }
 461  0 public boolean isAbstract() { return _m.getModifiers().isAbstract() || isInterface(); }
 462  0 public boolean isFinal() { return _m.getModifiers().isFinal(); }
 463  54 public Access accessibility() {
 464  54 return isInterface() ? Access.PUBLIC : extractAccessibility(_m.getModifiers());
 465    }
 466  0 public Access.Module accessModule() { return _accessModule; }
 467   
 468  236 public Type returnType() { return NodeProperties.getType(_m.getReturnType()); }
 469   
 470  377 public Iterable<VariableType> typeParameters() {
 471  377 List<TypeParameter> paramAsts = _m.getTypeParams().unwrap(Collections.<TypeParameter>emptyList());
 472  377 return IterUtil.mapSnapshot(paramAsts, NodeProperties.NODE_TYPE_VARIABLE);
 473    }
 474   
 475  804 public Iterable<LocalVariable> parameters() {
 476  804 return IterUtil.mapSnapshot(_m.getParameters(), NodeProperties.NODE_VARIABLE);
 477    }
 478   
 479  43 public Iterable<Type> thrownTypes() {
 480  43 return IterUtil.mapSnapshot(_m.getExceptions(), NodeProperties.NODE_TYPE);
 481    }
 482   
 483  0 public DJMethod declaredSignature() { return this; }
 484   
 485  29 public Object evaluate(Object receiver, Iterable<Object> args, RuntimeBindings bindings, Options options)
 486    throws EvaluatorException {
 487  0 if (isStatic()) { args = IterUtil.compose(bindings, args); }
 488  29 return _loaded.value().evaluate(receiver, args, bindings, options);
 489    }
 490   
 491  0 public String toString() { return "TreeMethod(" + declaredName() + ")"; }
 492    }
 493   
 494   
 495    /** Convert a reflection modifier int to an appropriate Access object */
 496  500 private static Access extractAccessibility(ModifierSet mods) {
 497  178 if (mods.isPublic()) { return Access.PUBLIC; }
 498  0 else if (mods.isProtected()) { return Access.PROTECTED; }
 499  322 else if (mods.isPrivate()) { return Access.PRIVATE; }
 500  0 else { return Access.PACKAGE; }
 501    }
 502   
 503    /**
 504    * Assumes the classes corresponding to the types of the local variables can be loaded.
 505    * Non-static because it depends on _opt.
 506    */
 507  59 private boolean paramsMatch(Iterable<LocalVariable> p1, Iterable<LocalVariable> p2) {
 508  59 if (IterUtil.sizeOf(p1) == IterUtil.sizeOf(p2)) {
 509  59 TypeSystem ts = _opt.typeSystem();
 510  59 for (Pair<LocalVariable, LocalVariable> vars : IterUtil.zip(p1, p2)) {
 511  70 Thunk<Class<?>> c1 = ts.erasedClass(vars.first().type());
 512  70 Thunk<Class<?>> c2 = ts.erasedClass(vars.second().type());
 513  70 if (!c1.value().equals(c2.value())) {
 514  0 return false;
 515    }
 516    }
 517  59 return true;
 518    }
 519  0 else { return false; }
 520    }
 521   
 522    }