Clover coverage report - Java Language Levels Test Coverage (javalanglevels-20120305-r5436)
Coverage timestamp: Sun Mar 4 2012 22:02:46 CST
file stats: LOC: 655   Methods: 19
NCLOC: 411   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
LValueWithValueTypeChecker.java 97.4% 99.7% 94.7% 99.1%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.javalanglevels;
 38   
 39    import edu.rice.cs.javalanglevels.tree.*;
 40    import edu.rice.cs.javalanglevels.parser.JExprParser;
 41    import java.util.*;
 42    import java.io.File;
 43    import edu.rice.cs.plt.reflect.JavaVersion;
 44    import edu.rice.cs.plt.iter.*;
 45   
 46    import junit.framework.TestCase;
 47   
 48   
 49    /** Used to type check the LHS of an assignment expression such as += or -=, where the left hand side needs to not be final
 50    * and already have a value.
 51    */
 52    public class LValueWithValueTypeChecker extends JExpressionIFAbstractVisitor<TypeData> {
 53   
 54    /** Instance of the testAssignable visitor that will be used to make sure that if the lhs
 55    * is something of the type that could be assigned to, it can actually be assigned to*/
 56    private final TestAssignable _testAssignableInstance;
 57   
 58    // The visitor that invoked this: holds the error list
 59    private final SpecialTypeChecker _bob;
 60   
 61    /* Constructor for LValueTypeChecker. Initializes _testAssignableInstance.
 62    * @param bob The visitor that invoked this visitor.
 63    */
 64  37 public LValueWithValueTypeChecker(SpecialTypeChecker bob) {
 65  37 _testAssignableInstance = new TestAssignable(bob._data, bob._file, bob._package, bob._importedFiles, bob._importedPackages, bob._vars, bob._thrown);
 66  37 _bob = bob;
 67    }
 68   
 69    /** Most expressions cannot appear on the lhs of an assignment: give an appropriate error */
 70  3 public TypeData defaultCase(JExpressionIF that) {
 71  3 _bob._addError("You cannot assign a value to an expression of this kind. Values can only be assigned to fields or variables", that);
 72  3 return null;
 73    }
 74   
 75    /**An increment expression is a special case that cannot appear on the lhs*/
 76  2 public TypeData forIncrementExpression(IncrementExpression that) {
 77  2 _bob._addError("You cannot assign a value to an increment expression", that);
 78  2 return null;
 79    }
 80   
 81    /* Names can appear on the lhs, so check to see if the name can be assigned to*/
 82  55 public TypeData forNameReference(NameReference that) {
 83  55 return that.visit(_testAssignableInstance);
 84    }
 85   
 86    /** Array accesses can appear on the lhs, so check to see if the array can be assigned to*/
 87  3 public TypeData forArrayAccess(ArrayAccess that) {
 88  3 return that.visit(_testAssignableInstance);
 89    }
 90   
 91    /** Recur on the value stored in the parentheses*/
 92  10 public TypeData forParenthesized(Parenthesized that) {
 93  10 return that.getValue().visit(this);
 94    }
 95   
 96    /** Checks to see if what is on the lhs is assignable to and already has a value*/
 97    private class TestAssignable extends ExpressionTypeChecker {
 98   
 99  37 public TestAssignable(Data data, File file, String packageName, LinkedList<String> importedFiles, LinkedList<String> importedPackages, LinkedList<VariableData> vars, LinkedList<Pair<SymbolData, JExpression>> thrown) {
 100  37 super(data, file, packageName, importedFiles, importedPackages, vars, thrown);
 101    }
 102   
 103    /** The variable referenced here should already have a value and should not be final. */
 104  22 public TypeData forSimpleNameReference(SimpleNameReference that) {
 105  22 Word myWord = that.getName();
 106  22 myWord.visit(this);
 107   
 108  22 VariableData reference = getFieldOrVariable(myWord.getText(), _data, _data.getSymbolData(), that, _vars, true, true);
 109  22 if (reference != null) {
 110  14 if (!reference.hasValue()) {
 111  1 _addError("You cannot use " + reference.getName() + " here, because it may not have been given a value", that.getName());
 112    }
 113  13 else if (reference.isFinal()) {
 114  1 _addError("You cannot assign a new value to " + reference.getName() + " because it is immutable and has already been given a value", that.getName());
 115    }
 116   
 117    //if reference is non-static, but context is static, give error
 118  12 else if (! reference.hasModifier("static") && inStaticMethod()) {
 119  1 _addError("Non static field or variable " + reference.getName() + " cannot be referenced from a static context", that);
 120    }
 121   
 122  14 return reference.getType().getInstanceData();
 123   
 124    }
 125   
 126  8 SymbolData classR = findClassReference(null, myWord.getText(), that);
 127  1 if (classR == SymbolData.AMBIGUOUS_REFERENCE) {return null;}
 128  7 if (classR != null) {
 129  6 if (checkAccess(that, classR.getMav(), classR.getName(), classR, _data.getSymbolData(), "class or interface", false)) {
 130  5 return classR;
 131    }
 132    }
 133  2 PackageData packageD = new PackageData(myWord.getText());
 134  2 return packageD;
 135    }
 136   
 137    /**
 138    * Here is a table that explains what is allowed:
 139    * result:
 140    * left: package | symbol | instance
 141    * package | yes yes(if class exists) no
 142    * symbol | no yes, if static inner class yes if field is static and assignable
 143    * instance | no ERROR yes, if field is assignable
 144    */
 145  33 public TypeData forComplexNameReference(ComplexNameReference that) {
 146  33 ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
 147  33 TypeData lhs = that.getEnclosing().visit(etc);
 148  33 _bob.thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned);
 149  33 Word myWord = that.getName();
 150   
 151    //if lhs is a package data, either we found a class reference or this piece is still part of the package
 152  33 if (lhs instanceof PackageData) {
 153  2 SymbolData classRef = findClassReference(lhs, myWord.getText(), that);
 154  1 if (classRef != null) {return classRef;}
 155  1 return new PackageData((PackageData) lhs, myWord.getText());
 156    }
 157   
 158    //if the word is a variable reference, make sure it can be seen from this context
 159  31 VariableData reference = getFieldOrVariable(myWord.getText(), lhs.getSymbolData(), _data.getSymbolData(), that);
 160  31 if (reference != null) {
 161  25 if (lhs instanceof SymbolData) {
 162    //does this reference a field? if so, it must be static
 163  3 if (!reference.hasModifier("static")) {
 164  1 _addError("Non-static variable " + reference.getName() + " cannot be accessed from the static context " + Data.dollarSignsToDots(lhs.getName()) + ". Perhaps you meant to instantiate an instance of " + Data.dollarSignsToDots(lhs.getName()), that);
 165  1 return reference.getType().getInstanceData();
 166    }
 167    }
 168   
 169    //make sure it already had a value
 170  24 if (!reference.hasValue()) {
 171  7 _addError("You cannot use " + reference.getName() + " here, because it may not have been given a value", that.getName());
 172    }
 173   
 174    //make sure it can be assigned
 175  24 if (!canBeAssigned(reference)) {
 176  5 _addError("You cannot assign a new value to " + reference.getName() + " because it is immutable and has already been given a value", that.getName());
 177    }
 178  24 return reference.getType().getInstanceData();
 179    }
 180   
 181    //does this reference an inner class? if so, it must be static
 182  6 SymbolData sd = getSymbolData(true, myWord.getText(), lhs.getSymbolData(), that, false);
 183  6 if (sd != null && sd != SymbolData.AMBIGUOUS_REFERENCE) {
 184   
 185  1 if (!checkAccess(that, sd.getMav(), sd.getName(), sd, _data.getSymbolData(), "class or interface")) {return null;}
 186   
 187   
 188  3 if (!sd.hasModifier("static")) {
 189  2 _addError("Non-static inner class " +Data.dollarSignsToDots(sd.getName()) + " cannot be accessed from this context. Perhaps you meant to instantiate it", that);
 190    }
 191   
 192    //you cannot reference static inner classes from the context of an instantiation of their outer class
 193  1 else if (lhs instanceof InstanceData) {
 194  1 _addError("You cannot reference the static inner class " + Data.dollarSignsToDots(sd.getName()) + " from an instance of " + Data.dollarSignsToDots(lhs.getName()), that);
 195    }
 196  3 return sd;
 197    }
 198   
 199  1 if (sd != SymbolData.AMBIGUOUS_REFERENCE) {_addError("Could not resolve " + myWord.getText() +
 200    " from the context of " +
 201    Data.dollarSignsToDots(lhs.getName()), that);}
 202  2 return null;
 203    }
 204   
 205    /** Type-check the lhs and the index. */
 206  3 public TypeData forArrayAccess(ArrayAccess that) {
 207  3 ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
 208  3 TypeData lhs = that.getArray().visit(etc);
 209  3 _bob.thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned); //update internal SpecialTypeChecker's list of what got assigned
 210   
 211  3 ExpressionTypeChecker indexTC = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
 212  3 TypeData index = that.getIndex().visit(indexTC);
 213  3 _bob.thingsThatHaveBeenAssigned.addAll(indexTC.thingsThatHaveBeenAssigned); //update internal SpecialTypeChecker's list of what got assigned
 214   
 215  3 return forArrayAccessOnly(that, lhs, index);
 216    }
 217   
 218    }
 219   
 220   
 221    /**Test the methods defined in the above class*/
 222    public static class LValueWithValueTypeCheckerTest extends TestCase {
 223   
 224    private LValueWithValueTypeChecker _lvtc;
 225    LValueWithValueTypeChecker.TestAssignable _ta;
 226   
 227   
 228    private SymbolData _sd1;
 229    private SymbolData _sd2;
 230    private SymbolData _sd3;
 231    private SymbolData _sd4;
 232    private SymbolData _sd5;
 233    private SymbolData _sd6;
 234    private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
 235    private ModifiersAndVisibility _protectedMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
 236    private ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
 237    private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
 238    private ModifiersAndVisibility _abstractMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
 239    private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
 240    private ModifiersAndVisibility _finalPublicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final", "public"});
 241    private ModifiersAndVisibility _publicAbstractMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "abstract"});
 242    private ModifiersAndVisibility _publicStaticMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "static"});
 243   
 244   
 245  0 public LValueWithValueTypeCheckerTest() {
 246  0 this("");
 247    }
 248  6 public LValueWithValueTypeCheckerTest(String name) {
 249  6 super(name);
 250    }
 251   
 252  6 public void setUp() {
 253  6 _sd1 = new SymbolData("i.like.monkey");
 254  6 _sd2 = new SymbolData("i.like.giraffe");
 255  6 _sd3 = new SymbolData("zebra");
 256  6 _sd4 = new SymbolData("u.like.emu");
 257  6 _sd5 = new SymbolData("");
 258  6 _sd6 = new SymbolData("cebu");
 259  6 _lvtc =
 260    new LValueWithValueTypeChecker(new SpecialTypeChecker(_sd1, new File(""), "", new LinkedList<String>(),
 261    new LinkedList<String>(), new LinkedList<VariableData>(),
 262    new LinkedList<Pair<SymbolData, JExpression>>()));
 263  6 _ta = _lvtc._testAssignableInstance;
 264  6 _lvtc._bob.errors = new LinkedList<Pair<String, JExpressionIF>>();
 265  6 LanguageLevelConverter.symbolTable.clear();
 266    // LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, IterUtil.<File>empty());
 267  6 _lvtc._bob._importedPackages.addFirst("java.lang");
 268    }
 269   
 270    //Test methods of LeftValueTypeChecker:
 271   
 272  1 public void testDefaultCase() {
 273    //should add an error
 274  1 new NullLiteral(SourceInfo.NONE).visit(_lvtc);
 275  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 276  1 assertEquals("Error message should be correct", "You cannot assign a value to an expression of this kind. Values can only be assigned to fields or variables",
 277    _lvtc._bob.errors.getLast().getFirst());
 278   
 279    //should add an error
 280  1 new PlusExpression(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 21), new IntegerLiteral(SourceInfo.NONE, 22)).visit(_lvtc);
 281  1 assertEquals("Should be 2 errors", 2, _lvtc._bob.errors.size());
 282  1 assertEquals("Error message should be correct", "You cannot assign a value to an expression of this kind. Values can only be assigned to fields or variables",
 283    _lvtc._bob.errors.getLast().getFirst());
 284    }
 285   
 286  1 public void testForIncrementExpression() {
 287    //should add an error
 288  1 PositivePrefixIncrementExpression p = new PositivePrefixIncrementExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "bob")));
 289  1 assertEquals("Should return null", null, p.visit(_lvtc));
 290  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 291  1 assertEquals("Error message should be correct", "You cannot assign a value to an increment expression", _lvtc._bob.errors.getLast().getFirst());
 292    }
 293   
 294   
 295  1 public void testForSimpleNameReference() {
 296    //first, consider the case where what we have is a variable reference:
 297  1 SimpleNameReference var = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1"));
 298  1 VariableData varData = new VariableData("variable1", _publicMav, SymbolData.INT_TYPE, false, _ta._data);
 299  1 _ta._vars.add(varData);
 300   
 301    //in this case, it has not been initialized--should throw error because it needs to have already had a value
 302  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 303  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 304  1 assertEquals("Error message should be correct", "You cannot use variable1 here, because it may not have been given a value", _lvtc._bob.errors.getLast().getFirst());
 305   
 306    //if it has been initialized but is not final, do not give an error
 307  1 varData.gotValue();
 308  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 309  1 assertEquals("Should still be 1 error", 1, _lvtc._bob.errors.size());
 310   
 311    //if it has been initialized and is final, give an error
 312  1 varData.setMav(_finalMav);
 313  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 314  1 assertEquals("Should be 2 errors", 2, _lvtc._bob.errors.size());
 315  1 assertEquals("Error message should be correct", "You cannot assign a new value to variable1 because it is immutable and has already been given a value", _lvtc._bob.errors.getLast().getFirst());
 316  1 varData.setMav(_publicMav);
 317   
 318    //if variable is non-static, but you are in static context, cannot reference it. Should give error
 319  1 MethodData newContext = new MethodData("method", _publicStaticMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[0], new String[0], _sd1, new NullLiteral(SourceInfo.NONE));
 320  1 _ta._data = newContext;
 321  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 322  1 assertEquals("Should be 3 errors", 3, _lvtc._bob.errors.size());
 323  1 assertEquals("Error message should be correct", "Non static field or variable variable1 cannot be referenced from a static context", _lvtc._bob.errors.getLast().getFirst());
 324  1 _ta._data = _sd1;
 325   
 326    //if it is a variable of your super class, it won't be in _vars. Check this case.
 327  1 _ta._vars = new LinkedList<VariableData>();
 328  1 _sd1.setSuperClass(_sd2);
 329  1 _sd2.addVar(varData);
 330  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 331  1 assertEquals("Should still be 3 errors", 3, _lvtc._bob.errors.size());
 332   
 333    //now, consider the case where what we have is a class reference:
 334  1 SimpleNameReference className = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Frog"));
 335  1 SymbolData frog = new SymbolData("Frog");
 336  1 frog.setIsContinuation(false);
 337  1 _lvtc._bob.symbolTable.put("Frog", frog);
 338   
 339    //if it is not visibile from this context, return package data
 340  1 TypeData result = className.visit(_lvtc);
 341  1 assertTrue("Result should be a PackageData since Frog is not accessible", result instanceof PackageData);
 342  1 assertEquals("Should have correct name", "Frog", result.getName());
 343  1 assertEquals("Should still be 3 errors", 3, _lvtc._bob.errors.size());
 344   
 345    //if it is visibile from this context, no error
 346  1 frog.setMav(_publicMav);
 347  1 assertEquals("Should return Frog", frog, className.visit(_lvtc));
 348  1 assertEquals("Should still be 3 errors", 3, _lvtc._bob.errors.size());
 349   
 350    //If the name cannot be resolved, simply return a packageData.
 351  1 SimpleNameReference fake = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "notRealReference"));
 352  1 assertEquals("Should return package data", "notRealReference", (fake.visit(_lvtc)).getName());
 353  1 assertEquals("Should still be just 3 errors", 3, _lvtc._bob.errors.size());
 354   
 355    //if the reference is ambiguous (matches both an interface and a class) give an error
 356  1 SimpleNameReference ambigRef = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "ambigThing"));
 357   
 358  1 SymbolData interfaceD = new SymbolData("interface");
 359  1 interfaceD.setIsContinuation(false);
 360  1 interfaceD.setInterface(true);
 361  1 interfaceD.setMav(_publicMav);
 362   
 363  1 SymbolData classD = new SymbolData("superClass");
 364  1 classD.setIsContinuation(false);
 365  1 classD.setMav(_publicMav);
 366   
 367  1 SymbolData ambigThingI = new SymbolData("ambigThing");
 368  1 ambigThingI.setIsContinuation(false);
 369  1 ambigThingI.setInterface(true);
 370  1 interfaceD.addInnerInterface(ambigThingI);
 371  1 ambigThingI.setOuterData(interfaceD);
 372  1 ambigThingI.setMav(_publicStaticMav);
 373   
 374  1 SymbolData ambigThingC = new SymbolData("ambigThing");
 375  1 ambigThingC.setIsContinuation(false);
 376  1 classD.addInnerClass(ambigThingC);
 377  1 ambigThingC.setOuterData(classD);
 378  1 ambigThingC.setMav(_publicStaticMav);
 379   
 380  1 _sd6.addInterface(interfaceD);
 381  1 _sd6.setSuperClass(classD);
 382   
 383  1 _sd6.setMav(_publicMav);
 384  1 _sd6.setIsContinuation(false);
 385   
 386  1 _ta._data = _sd6;
 387   
 388  1 assertEquals("Should return null", null, ambigRef.visit(_lvtc));
 389  1 assertEquals("Should be 4 errors", 4, _lvtc._bob.errors.size());
 390  1 assertEquals("Error message should be correct", "Ambiguous reference to class or interface ambigThing",
 391    _lvtc._bob.errors.getLast().getFirst());
 392    }
 393   
 394   
 395  1 public void testForComplexNameReference() {
 396    //if lhs is a package data, we want to keep building it:
 397   
 398    //if whole reference is just package reference, return package data
 399  1 ComplexNameReference ref1 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "java")), new Word(SourceInfo.NONE, "lang"));
 400  1 assertEquals("Should return correct package data", "java.lang", ref1.visit(_lvtc).getName());
 401  1 assertEquals("Should be no errors", 0, _lvtc._bob.errors.size());
 402   
 403    //if reference builds to a class in the symbol table, return that class
 404  1 ComplexNameReference ref2 = new ComplexNameReference(SourceInfo.NONE, ref1, new Word(SourceInfo.NONE, "String"));
 405  1 SymbolData string = new SymbolData("java.lang.String");
 406  1 string.setPackage("java.lang");
 407  1 string.setMav(_publicMav);
 408  1 string.setIsContinuation(false);
 409  1 _lvtc._bob.symbolTable.put("java.lang.String", string);
 410   
 411  1 assertEquals("Should return string", string, ref2.visit(_lvtc));
 412   
 413  1 assertEquals("Should still be no errors", 0, _lvtc._bob.errors.size());
 414   
 415   
 416    //if lhs is not a package data, it gets more complicated:
 417   
 418    //we're referencing a variable inside of symbol data lhs:
 419  1 VariableData myVar = new VariableData("myVar", _publicStaticMav, SymbolData.DOUBLE_TYPE, true, string);
 420  1 string.addVar(myVar);
 421  1 ComplexNameReference varRef1 = new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "myVar"));
 422   
 423    //static var from static context
 424  1 assertEquals("Should return Double_Type instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_lvtc));
 425  1 assertEquals("There should still be no errors", 0, _lvtc._bob.errors.size());
 426   
 427    //static uninitialized var from static context--give error
 428  1 myVar.lostValue();
 429  1 assertEquals("Should return Double_Type instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_lvtc));
 430  1 assertEquals("There should be one error", 1, _lvtc._bob.errors.size());
 431  1 assertEquals("Error message should be correct", "You cannot use myVar here, because it may not have been given a value", _lvtc._bob.errors.getLast().getFirst());
 432   
 433   
 434    //non-static var--this is a static context
 435  1 myVar.setMav(_publicMav);
 436  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_lvtc));
 437  1 assertEquals("Should be 2 errors", 2, _lvtc._bob.errors.size());
 438  1 assertEquals("Error message should be correct", "Non-static variable myVar cannot be accessed from the static context java.lang.String. Perhaps you meant to instantiate an instance of java.lang.String", _lvtc._bob.errors.getLast().getFirst());
 439   
 440   
 441    //non-static context, okay to reference non-static var
 442  1 VariableData stringVar = new VariableData("s", _publicMav, string, true, _lvtc._bob._data);
 443  1 _ta._vars.add(stringVar);
 444  1 myVar.gotValue();
 445  1 ComplexNameReference varRef2 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")), new Word(SourceInfo.NONE, "myVar"));
 446  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_lvtc));
 447  1 assertEquals("Should still just be 2 errors", 2, _lvtc._bob.errors.size());
 448   
 449    //if it has been initialized and is final, give an error
 450  1 myVar.setMav(_finalPublicMav);
 451  1 myVar.gotValue();
 452  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_lvtc));
 453  1 assertEquals("Should be 3 errors", 3, _lvtc._bob.errors.size());
 454  1 assertEquals("Error message should be correct", "You cannot assign a new value to myVar because it is immutable and has already been given a value", _lvtc._bob.errors.getLast().getFirst());
 455  1 myVar.setMav(_publicMav);
 456   
 457    //if it is a variable of the super class, you should still be able to see it. Check this case.
 458  1 myVar.setMav(_publicMav);
 459  1 string.setVars(new LinkedList<VariableData>());
 460  1 string.setSuperClass(_sd2);
 461  1 _sd2.addVar(myVar);
 462  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_lvtc));
 463  1 assertEquals("Should still be 3 errors", 3, _lvtc._bob.errors.size());
 464   
 465    //here's a complex multiple variable reference case:
 466  1 VariableData vd1 = new VariableData("Mojo", _publicMav, SymbolData.INT_TYPE, true, _sd1);
 467  1 VariableData vd2 = new VariableData("Santa's Little Helper", _publicMav, _sd1, true, _sd2);
 468  1 VariableData vd3 = new VariableData("Snowball1", _publicMav, _sd2, true, _sd3);
 469  1 _sd3.addVar(vd3);
 470  1 _sd2.addVar(vd2);
 471  1 _sd1.addVar(vd1);
 472   
 473  1 ComplexNameReference varRef3 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Snowball1")),
 474    new Word(SourceInfo.NONE, "Santa's Little Helper"));
 475  1 ComplexNameReference varRef4 = new ComplexNameReference(SourceInfo.NONE, varRef3, new Word(SourceInfo.NONE, "Mojo"));
 476   
 477  1 Data oldData = _lvtc._bob._data;
 478  1 _lvtc._bob._data = _sd3;
 479  1 _lvtc._bob._vars.add(vd3);
 480   
 481  1 TypeData result = varRef4.visit(_lvtc);
 482  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), result);
 483  1 assertEquals("Should still be 3 errors", 3, _lvtc._bob.errors.size());
 484   
 485   
 486  1 _lvtc._bob._data = oldData;
 487   
 488   
 489    //what if what we have is an inner class?
 490  1 SymbolData inner = new SymbolData("java.lang.String$Inner");
 491  1 inner.setPackage("java.lang");
 492  1 inner.setIsContinuation(false);
 493  1 inner.setOuterData(string);
 494  1 string.addInnerClass(inner);
 495   
 496   
 497    //if inner is not visible, throw error
 498  1 ComplexNameReference innerRef0 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")), new Word(SourceInfo.NONE, "Inner"));
 499  1 assertEquals("Should return null", null, innerRef0.visit(_lvtc));
 500  1 assertEquals("Should be 4 errors", 4, _lvtc._bob.errors.size());
 501  1 assertEquals("Error message should be correct", "The class or interface java.lang.String.Inner is package protected because there is no access specifier and cannot be accessed from i.like.monkey", _lvtc._bob.errors.getLast().getFirst());
 502   
 503  1 inner.setMav(_publicMav);
 504   
 505    //if inner is not static, give error:
 506  1 ComplexNameReference innerRef1 = new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "Inner"));
 507  1 assertEquals("Should return inner", inner, innerRef1.visit(_lvtc));
 508  1 assertEquals("Should be 5 errors", 5, _lvtc._bob.errors.size());
 509  1 assertEquals("Error message should be correct", "Non-static inner class java.lang.String.Inner cannot be accessed from this context. Perhaps you meant to instantiate it", _lvtc._bob.errors.getLast().getFirst());
 510   
 511    //if inner is not static and outer is not static, it's okay...
 512  1 ComplexNameReference innerRef2 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")), new Word(SourceInfo.NONE, "Inner"));
 513  1 assertEquals("Should return inner", inner, innerRef2.visit(_lvtc));
 514  1 assertEquals("Should be 6 errors", 6, _lvtc._bob.errors.size());
 515  1 assertEquals("Error message should be correct", "Non-static inner class java.lang.String.Inner cannot be accessed from this context. Perhaps you meant to instantiate it", _lvtc._bob.errors.getLast().getFirst());
 516   
 517    //if inner is static and outer is not static, throw error
 518  1 inner.setMav(_publicStaticMav);
 519  1 assertEquals("Should return inner", inner, innerRef2.visit(_lvtc));
 520  1 assertEquals("Should be 7 errors", 7, _lvtc._bob.errors.size());
 521  1 assertEquals("Error message should be correct", "You cannot reference the static inner class java.lang.String.Inner from an instance of java.lang.String", _lvtc._bob.errors.getLast().getFirst());
 522   
 523   
 524    //if the symbol could not be matched, give an error and return null
 525  1 ComplexNameReference noSense = new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "nonsense"));
 526  1 assertEquals("Should return null", null, noSense.visit(_lvtc));
 527  1 assertEquals("Should be 8 errors", 8, _lvtc._bob.errors.size());
 528  1 assertEquals("Error message should be correct", "Could not resolve nonsense from the context of java.lang.String", _lvtc._bob.errors.getLast().getFirst());
 529   
 530    //if the reference is ambiguous (matches both an interface and a class) give an error
 531  1 ComplexNameReference ambigRef = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "cebu")), new Word(SourceInfo.NONE, "ambigThing"));
 532   
 533  1 SymbolData interfaceD = new SymbolData("interface");
 534  1 interfaceD.setIsContinuation(false);
 535  1 interfaceD.setInterface(true);
 536  1 interfaceD.setMav(_publicMav);
 537   
 538  1 SymbolData classD = new SymbolData("superClass");
 539  1 classD.setIsContinuation(false);
 540  1 classD.setMav(_publicMav);
 541   
 542  1 SymbolData ambigThingI = new SymbolData("ambigThing");
 543  1 ambigThingI.setIsContinuation(false);
 544  1 ambigThingI.setInterface(true);
 545  1 interfaceD.addInnerInterface(ambigThingI);
 546  1 ambigThingI.setOuterData(interfaceD);
 547  1 ambigThingI.setMav(_publicStaticMav);
 548   
 549  1 SymbolData ambigThingC = new SymbolData("ambigThing");
 550  1 ambigThingC.setIsContinuation(false);
 551  1 classD.addInnerClass(ambigThingC);
 552  1 ambigThingC.setOuterData(classD);
 553  1 ambigThingC.setMav(_publicStaticMav);
 554   
 555  1 _sd6.addInterface(interfaceD);
 556  1 _sd6.setSuperClass(classD);
 557   
 558  1 _lvtc._bob.symbolTable.put("cebu", _sd6);
 559  1 _sd6.setMav(_publicMav);
 560  1 _sd6.setIsContinuation(false);
 561   
 562  1 assertEquals("Should return null", null, ambigRef.visit(_lvtc));
 563  1 assertEquals("Should be 9 errors", 9, _lvtc._bob.errors.size());
 564    // TODO: should following error message mention the context 'cebu'?
 565  1 assertEquals("Error message should be correct", "Ambiguous reference to class or interface ambigThing",
 566    _lvtc._bob.errors.getLast().getFirst());
 567   
 568    }
 569   
 570   
 571  1 public void testForArrayAccess() {
 572  1 ArrayData intArray =
 573    new ArrayData(SymbolData.INT_TYPE,
 574    new LanguageLevelVisitor(_lvtc._bob._file,
 575    _lvtc._bob._package,
 576    null, // enclosingClassName for top level traversal
 577    _lvtc._bob._importedFiles,
 578    _lvtc._bob._importedPackages,
 579    new HashSet<String>(),
 580    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 581    new LinkedList<Command>()),
 582    SourceInfo.NONE);
 583  1 VariableData variable1 = new VariableData("variable1", _publicMav, intArray, true, _ta._data);
 584  1 _ta._vars.add(variable1);
 585   
 586  1 VariableData intVar = new VariableData("intVar", _publicMav, SymbolData.INT_TYPE, true, _ta._data);
 587  1 _ta._vars.add(intVar);
 588   
 589  1 MethodData makeArray = new MethodData("makeArray", _privateMav, new TypeParameter[0], intArray, new VariableData[0], new String[0], _ta._data.getSymbolData(), new NullLiteral(SourceInfo.NONE));
 590  1 _ta._data.getSymbolData().addMethod(makeArray);
 591   
 592    //first, a simple index into an int[]
 593   
 594  1 ArrayAccess a1 = new ArrayAccess(SourceInfo.NONE,
 595    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1")),
 596    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "intVar")));
 597   
 598  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), a1.visit(_lvtc));
 599  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 600   
 601   
 602    //make sure that an arbitrary expression can occur in the index
 603   
 604  1 ArrayAccess a2 = new ArrayAccess(SourceInfo.NONE,
 605    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1")),
 606    new PlusExpression(SourceInfo.NONE,
 607    new IntegerLiteral(SourceInfo.NONE, 12),
 608    new IntegerLiteral(SourceInfo.NONE, 22)));
 609   
 610  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), a2.visit(_lvtc));
 611  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 612   
 613    //make sure that an arbitrary expression can occur in the array
 614   
 615  1 ArrayAccess a3 = new ArrayAccess(SourceInfo.NONE,
 616    new SimpleMethodInvocation(SourceInfo.NONE,
 617    new Word(SourceInfo.NONE, "makeArray"),
 618    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])),
 619    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "intVar")));
 620  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), a3.visit(_lvtc));
 621  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 622    }
 623   
 624  1 public void testForParenthesized() {
 625   
 626  1 VariableData x = new VariableData("x", _publicMav, SymbolData.INT_TYPE, true, _ta._data);
 627  1 _ta._vars.add(x);
 628   
 629    // make sure (((x))) is okay
 630  1 Parenthesized p1 = new Parenthesized(SourceInfo.NONE,
 631    new Parenthesized(SourceInfo.NONE,
 632    new Parenthesized(SourceInfo.NONE,
 633    new SimpleNameReference(SourceInfo.NONE,
 634    new Word(SourceInfo.NONE, "x")))));
 635   
 636  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), p1.visit(_lvtc));
 637  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 638   
 639    // make sure ((1)) breaks
 640  1 Parenthesized p2 = new Parenthesized(SourceInfo.NONE,
 641    new Parenthesized(SourceInfo.NONE,
 642    new IntegerLiteral(SourceInfo.NONE, 1)));
 643  1 assertEquals("should return null", null, p2.visit(_lvtc));
 644  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 645  1 assertEquals("Error message should be correct", "You cannot assign a value to an expression of this kind. Values can only be assigned to fields or variables",
 646    _lvtc._bob.errors.getLast().getFirst());
 647   
 648    }
 649   
 650   
 651   
 652    //methods of TestAssignable are implicitly tested above.
 653   
 654    }
 655    }