Clover coverage report - Java Language Levels Test Coverage (javalanglevels-20120305-r5436)
Coverage timestamp: Sun Mar 4 2012 22:02:46 CST
file stats: LOC: 650   Methods: 20
NCLOC: 402   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
LValueTypeChecker.java 97.4% 99.7% 95% 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    /** Do what is necessary to type check the lhs of an assignment expression, i.e., make sure that
 50    * what is on the lhs is something that can be assigned to, and if so, return its type.
 51    */
 52    public class LValueTypeChecker 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  65 public LValueTypeChecker(SpecialTypeChecker bob) {
 65  65 _testAssignableInstance = new TestAssignable(bob._data, bob._file, bob._package, bob._importedFiles, bob._importedPackages, bob._vars, bob._thrown);
 66  65 _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  1 public TypeData forIncrementExpression(IncrementExpression that) {
 77  1 _bob._addError("You cannot assign a value to an increment expression", that);
 78  1 return null;
 79    }
 80   
 81    /*Names can appear on the lhs, so check to see if the name can be assigned to*/
 82  83 public TypeData forNameReference(NameReference that) {
 83  83 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  4 public TypeData forArrayAccess(ArrayAccess that) {
 88  4 return that.visit(_testAssignableInstance);
 89    }
 90   
 91    /**Recur on the value stored in the parentheses*/
 92  5 public TypeData forParenthesized(Parenthesized that) {
 93  5 return that.getValue().visit(this);
 94    }
 95   
 96    /**Checks to see if what is on the lhs is assignable*/
 97    private class TestAssignable extends ExpressionTypeChecker {
 98   
 99  65 public TestAssignable(Data data, File file, String packageName, LinkedList<String> importedFiles, LinkedList<String> importedPackages, LinkedList<VariableData> vars, LinkedList<Pair<SymbolData, JExpression>> thrown) {
 100  65 super(data, file, packageName, importedFiles, importedPackages, vars, thrown);
 101    }
 102   
 103    /** A SimpleName reference is one of three things:
 104    * 1. A variable reference, in which case the variable can be assigned to as long as it is not immutable and
 105    * already has a value, or it is non-static in a static context
 106    * 2. A class name reference (such as String), which cannot be assigned to.
 107    * 3. A PackageData i.e. unresolved type which cannot be assigned to.
 108    */
 109  63 public TypeData forSimpleNameReference(SimpleNameReference that) {
 110  63 Word myWord = that.getName();
 111  63 myWord.visit(this);
 112   
 113  63 VariableData reference = getFieldOrVariable(myWord.getText(), _data, _data.getSymbolData(), that, _vars, true, true);
 114  63 if (reference != null) {
 115  56 if (! canBeAssigned(reference)) {
 116  3 _addError("You cannot assign a value to " + reference.getName() + " because it is immutable and has already been given a value", that.getName());
 117    }
 118  40 else if (reference.gotValue()) { _bob.thingsThatHaveBeenAssigned.add(reference);}
 119   
 120   
 121    // if reference is non-static, but context is static, give error
 122  56 if (! reference.hasModifier("static") && inStaticMethod()) {
 123  1 _addError("Non static field or variable " + reference.getName() + " cannot be referenced from a static context", that);
 124    }
 125   
 126  56 return reference.getType().getInstanceData();
 127    }
 128   
 129  7 SymbolData classR = findClassReference(null, myWord.getText(), that);
 130  1 if (classR == SymbolData.AMBIGUOUS_REFERENCE) {return null;}
 131  6 if (classR != null) {
 132  3 if (checkAccess(that, classR.getMav(), classR.getName(), classR, _data.getSymbolData(), "class or interface", false)) {
 133  2 return classR;
 134    }
 135    }
 136   
 137  4 PackageData packageD = new PackageData(myWord.getText());
 138  4 return packageD;
 139    }
 140   
 141    /** Here is a table that explains what is allowed:
 142    * result:
 143    * left: package | symbol | instance
 144    * package | yes yes(if class exists) no
 145    * symbol | no yes, if static inner class yes if field is static and assignable
 146    * instance | no ERROR yes, if field is assignable
 147    */
 148  20 public TypeData forComplexNameReference(ComplexNameReference that) {
 149  20 ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
 150  20 TypeData lhs = that.getEnclosing().visit(etc);
 151  20 _bob.thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned); //update internal SpecialTypeChecker's list of what got assigned
 152  20 Word myWord = that.getName();
 153   
 154    //if lhs is a package data, either we found a class reference or this piece is still part of the package
 155  20 if (lhs instanceof PackageData) {
 156  2 SymbolData classRef = findClassReference(lhs, myWord.getText(), that);
 157  1 if (classRef != null) {return classRef;}
 158  1 return new PackageData((PackageData) lhs, myWord.getText());
 159    }
 160   
 161    //if the word is a variable reference, make sure it can be seen from this context
 162  18 VariableData reference = getFieldOrVariable(myWord.getText(), lhs.getSymbolData(), _data.getSymbolData(), that);
 163  18 if (reference != null) {
 164  12 if (lhs instanceof SymbolData) {
 165    //does this reference a field? if so, it must be static
 166  3 if (! reference.hasModifier("static")) {
 167  1 _addError("Non-static variable " + Data.dollarSignsToDots(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);
 168  1 return reference.getType().getInstanceData();
 169    }
 170    }
 171   
 172    //make sure it can be assigned
 173  11 if (!canBeAssigned(reference)) {
 174  2 _addError("You cannot assign a value to " + Data.dollarSignsToDots(reference.getName()) + " because it is immutable and has already been given a value", that.getName());
 175    }
 176   
 177  3 else if (reference.gotValue()) { _bob.thingsThatHaveBeenAssigned.add(reference);}
 178   
 179   
 180  11 return reference.getType().getInstanceData();
 181    }
 182   
 183    //does this reference an inner class? if so, it must be static
 184  6 SymbolData sd = getSymbolData(true, myWord.getText(), lhs.getSymbolData(), that, false);
 185  6 if (sd != null && sd != SymbolData.AMBIGUOUS_REFERENCE) {
 186   
 187  1 if (!checkAccess(that, sd.getMav(), sd.getName(), sd, _data.getSymbolData(), "class or interface")) {return null;}
 188   
 189  3 if (!sd.hasModifier("static")) {
 190  2 _addError("Non-static inner class " + Data.dollarSignsToDots(sd.getName()) + " cannot be accessed from this context. Perhaps you meant to instantiate it", that);
 191    }
 192   
 193    //you cannot reference static inner classes from the context of an instantiation of their outer class
 194  1 else if (lhs instanceof InstanceData) {
 195  1 _addError("You cannot reference the static inner class " + Data.dollarSignsToDots(sd.getName()) + " from an instance of " + Data.dollarSignsToDots(lhs.getName()), that);
 196    }
 197  3 return sd;
 198    }
 199   
 200  1 if (sd != SymbolData.AMBIGUOUS_REFERENCE) {_addError("Could not resolve " + myWord.getText() + " from the context of " + Data.dollarSignsToDots(lhs.getName()), that);}
 201  2 return null;
 202    }
 203   
 204    /**
 205    * Type-check the lhs and the index.
 206    */
 207  4 public TypeData forArrayAccess(ArrayAccess that) {
 208  4 ExpressionTypeChecker etc = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
 209  4 TypeData lhs = that.getArray().visit(etc);
 210  4 _bob.thingsThatHaveBeenAssigned.addAll(etc.thingsThatHaveBeenAssigned); //update internal SpecialTypeChecker's list of what got assigned
 211   
 212  4 ExpressionTypeChecker indexTC = new ExpressionTypeChecker(_data, _file, _package, _importedFiles, _importedPackages, _vars, _thrown);
 213  4 TypeData index = that.getIndex().visit(indexTC);
 214  4 _bob.thingsThatHaveBeenAssigned.addAll(indexTC.thingsThatHaveBeenAssigned); //update internal SpecialTypeChecker's list of what got assigned
 215   
 216   
 217  4 return forArrayAccessOnly(that, lhs, index);
 218    }
 219   
 220    /**A VariableData can be assigned to if it is not final or if it does not already have a value */
 221  67 protected boolean canBeAssigned(VariableData vd) {
 222  67 return !vd.isFinal() || !vd.hasValue();
 223    }
 224   
 225    }
 226   
 227    /**
 228    * Test the methods defined in the above class
 229    */
 230    public static class LValueTypeCheckerTest extends TestCase {
 231   
 232    private LValueTypeChecker _lvtc;
 233    LValueTypeChecker.TestAssignable _ta;
 234   
 235   
 236    private SymbolData _sd1;
 237    private SymbolData _sd2;
 238    private SymbolData _sd3;
 239    private SymbolData _sd4;
 240    private SymbolData _sd5;
 241    private SymbolData _sd6;
 242    private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
 243    private ModifiersAndVisibility _protectedMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
 244    private ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
 245    private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
 246    private ModifiersAndVisibility _abstractMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
 247    private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
 248    private ModifiersAndVisibility _finalPublicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final", "public"});
 249    private ModifiersAndVisibility _publicAbstractMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "abstract"});
 250    private ModifiersAndVisibility _publicStaticMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "static"});
 251   
 252   
 253  0 public LValueTypeCheckerTest() {
 254  0 this("");
 255    }
 256  6 public LValueTypeCheckerTest(String name) {
 257  6 super(name);
 258    }
 259   
 260  6 public void setUp() {
 261  6 _sd1 = new SymbolData("i.like.monkey");
 262  6 _sd2 = new SymbolData("i.like.giraffe");
 263  6 _sd3 = new SymbolData("zebra");
 264  6 _sd4 = new SymbolData("u.like.emu");
 265  6 _sd5 = new SymbolData("");
 266  6 _sd6 = new SymbolData("cebu");
 267  6 _lvtc =
 268    new LValueTypeChecker(new SpecialTypeChecker(_sd1, new File(""), "", new LinkedList<String>(), new LinkedList<String>(),
 269    new LinkedList<VariableData>(), new LinkedList<Pair<SymbolData, JExpression>>()));
 270  6 _ta = _lvtc._testAssignableInstance;
 271  6 _lvtc._bob.errors = new LinkedList<Pair<String, JExpressionIF>>();
 272  6 LanguageLevelConverter.symbolTable.clear();
 273    // LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, IterUtil.<File>empty());
 274  6 _lvtc._bob._importedPackages.addFirst("java.lang");
 275    }
 276   
 277    //Test methods of LeftValueTypeChecker:
 278   
 279  1 public void testDefaultCase() {
 280    //should add an error
 281  1 new NullLiteral(SourceInfo.NONE).visit(_lvtc);
 282  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 283  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",
 284    _lvtc._bob.errors.getLast().getFirst());
 285   
 286    //should add an error
 287  1 new PlusExpression(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 21), new IntegerLiteral(SourceInfo.NONE, 22)).visit(_lvtc);
 288  1 assertEquals("Should be 2 errors", 2, _lvtc._bob.errors.size());
 289  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",
 290    _lvtc._bob.errors.getLast().getFirst());
 291    }
 292   
 293   
 294  1 public void testForIncrementExpression() {
 295    //should add an error
 296  1 PositivePrefixIncrementExpression p = new PositivePrefixIncrementExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "bob")));
 297  1 assertEquals("Should return null", null, p.visit(_lvtc));
 298  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 299  1 assertEquals("Error message should be correct", "You cannot assign a value to an increment expression", _lvtc._bob.errors.getLast().getFirst());
 300    }
 301   
 302  1 public void testForSimpleNameReference() {
 303    //first, consider the case where what we have is a variable reference:
 304  1 SimpleNameReference var = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1"));
 305  1 VariableData varData = new VariableData("variable1", _publicMav, SymbolData.INT_TYPE, false, _ta._data);
 306  1 _ta._vars.add(varData);
 307   
 308    //in this case, it has not been initialized--but this is okay--should not throw error
 309  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 310  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 311   
 312    //if it has been initialized but is not final, do not give an error
 313  1 varData.gotValue();
 314  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 315  1 assertEquals("Should still be 0 errors", 0, _lvtc._bob.errors.size());
 316   
 317    //if it has been initialized and is final, give an error
 318  1 varData.setMav(_finalMav);
 319  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 320  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 321  1 assertEquals("Error message should be correct", "You cannot assign a value to variable1 because it is immutable and has already been given a value", _lvtc._bob.errors.getLast().getFirst());
 322  1 varData.setMav(_publicMav);
 323   
 324    //if variable is non-static, but you are in static context, cannot reference it. Should give error
 325  1 MethodData newContext = new MethodData("method", _publicStaticMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[0], new String[0], _sd1, new NullLiteral(SourceInfo.NONE));
 326  1 _ta._data = newContext;
 327  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 328  1 assertEquals("Should be 2 errors", 2, _lvtc._bob.errors.size());
 329  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());
 330  1 _ta._data = _sd1;
 331   
 332    //if it is a variable of your super class, it won't be in _vars. Check this case.
 333  1 _ta._vars = new LinkedList<VariableData>();
 334  1 _sd1.setSuperClass(_sd2);
 335  1 _sd2.addVar(varData);
 336  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_lvtc));
 337  1 assertEquals("Should still be 2 errors", 2, _lvtc._bob.errors.size());
 338   
 339    //now, consider the case where what we have is a class reference:
 340  1 SimpleNameReference className = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Frog"));
 341  1 SymbolData frog = new SymbolData("Frog");
 342  1 frog.setIsContinuation(false);
 343  1 _lvtc._bob.symbolTable.put("Frog", frog);
 344   
 345    //if it is not visibile from this context, return package data
 346  1 TypeData result = className.visit(_lvtc);
 347  1 assertTrue("Result should be a PackageData since Frog is not accessible", result instanceof PackageData);
 348  1 assertEquals("Should have correct name", "Frog", result.getName());
 349  1 assertEquals("Should still be 2 errors", 2, _lvtc._bob.errors.size());
 350   
 351    //if it is visibile from this context, no error
 352  1 frog.setMav(_publicMav);
 353  1 assertEquals("Should return Frog", frog, className.visit(_lvtc));
 354  1 assertEquals("Should still be 2 errors", 2, _lvtc._bob.errors.size());
 355   
 356    //If the name cannot be resolved, simply return a packageData.
 357  1 SimpleNameReference fake = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "notRealReference"));
 358  1 assertEquals("Should return package data", "notRealReference", (fake.visit(_lvtc)).getName());
 359  1 assertEquals("Should still be just 2 errors", 2, _lvtc._bob.errors.size());
 360   
 361    //if the reference is ambiguous (matches both an interface and a class) give an error
 362  1 SimpleNameReference ambigRef = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "ambigThing"));
 363   
 364  1 SymbolData interfaceD = new SymbolData("interface");
 365  1 interfaceD.setIsContinuation(false);
 366  1 interfaceD.setInterface(true);
 367  1 interfaceD.setMav(_publicMav);
 368   
 369  1 SymbolData classD = new SymbolData("superClass");
 370  1 classD.setIsContinuation(false);
 371  1 classD.setMav(_publicMav);
 372   
 373  1 SymbolData ambigThingI = new SymbolData("ambigThing");
 374  1 ambigThingI.setIsContinuation(false);
 375  1 ambigThingI.setInterface(true);
 376  1 interfaceD.addInnerInterface(ambigThingI);
 377  1 ambigThingI.setOuterData(interfaceD);
 378  1 ambigThingI.setMav(_publicStaticMav);
 379   
 380  1 SymbolData ambigThingC = new SymbolData("ambigThing");
 381  1 ambigThingC.setIsContinuation(false);
 382  1 classD.addInnerClass(ambigThingC);
 383  1 ambigThingC.setOuterData(classD);
 384  1 ambigThingC.setMav(_publicStaticMav);
 385   
 386  1 _sd6.addInterface(interfaceD);
 387  1 _sd6.setSuperClass(classD);
 388   
 389  1 _sd6.setMav(_publicMav);
 390  1 _sd6.setIsContinuation(false);
 391   
 392  1 _ta._data = _sd6;
 393   
 394  1 assertEquals("Should return null", null, ambigRef.visit(_lvtc));
 395  1 assertEquals("Should be 3 errors", 3, _lvtc._bob.errors.size());
 396  1 assertEquals("Error message should be correct", "Ambiguous reference to class or interface ambigThing", _lvtc._bob.errors.getLast().getFirst());
 397    }
 398   
 399  1 public void testForComplexNameReference() {
 400    //if lhs is a package data, we want to keep building it:
 401   
 402    //if whole reference is just package reference, return package data
 403  1 ComplexNameReference ref1 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "java")), new Word(SourceInfo.NONE, "lang"));
 404  1 assertEquals("Should return correct package data", "java.lang", ref1.visit(_lvtc).getName());
 405  1 assertEquals("Should be no errors", 0, _lvtc._bob.errors.size());
 406   
 407    //if reference builds to a class in the symbol table, return that class
 408  1 ComplexNameReference ref2 = new ComplexNameReference(SourceInfo.NONE, ref1, new Word(SourceInfo.NONE, "String"));
 409  1 SymbolData string = new SymbolData("java.lang.String");
 410  1 string.setPackage("java.lang");
 411  1 string.setMav(_publicMav);
 412  1 string.setIsContinuation(false);
 413  1 _lvtc._bob.symbolTable.put("java.lang.String", string);
 414   
 415  1 assertEquals("Should return string", string, ref2.visit(_lvtc));
 416   
 417  1 assertEquals("Should still be no errors", 0, _lvtc._bob.errors.size());
 418   
 419   
 420    //if lhs is not a package data, it gets more complicated:
 421   
 422    //we're referencing a variable inside of symbol data lhs:
 423  1 VariableData myVar = new VariableData("myVar", _publicStaticMav, SymbolData.DOUBLE_TYPE, true, string);
 424  1 string.addVar(myVar);
 425  1 ComplexNameReference varRef1 = new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "myVar"));
 426   
 427    //static var from static context
 428  1 assertEquals("Should return Double_Type instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_lvtc));
 429  1 assertEquals("There should still be no errors", 0, _lvtc._bob.errors.size());
 430   
 431    //static uninitialized var from static context--okay, because we want to give it a value
 432  1 myVar.lostValue();
 433  1 assertEquals("Should return Double_Type instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_lvtc));
 434  1 assertEquals("There should still be no errors", 0, _lvtc._bob.errors.size());
 435   
 436   
 437    //non-static var--this is a static context
 438  1 myVar.setMav(_publicMav);
 439  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_lvtc));
 440  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 441  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());
 442   
 443   
 444    //non-static context, okay to reference non-static var
 445  1 VariableData stringVar = new VariableData("s", _publicMav, string, true, _lvtc._bob._data);
 446  1 _ta._vars.add(stringVar);
 447  1 ComplexNameReference varRef2 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")), new Word(SourceInfo.NONE, "myVar"));
 448  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_lvtc));
 449  1 assertEquals("Should still just be 1 error", 1, _lvtc._bob.errors.size());
 450   
 451    //if it has been initialized and is final, give an error
 452  1 myVar.setMav(_finalPublicMav);
 453  1 myVar.gotValue();
 454  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_lvtc));
 455  1 assertEquals("Should be 2 errors", 2, _lvtc._bob.errors.size());
 456  1 assertEquals("Error message should be correct", "You cannot assign a value to myVar because it is immutable and has already been given a value", _lvtc._bob.errors.getLast().getFirst());
 457  1 myVar.setMav(_publicMav);
 458  1 myVar.lostValue();
 459   
 460    //if it is a variable of the super class, you should still be able to see it. Check this case.
 461  1 string.setVars(new LinkedList<VariableData>());
 462  1 string.setSuperClass(_sd2);
 463  1 _sd2.addVar(myVar);
 464  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_lvtc));
 465  1 assertEquals("Should still be 2 errors", 2, _lvtc._bob.errors.size());
 466   
 467    //here's a complex multiple variable reference case:
 468  1 VariableData vd1 = new VariableData("Mojo", _publicMav, SymbolData.INT_TYPE, true, _sd1);
 469  1 VariableData vd2 = new VariableData("Santa's Little Helper", _publicMav, _sd1, true, _sd2);
 470  1 VariableData vd3 = new VariableData("Snowball1", _publicMav, _sd2, true, _sd3);
 471  1 _sd3.addVar(vd3);
 472  1 _sd2.addVar(vd2);
 473  1 _sd1.addVar(vd1);
 474   
 475  1 ComplexNameReference varRef3 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Snowball1")),
 476    new Word(SourceInfo.NONE, "Santa's Little Helper"));
 477  1 ComplexNameReference varRef4 = new ComplexNameReference(SourceInfo.NONE, varRef3, new Word(SourceInfo.NONE, "Mojo"));
 478   
 479  1 Data oldData = _lvtc._bob._data;
 480  1 _lvtc._bob._data = _sd3;
 481  1 _lvtc._bob._vars.add(vd3);
 482   
 483  1 TypeData result = varRef4.visit(_lvtc);
 484  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), result);
 485  1 assertEquals("Should still be 2 errors", 2, _lvtc._bob.errors.size());
 486   
 487  1 _lvtc._bob._data = oldData;
 488   
 489    // What if what we have is an inner class?
 490    /* This test case may be WRONG. '$' should not be used as a name segment delimiter in internal
 491    * symbol names. */
 492  1 SymbolData inner = new SymbolData("java.lang.String$Inner");
 493  1 inner.setPackage("java.lang");
 494  1 inner.setIsContinuation(false);
 495  1 inner.setOuterData(string);
 496  1 string.addInnerClass(inner);
 497   
 498    //if inner is not visible, throw error
 499  1 ComplexNameReference innerRef0 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")), new Word(SourceInfo.NONE, "Inner"));
 500  1 assertEquals("Should return null", null, innerRef0.visit(_lvtc));
 501  1 assertEquals("Should be 3 errors", 3, _lvtc._bob.errors.size());
 502  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());
 503   
 504  1 inner.setMav(_publicMav);
 505   
 506    //if inner is not static, give error:
 507  1 ComplexNameReference innerRef1 = new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "Inner"));
 508  1 assertEquals("Should return inner", inner, innerRef1.visit(_lvtc));
 509  1 assertEquals("Should be 4 errors", 4, _lvtc._bob.errors.size());
 510  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());
 511   
 512    //if inner is not static and outer is not static, it's okay...
 513  1 ComplexNameReference innerRef2 = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")), new Word(SourceInfo.NONE, "Inner"));
 514  1 assertEquals("Should return inner", inner, innerRef2.visit(_lvtc));
 515  1 assertEquals("Should be 5 errors", 5, _lvtc._bob.errors.size());
 516  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());
 517   
 518    //if inner is static and outer is not static, throw error
 519  1 inner.setMav(_publicStaticMav);
 520  1 assertEquals("Should return inner", inner, innerRef2.visit(_lvtc));
 521  1 assertEquals("Should be 6 errors", 6, _lvtc._bob.errors.size());
 522  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());
 523   
 524   
 525    //if the symbol could not be matched, give an error and return null
 526  1 ComplexNameReference noSense = new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "nonsense"));
 527  1 assertEquals("Should return null", null, noSense.visit(_lvtc));
 528  1 assertEquals("Should be 7 errors", 7, _lvtc._bob.errors.size());
 529  1 assertEquals("Error message should be correct", "Could not resolve nonsense from the context of java.lang.String", _lvtc._bob.errors.getLast().getFirst());
 530   
 531    //if the reference is ambiguous (matches both an interface and a class) give an error
 532  1 ComplexNameReference ambigRef = new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "cebu")), new Word(SourceInfo.NONE, "ambigThing"));
 533   
 534  1 SymbolData interfaceD = new SymbolData("interface");
 535  1 interfaceD.setIsContinuation(false);
 536  1 interfaceD.setInterface(true);
 537  1 interfaceD.setMav(_publicMav);
 538   
 539  1 SymbolData classD = new SymbolData("superClass");
 540  1 classD.setIsContinuation(false);
 541  1 classD.setMav(_publicMav);
 542   
 543  1 SymbolData ambigThingI = new SymbolData("ambigThing");
 544  1 ambigThingI.setIsContinuation(false);
 545  1 ambigThingI.setInterface(true);
 546  1 interfaceD.addInnerInterface(ambigThingI);
 547  1 ambigThingI.setOuterData(interfaceD);
 548  1 ambigThingI.setMav(_publicStaticMav);
 549   
 550  1 SymbolData ambigThingC = new SymbolData("ambigThing");
 551  1 ambigThingC.setIsContinuation(false);
 552  1 classD.addInnerClass(ambigThingC);
 553  1 ambigThingC.setOuterData(classD);
 554  1 ambigThingC.setMav(_publicStaticMav);
 555   
 556  1 _sd6.addInterface(interfaceD);
 557  1 _sd6.setSuperClass(classD);
 558   
 559  1 _lvtc._bob.symbolTable.put("cebu", _sd6);
 560  1 _sd6.setMav(_publicMav);
 561  1 _sd6.setIsContinuation(false);
 562   
 563  1 assertEquals("Should return null", null, ambigRef.visit(_lvtc));
 564  1 assertEquals("Should be 8 errors", 8, _lvtc._bob.errors.size());
 565  1 assertEquals("Error message should be correct", "Ambiguous reference to class or interface ambigThing", _lvtc._bob.errors.getLast().getFirst());
 566   
 567   
 568    }
 569   
 570  1 public void testForArrayAccess() {
 571  1 ArrayData intArray =
 572    new ArrayData(SymbolData.INT_TYPE,
 573    new LanguageLevelVisitor(_lvtc._bob._file,
 574    _lvtc._bob._package,
 575    null, // enclosingClassName for top level traversal
 576    _lvtc._bob._importedFiles,
 577    _lvtc._bob._importedPackages,
 578    new HashSet<String>(),
 579    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 580    new LinkedList<Command>()),
 581    SourceInfo.NONE);
 582  1 VariableData variable1 = new VariableData("variable1", _publicMav, intArray, true, _ta._data);
 583  1 _ta._vars.add(variable1);
 584   
 585  1 VariableData intVar = new VariableData("intVar", _publicMav, SymbolData.INT_TYPE, true, _ta._data);
 586  1 _ta._vars.add(intVar);
 587   
 588  1 MethodData makeArray = new MethodData("makeArray", _privateMav, new TypeParameter[0], intArray, new VariableData[0], new String[0], _ta._data.getSymbolData(), new NullLiteral(SourceInfo.NONE));
 589  1 _ta._data.getSymbolData().addMethod(makeArray);
 590   
 591    //first, a simple index into an int[]
 592   
 593  1 ArrayAccess a1 = new ArrayAccess(SourceInfo.NONE,
 594    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1")),
 595    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "intVar")));
 596   
 597  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), a1.visit(_lvtc));
 598  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 599   
 600   
 601    //make sure that an arbitrary expression can occur in the index
 602   
 603  1 ArrayAccess a2 = new ArrayAccess(SourceInfo.NONE,
 604    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1")),
 605    new PlusExpression(SourceInfo.NONE,
 606    new IntegerLiteral(SourceInfo.NONE, 12),
 607    new IntegerLiteral(SourceInfo.NONE, 22)));
 608   
 609  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), a2.visit(_lvtc));
 610  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 611   
 612    //make sure that an arbitrary expression can occur in the array
 613   
 614  1 ArrayAccess a3 = new ArrayAccess(SourceInfo.NONE,
 615    new SimpleMethodInvocation(SourceInfo.NONE,
 616    new Word(SourceInfo.NONE, "makeArray"),
 617    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0])),
 618    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "intVar")));
 619  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), a3.visit(_lvtc));
 620  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 621    }
 622   
 623  1 public void testForParenthesized() {
 624   
 625  1 VariableData x = new VariableData("x", _publicMav, SymbolData.INT_TYPE, false, _ta._data);
 626  1 _ta._vars.add(x);
 627   
 628    // make sure (((x))) is okay
 629  1 Parenthesized p1 = new Parenthesized(SourceInfo.NONE,
 630    new Parenthesized(SourceInfo.NONE,
 631    new Parenthesized(SourceInfo.NONE,
 632    new SimpleNameReference(SourceInfo.NONE,
 633    new Word(SourceInfo.NONE, "x")))));
 634   
 635  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(), p1.visit(_lvtc));
 636  1 assertEquals("Should be 0 errors", 0, _lvtc._bob.errors.size());
 637   
 638    // make sure ((1)) breaks
 639  1 Parenthesized p2 = new Parenthesized(SourceInfo.NONE,
 640    new Parenthesized(SourceInfo.NONE,
 641    new IntegerLiteral(SourceInfo.NONE, 1)));
 642  1 assertEquals("should return null", null, p2.visit(_lvtc));
 643  1 assertEquals("Should be 1 error", 1, _lvtc._bob.errors.size());
 644  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",
 645    _lvtc._bob.errors.getLast().getFirst());
 646   
 647    }
 648    //methods of TestAssignable are implicitly tested above.
 649    }
 650    }