Clover coverage report - DynamicJava Test Coverage (dynamicjava-20130615-r5436)
Coverage timestamp: Sat Jun 15 2013 03:01:32 CDT
file stats: LOC: 397   Methods: 46
NCLOC: 273   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ImportContext.java 43.3% 53% 45.7% 49.6%
coverage coverage
 1    package edu.rice.cs.dynamicjava.interpreter;
 2   
 3    import java.util.*;
 4   
 5    import edu.rice.cs.plt.collect.IndexedRelation;
 6    import edu.rice.cs.plt.collect.Relation;
 7    import edu.rice.cs.plt.iter.IterUtil;
 8    import edu.rice.cs.plt.iter.SequenceIterator;
 9    import edu.rice.cs.plt.lambda.Lambda;
 10    import edu.rice.cs.plt.lambda.LambdaUtil;
 11    import edu.rice.cs.plt.text.TextUtil;
 12   
 13    import edu.rice.cs.dynamicjava.Options;
 14    import edu.rice.cs.dynamicjava.symbol.*;
 15    import edu.rice.cs.dynamicjava.symbol.type.IntersectionType;
 16    import edu.rice.cs.dynamicjava.symbol.type.Type;
 17    import edu.rice.cs.dynamicjava.symbol.type.ClassType;
 18   
 19    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 20   
 21    /**
 22    * The context at the top level of a source file or local block. Manages package and
 23    * import statements.
 24    */
 25    public class ImportContext extends DelegatingContext {
 26   
 27    private final TypeContext _next; // need to save here for making copies
 28    private final Options _opt;
 29    private final String _currentPackage;
 30    private final Iterator<Integer> _anonymousCounter;
 31   
 32    // The following fields refer to specific implementation classes in order to use the clone() method.
 33   
 34    /** Packages whose top-level classes are all imported */
 35    private final HashSet<String> _onDemandPackages;
 36    /** Classes whose member classes are all imported */
 37    private final HashSet<DJClass> _onDemandClasses;
 38    /** Classes whose static members (fields, methods, and classes) are all imported */
 39    private final HashSet<DJClass> _staticOnDemandClasses;
 40   
 41    /** Top-level classes that are individually imported */
 42    private final HashMap<String, DJClass> _importedTopLevelClasses;
 43    /** Classes containing an individually-imported member class */
 44    private final HashMap<String, DJClass> _importedMemberClasses;
 45    /** Classes containing an individually-imported field */
 46    private final HashMap<String, DJClass> _importedFields;
 47    /** Classes containing an individually-imported method */
 48    private final Relation<String, DJClass> _importedMethods;
 49   
 50    /**
 51    * Make a top-level context that delegates to a LibraryContext based on the given class loader.
 52    * The context is initialized with an on-demand import of "java.lang".
 53    */
 54  183 public ImportContext(ClassLoader loader, Options opt) {
 55  183 this(new LibraryContext(SymbolUtil.classLibrary(loader)), opt);
 56    }
 57   
 58    /**
 59    * Make a top-level context that delegates to the given context.
 60    * The context is initialized with an on-demand import of "java.lang".
 61    */
 62  183 public ImportContext(TypeContext next, Options opt) {
 63  183 super(next);
 64  183 _next = next;
 65  183 _opt = opt;
 66  183 _currentPackage = "";
 67  183 _anonymousCounter = new SequenceIterator<Integer>(1, LambdaUtil.INCREMENT_INT);
 68  183 _onDemandPackages = new HashSet<String>();
 69  183 _onDemandClasses = new HashSet<DJClass>();
 70  183 _staticOnDemandClasses = new HashSet<DJClass>();
 71  183 _importedTopLevelClasses = new HashMap<String, DJClass>();
 72  183 _importedMemberClasses = new HashMap<String, DJClass>();
 73  183 _importedFields = new HashMap<String, DJClass>();
 74  183 _importedMethods = new IndexedRelation<String, DJClass>(false);
 75   
 76  183 _onDemandPackages.add("java.lang");
 77    }
 78   
 79  9 private ImportContext(ImportContext copy) {
 80  9 this(copy._next, copy._currentPackage, copy);
 81    }
 82   
 83  9 @SuppressWarnings("unchecked")
 84    private ImportContext(TypeContext next, String currentPackage, ImportContext bindings) {
 85  9 super(next);
 86  9 _next = next;
 87  9 _opt = bindings._opt;
 88  9 _currentPackage = currentPackage;
 89  9 _anonymousCounter = bindings._anonymousCounter;
 90  9 _onDemandPackages = (HashSet<String>) bindings._onDemandPackages.clone();
 91  9 _onDemandClasses = (HashSet<DJClass>) bindings._onDemandClasses.clone();
 92  9 _staticOnDemandClasses = (HashSet<DJClass>) bindings._staticOnDemandClasses.clone();
 93  9 _importedTopLevelClasses = (HashMap<String, DJClass>) bindings._importedTopLevelClasses.clone();
 94  9 _importedMemberClasses = (HashMap<String, DJClass>) bindings._importedMemberClasses.clone();
 95  9 _importedFields = (HashMap<String, DJClass>) bindings._importedFields.clone();
 96  9 _importedMethods = new IndexedRelation<String, DJClass>(false);
 97  9 _importedMethods.addAll(bindings._importedMethods);
 98    }
 99   
 100  0 protected TypeContext duplicate(TypeContext next) {
 101  0 return new ImportContext(next, _currentPackage, this);
 102    }
 103   
 104   
 105    /* PACKAGE AND IMPORT MANAGEMENT */
 106   
 107    /** Set the current package to the given package name */
 108  0 @Override public TypeContext setPackage(String name) { return new ImportContext(_next, name, this); }
 109   
 110    /** Import on demand all top-level classes in the given package */
 111  9 @Override public TypeContext importTopLevelClasses(String pkg) {
 112  9 ImportContext result = new ImportContext(this);
 113  9 result._onDemandPackages.add(pkg);
 114  9 return result;
 115    }
 116   
 117    /** Import on demand all member classes of the given class */
 118  0 @Override public TypeContext importMemberClasses(DJClass outer) {
 119  0 ImportContext result = new ImportContext(this);
 120  0 result._onDemandClasses.add(outer);
 121  0 return result;
 122    }
 123   
 124    /** Import on demand all static members of the given class */
 125  0 @Override public TypeContext importStaticMembers(DJClass c) {
 126  0 ImportContext result = new ImportContext(this);
 127  0 result._staticOnDemandClasses.add(c);
 128  0 return result;
 129    }
 130   
 131    /** Import the given top-level class */
 132  0 @Override public TypeContext importTopLevelClass(DJClass c) {
 133  0 ImportContext result = new ImportContext(this);
 134  0 String name = c.declaredName();
 135    // Under strict circumstances, a duplicate import for a name is illegal, but DynamicJava allows it
 136  0 result._importedMemberClasses.remove(name);
 137  0 result._importedTopLevelClasses.put(name, c);
 138  0 return result;
 139    }
 140   
 141    /** Import the member class(es) of {@code outer} with the given name */
 142  0 @Override public TypeContext importMemberClass(DJClass outer, String name) {
 143  0 ImportContext result = new ImportContext(this);
 144    // Under strict circumstances, a duplicate import for a name is illegal, but DynamicJava allows it
 145  0 result._importedTopLevelClasses.remove(name);
 146  0 result._importedMemberClasses.put(name, outer);
 147  0 return result;
 148    }
 149   
 150    /** Import the field(s) of {@code c} with the given name */
 151  0 @Override public TypeContext importField(DJClass c, String name) {
 152  0 ImportContext result = new ImportContext(this);
 153    // Under strict circumstances, a duplicate import for a name is illegal, but DynamicJava allows it
 154  0 result._importedFields.put(name, c);
 155  0 return result;
 156    }
 157   
 158    /** Import the method(s) of {@code c} with the given name */
 159  0 @Override public TypeContext importMethod(DJClass c, String name) {
 160  0 ImportContext result = new ImportContext(this);
 161  0 result._importedMethods.add(name, c); // overloads with any others already imported
 162  0 return result;
 163    }
 164   
 165   
 166    /* TYPES: TOP-LEVEL CLASSES, MEMBER CLASSES, AND TYPE VARIABLES */
 167   
 168  54 @Override public boolean typeExists(String name, TypeSystem ts) {
 169  54 return importsTopLevelClass(name, ts) || importsMemberClass(name, ts) || super.typeExists(name, ts);
 170    }
 171   
 172  0 @Override public boolean topLevelClassExists(String name, TypeSystem ts) {
 173  0 return importsTopLevelClass(name, ts) || (!importsMemberClass(name, ts) && super.topLevelClassExists(name, ts));
 174    }
 175   
 176  2028 @Override public DJClass getTopLevelClass(String name, TypeSystem ts) throws AmbiguousNameException {
 177  2028 DJClass result = importedTopLevelClass(name, ts);
 178  2028 return (result == null && !importsMemberClass(name, ts)) ? super.getTopLevelClass(name, ts) : result;
 179    }
 180   
 181  522 private boolean importsTopLevelClass(String name, TypeSystem ts) {
 182  522 try { return importedTopLevelClass(name, ts) != null; }
 183  0 catch (AmbiguousNameException e) { return true; }
 184    }
 185   
 186  2550 private DJClass importedTopLevelClass(String name, TypeSystem ts) throws AmbiguousNameException {
 187  2550 DJClass result = null;
 188  2550 if (!TextUtil.contains(name, '.')) { // qualified names cannot be imported
 189  1793 result = _importedTopLevelClasses.get(name);
 190  1793 if (result == null) {
 191  1793 result = super.getTopLevelClass(makeClassName(name), ts);
 192  1793 if (result == null) {
 193  1367 LinkedList<String> onDemandNames = new LinkedList<String>();
 194  1367 for (String p : _onDemandPackages) {
 195  1473 String fullName = p + "." + name;
 196  890 if (super.topLevelClassExists(fullName, ts)) { onDemandNames.add(fullName); }
 197    }
 198  0 if (onDemandNames.size() > 1) { throw new AmbiguousNameException(); }
 199  890 else if (onDemandNames.size() == 1) { result = super.getTopLevelClass(onDemandNames.get(0), ts); }
 200    }
 201    }
 202  1793 if (result != null && (_opt.enforcePrivateAccess() || _opt.enforceAllAccess())) {
 203  0 if (!result.accessibility().equals(Access.PUBLIC) &&
 204    !_currentPackage.equals(result.accessModule().packageName())) {
 205  0 result = null;
 206    }
 207    }
 208    }
 209  2550 return result;
 210    }
 211   
 212  0 @Override public boolean memberClassExists(String name, TypeSystem ts) {
 213  0 return importsMemberClass(name, ts) || (!importsTopLevelClass(name, ts) && super.memberClassExists(name, ts));
 214    }
 215   
 216  468 @Override public ClassType typeContainingMemberClass(String name, TypeSystem ts) throws AmbiguousNameException {
 217  468 ClassType result = importedMemberClassType(name, ts);
 218  468 return (result == null && !importsTopLevelClass(name, ts)) ? super.typeContainingMemberClass(name, ts) : result;
 219    }
 220   
 221  766 private boolean importsMemberClass(String name, TypeSystem ts) {
 222  766 try { return importedMemberClassType(name, ts) != null; }
 223  0 catch (AmbiguousNameException e) { return true; }
 224    }
 225   
 226  1234 private ClassType importedMemberClassType(String name, TypeSystem ts) throws AmbiguousNameException {
 227  1234 DJClass explicitImport = _importedMemberClasses.get(name);
 228  1234 ClassType result = explicitImport == null ? null : ts.makeClassType(explicitImport);
 229  1234 if (result == null) {
 230  1234 LinkedList<ClassType> onDemandMatches = new LinkedList<ClassType>();
 231  1234 for (DJClass c : _onDemandClasses) {
 232  0 ClassType t = ts.makeClassType(c);
 233    // accessModule() is not actually the referencing context, but should have
 234    // the same package name, which is all that matters (private members
 235    // should always be inaccessible if they're reached via an import)
 236  0 if (ts.containsClass(t, name, accessModule())) { onDemandMatches.add(t); }
 237    }
 238  1234 for (DJClass c : _staticOnDemandClasses) {
 239  0 ClassType t = ts.makeClassType(c);
 240  0 if (ts.containsStaticClass(t, name, accessModule())) { onDemandMatches.add(t); }
 241    }
 242  0 if (onDemandMatches.size() > 1) { throw new AmbiguousNameException(); }
 243  0 else if (onDemandMatches.size() == 1) { result = onDemandMatches.getFirst(); }
 244  1234 if (result == null) {
 245  1234 result = super.typeContainingMemberClass(name, ts);
 246    }
 247    }
 248  1234 return result;
 249    }
 250   
 251    /* VARIABLES: FIELDS AND LOCAL VARIABLES */
 252   
 253  0 @Override public boolean variableExists(String name, TypeSystem ts) {
 254  0 return importsField(name, ts) || super.variableExists(name, ts);
 255    }
 256   
 257  54 @Override public boolean fieldExists(String name, TypeSystem ts) {
 258  54 return importsField(name, ts) || super.fieldExists(name, ts);
 259    }
 260   
 261  0 @Override public ClassType typeContainingField(String name, TypeSystem ts) throws AmbiguousNameException {
 262  0 ClassType result = importedFieldType(name, ts);
 263  0 return (result == null) ? super.typeContainingField(name, ts) : result;
 264    }
 265   
 266  54 @Override public boolean localVariableExists(String name, TypeSystem ts) {
 267  54 return !importsField(name, ts) && super.localVariableExists(name, ts);
 268    }
 269   
 270  0 @Override public LocalVariable getLocalVariable(String name, TypeSystem ts) {
 271  0 return importsField(name, ts) ? null : super.getLocalVariable(name, ts);
 272    }
 273   
 274  108 private boolean importsField(String name, TypeSystem ts) {
 275  108 try { return importedFieldType(name, ts) != null; }
 276  0 catch (AmbiguousNameException e) { return true; }
 277    }
 278   
 279  108 private ClassType importedFieldType(String name, TypeSystem ts) throws AmbiguousNameException {
 280  108 DJClass explicitImport = _importedFields.get(name);
 281  108 ClassType result = explicitImport == null ? null : ts.makeClassType(explicitImport);
 282  108 if (result == null) {
 283  108 LinkedList<ClassType> onDemandMatches = new LinkedList<ClassType>();
 284  108 for (DJClass c : _staticOnDemandClasses) {
 285  0 ClassType t = ts.makeClassType(c);
 286  0 if (ts.containsStaticField(t, name, accessModule())) { onDemandMatches.add(t); }
 287    }
 288  0 if (onDemandMatches.size() > 1) { throw new AmbiguousNameException(); }
 289  0 else if (onDemandMatches.size() == 1) { result = onDemandMatches.getFirst(); }
 290  108 if (result == null) {
 291  108 result = super.typeContainingField(name, ts);
 292    }
 293    }
 294  108 return result;
 295    }
 296   
 297   
 298    /* METHODS */
 299   
 300  0 @Override public boolean functionExists(String name, TypeSystem ts) {
 301  0 return importsMethod(name, ts) || super.functionExists(name, ts);
 302    }
 303   
 304  0 @Override public boolean methodExists(String name, TypeSystem ts) {
 305  0 return importsMethod(name, ts) || super.methodExists(name, ts);
 306    }
 307   
 308  0 @Override public Type typeContainingMethod(String name, TypeSystem ts) {
 309  0 Type result = importedMethodType(name, ts);
 310  0 return (result == null) ? super.typeContainingMethod(name, ts) : result;
 311    }
 312   
 313  0 @Override public boolean localFunctionExists(String name, TypeSystem ts) {
 314  0 return !importsMethod(name, ts) && super.localFunctionExists(name, ts);
 315    }
 316   
 317  108 @Override public Iterable<LocalFunction> getLocalFunctions(String name, TypeSystem ts,
 318    Iterable<LocalFunction> partial) {
 319  108 boolean keepLooking = IterUtil.isEmpty(partial) && !importsMethod(name, ts);
 320  108 return keepLooking ? super.getLocalFunctions(name, ts, partial) : partial;
 321    }
 322   
 323  0 private boolean importsMethod(String name, TypeSystem ts) {
 324  0 return importedMethodType(name, ts) != null;
 325    }
 326   
 327  0 private Type importedMethodType(String name, final TypeSystem ts) {
 328  0 Iterable<ClassType> matches;
 329  0 Iterable<DJClass> explicitImports = _importedMethods.matchFirst(name);
 330  0 if (!IterUtil.isEmpty(explicitImports)) {
 331  0 matches = IterUtil.mapSnapshot(explicitImports, new Lambda<DJClass, ClassType>() {
 332  0 public ClassType value(DJClass c) { return ts.makeClassType(c); }
 333    });
 334    }
 335    else {
 336  0 LinkedList<ClassType> onDemandMatches = new LinkedList<ClassType>();
 337  0 for (DJClass c : _staticOnDemandClasses) {
 338  0 ClassType t = ts.makeClassType(c);
 339  0 if (ts.containsStaticMethod(t, name, accessModule())) { onDemandMatches.add(t); }
 340    }
 341  0 matches = onDemandMatches;
 342    }
 343   
 344  0 switch (IterUtil.sizeOf(matches, 2)) {
 345  0 case 0: return null;
 346  0 case 1: return IterUtil.first(matches);
 347  0 default: return new IntersectionType(matches);
 348    }
 349    }
 350   
 351   
 352    /* MISC CONTEXTUAL INFORMATION */
 353   
 354  929 @Override public Access.Module accessModule() { return new TopLevelAccessModule(_currentPackage); }
 355   
 356    /** Return a full name for a class with the given name declared here. */
 357  1882 @Override public String makeClassName(String n) {
 358  1882 return _currentPackage.equals("") ? n : _currentPackage + "." + n;
 359    }
 360   
 361    /** Return a full name for an anonymous class declared here. */
 362  0 @Override public String makeAnonymousClassName() {
 363  0 return makeClassName("$" + _anonymousCounter.next().toString());
 364    }
 365   
 366    /**
 367    * Return the type of {@code this} in the current context, or {@code null}
 368    * if there is no such value (for example, in a static context).
 369    */
 370  0 @Override public DJClass getThis() { return null; }
 371   
 372    /**
 373    * Return the type of {@code className.this} in the current context, or {@code null}
 374    * if there is no such value (for example, in a static context).
 375    */
 376  0 @Override public DJClass getThis(String className) { return null; }
 377   
 378  108 @Override public DJClass getThis(Type expected, TypeSystem ts) { return null; }
 379   
 380  0 @Override public DJClass initializingClass() { return null; }
 381   
 382    /**
 383    * The expected type of a {@code return} statement in the given context, or {@code null}
 384    * if {@code return} statements should not appear here.
 385    */
 386  0 @Override public Type getReturnType() { return null; }
 387   
 388    /**
 389    * The types that are allowed to be thrown in the current context. If there is no
 390    * such declaration, the list will be empty.
 391    */
 392  524 @Override public Iterable<Type> getDeclaredThrownTypes() {
 393    // the top level "catches" anything that is thrown.
 394  524 return IterUtil.<Type>singleton(TypeSystem.THROWABLE);
 395    }
 396   
 397    }