Clover coverage report - Java Language Levels Test Coverage (javalanglevels-20120305-r5436)
Coverage timestamp: Sun Mar 4 2012 22:02:46 CST
file stats: LOC: 4,925   Methods: 138
NCLOC: 3,405   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
ExpressionTypeChecker.java 75% 93.9% 89.1% 91%
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 edu.rice.cs.javalanglevels.util.Utilities;
 42    import java.util.*;
 43    import java.io.File;
 44    import edu.rice.cs.plt.reflect.JavaVersion;
 45    import edu.rice.cs.plt.iter.*;
 46   
 47    import junit.framework.TestCase;
 48   
 49    /** This is a TypeChecker for all Expressions used in the students files. It is used with every LanguageLevel. */
 50    public class ExpressionTypeChecker extends SpecialTypeChecker {
 51   
 52    public static final JavaVersion JAVA_VERSION = LanguageLevelConverter.OPT.javaVersion();
 53    public static final NullLiteral NULL_LITERAL = new NullLiteral(SourceInfo.NONE);
 54   
 55    /** Simply pass the necessary information on to superclass constructor.
 56    * @param data The data that represents the context. TODO: What classes can it be?
 57    * @param file The file that corresponds to the source file
 58    * @param packageName The string representing the package name
 59    * @param importedFiles The list of file names that have been specifically imported
 60    * @param importedPackages The list of package names that have been specifically imported
 61    * @param vars The list of fields that have been assigned up to the point where SpecialTypeChecker is called.
 62    * @param thrown The list of exceptions that the context is declared to throw
 63    */
 64  651 public ExpressionTypeChecker(Data data, File file, String packageName, LinkedList<String> importedFiles,
 65    LinkedList<String> importedPackages, LinkedList<VariableData> vars,
 66    LinkedList<Pair<SymbolData, JExpression>> thrown) {
 67  651 super(data, file, packageName, importedFiles, importedPackages, vars, thrown);
 68  0 if (vars == null) throw new RuntimeException("vars == null in new ExpressionTypeChecker operation");
 69    }
 70   
 71   
 72    /** Visit the lhs of this assignment with LValueTypeChecker, which does extra checking. Visit the rhs of this
 73    * assignment with the regular expression type checker, since anything normal expression can appear on the right.
 74    * @param that The SimpleAssignmentExpression to type check
 75    * @return The result of the assignment.
 76    */
 77  59 public TypeData forSimpleAssignmentExpression(SimpleAssignmentExpression that) {
 78  59 TypeData valueRes = that.getValue().visit(this);
 79  59 TypeData nameRes = that.getName().visit(new LValueTypeChecker(this));
 80  59 return forSimpleAssignmentExpressionOnly(that, nameRes, valueRes);
 81    }
 82   
 83    /** A SimpleAssignmentExpression is okay if both lhs and rhs are instances, and rhs is assignable to lhs. Give an
 84    * error if these constraints are not met. Return an instance of the lhs or null if the left or right could not be resolved.
 85    * @param that The SimpleAssignmentExpression being typechecked
 86    * @param nameRes The TypeData representing the lhs of the assignment
 87    * @param valueRes The TypeData representing the rhs of the assignment
 88    */
 89  67 public TypeData forSimpleAssignmentExpressionOnly(SimpleAssignmentExpression that, TypeData nameRes,
 90    TypeData valueRes) {
 91  2 if (nameRes == null || valueRes == null) {return null;}
 92   
 93    //make sure that both lhs and rhs could be resolved (not PackageDatas)
 94  65 if (!assertFound(nameRes, that) || !assertFound(valueRes, that)) {
 95  4 return null;
 96    }
 97   
 98    // make sure both are instance datas
 99  61 if (assertInstanceType(nameRes, "You cannot assign a value to the type " + nameRes.getName(), that) &&
 100    assertInstanceType(valueRes, "You cannot use the type name " + valueRes.getName() +
 101    " on the right hand side of an assignment", that)) {
 102   
 103    // make sure the rhs can be assigned to the lhs
 104  57 if (! valueRes.getSymbolData().isAssignableTo(nameRes.getSymbolData(), JAVA_VERSION)) {
 105  1 _addError("You cannot assign something of type " + valueRes.getName() + " to something of type " +
 106    nameRes.getName(), that);
 107    }
 108    }
 109  61 return nameRes.getInstanceData();
 110    }
 111   
 112    /** Visit the lhs of this assignment with LValueWithValueTypeChecker, which does extra checking. Visit the rhs of
 113    * this assignment with regular expression type checker, since anything regular expression can appear on the right.
 114    * @param that The PlusAssignmentExpression to type check
 115    * @return The result of the assignment.
 116    */
 117  12 public TypeData forPlusAssignmentExpression(PlusAssignmentExpression that) {
 118  12 TypeData valueRes = that.getValue().visit(this);
 119  12 TypeData nameRes = that.getName().visit(new LValueWithValueTypeChecker(this));
 120   
 121  12 return forPlusAssignmentExpressionOnly(that, nameRes, valueRes);
 122    }
 123   
 124    /** A PlusAssignmentExpression is okay if the lhs and rhs are both instances. If the lhs is a string, the rhs can
 125    * be anything. If the rhs is a string, the lhs had better be a string too. If neither of them is a string, they
 126    * should both be numbers, and the rhs should be assignable to the lhs.
 127    * @param that The PlusAssignmentExpression we are typechecking
 128    * @param nameRes The TypeData representing the lhs
 129    * @param valueRes The TypeData representing the rhs
 130    * @return An instance of the result of the lhs, or null if either the right or the left could not be resolved.
 131    */
 132  24 public TypeData forPlusAssignmentExpressionOnly(PlusAssignmentExpression that, TypeData nameRes,
 133    TypeData valueRes) {
 134  2 if (nameRes == null || valueRes == null) {return null;}
 135   
 136    //make sure that both lhs and rhs could be resolved (not PackageDatas)
 137  22 if (! assertFound(nameRes, that) || !assertFound(valueRes, that)) {
 138  2 return null;
 139    }
 140   
 141    // need to see if rhs is a String.
 142  20 SymbolData string = getSymbolData("java.lang.String", that, false, false);
 143   
 144  20 if (nameRes.getSymbolData().isAssignableTo(string, JAVA_VERSION)) {
 145    //the rhs is a String, so just make sure they are both instance types.
 146  6 assertInstanceType(nameRes, "The arguments to a Plus Assignment Operator (+=) must both be instances, " +
 147    "but you have specified a type name", that);
 148  6 assertInstanceType(valueRes, "The arguments to a Plus Assignment Operator (+=) must both be instances, " +
 149    "but you have specified a type name", that);
 150  6 return string.getInstanceData();
 151    }
 152   
 153    else { // neither is a string, so they must both be numbers
 154  14 if (!nameRes.getSymbolData().isNumberType(JAVA_VERSION) ||
 155    !valueRes.getSymbolData().isNumberType(JAVA_VERSION)) {
 156  3 _addError("The arguments to the Plus Assignment Operator (+=) must either include an instance of a String " +
 157    "or both be numbers. You have specified arguments of type " + nameRes.getName() + " and " +
 158    valueRes.getName(), that);
 159  3 return string.getInstanceData(); // return String by default
 160    }
 161   
 162  11 else if (! valueRes.getSymbolData().isAssignableTo(nameRes.getSymbolData(),
 163    JAVA_VERSION)) {
 164  1 _addError("You cannot increment something of type " + nameRes.getName() + " with something of type " +
 165    valueRes.getName(), that);
 166    }
 167   
 168    else {
 169  10 assertInstanceType(nameRes, "The arguments to the Plus Assignment Operator (+=) must both be instances, " +
 170    "but you have specified a type name", that);
 171  10 assertInstanceType(valueRes, "The arguments to the Plus Assignment Operator (+=) must both be instances, " +
 172    "but you have specified a type name", that);
 173    }
 174   
 175  11 return nameRes.getInstanceData();
 176    }
 177    }
 178   
 179    /** Visit the lhs of this assignment with the LValueWithValueTypeChecker, which does extra checking for the lhs,
 180    * because it needs to be able to be assigned to and already have a value. Visit the rhs of this assignment
 181    * with the regular expression type checker, since any regular expression can appear on the right.
 182    * @param that The NumericAssignmentExpression to type check
 183    * @return The result of the assignment.
 184    */
 185  5 public TypeData forNumericAssignmentExpression(NumericAssignmentExpression that) {
 186  5 TypeData valueRes = that.getValue().visit(this);
 187  5 TypeData nameRes = that.getName().visit(new LValueWithValueTypeChecker(this));
 188   
 189  5 return forNumericAssignmentExpressionOnly(that, nameRes, valueRes);
 190    }
 191   
 192    /** Delegate to method for super class. */
 193  3 public TypeData forMinusAssignmentExpression(MinusAssignmentExpression that) {
 194  3 return forNumericAssignmentExpression(that);
 195    }
 196   
 197    /** Delegate to method for super class. */
 198  0 public TypeData forMultiplyAssignmentExpression(MultiplyAssignmentExpression that) {
 199  0 return forNumericAssignmentExpression(that);
 200    }
 201   
 202    /** Delegate to method for super class. */
 203  0 public TypeData forDivideAssignmentExpression(DivideAssignmentExpression that) {
 204  0 return forNumericAssignmentExpression(that);
 205    }
 206   
 207    /** Delegate to method for super class. */
 208  2 public TypeData forModAssignmentExpression(ModAssignmentExpression that) {
 209  2 return forNumericAssignmentExpression(that);
 210    }
 211   
 212    /** A NumericAssignmentExpression is okay if both the lhs and the rhs are instances, both are numbers, and the rhs
 213    * is assignable to the lhs. Return the lhs, or null
 214    * @param that The SimpleAssignmentExpression being typechecked
 215    * @param nameRes The TypeData representing the lhs of the assignment
 216    * @param valueRes The TypeData representing the rhs of the assignment
 217    * @return An instance of the lhs, or null if the lhs or rhs could not be resolved.
 218    */
 219  16 public TypeData forNumericAssignmentExpressionOnly(NumericAssignmentExpression that, TypeData nameRes,
 220    TypeData valueRes) {
 221  2 if (nameRes == null || valueRes == null) {return null;}
 222   
 223    //make sure that both lhs and rhs could be resolved (not PackageDatas)
 224  14 if (!assertFound(nameRes, that) || !assertFound(valueRes, that)) {
 225  2 return null;
 226    }
 227   
 228    //make sure both are instance datas
 229  12 if (assertInstanceType(nameRes, "You cannot use a numeric assignment (-=, %=, *=, /=) on the type " +
 230    nameRes.getName(), that) &&
 231    assertInstanceType(valueRes, "You cannot use the type name " + valueRes.getName() +
 232    " on the left hand side of a numeric assignment (-=, %=, *=, /=)", that)) {
 233   
 234  10 boolean error = false;
 235    //make sure that both lhs and rhs are number types:
 236  10 if (!nameRes.getSymbolData().isNumberType(JAVA_VERSION)) {
 237  1 _addError("The left side of this expression is not a number. " +
 238    "Therefore, you cannot apply a numeric assignment (-=, %=, *=, /=) to it", that);
 239  1 error=true;
 240    }
 241  10 if (!valueRes.getSymbolData().isNumberType(JAVA_VERSION)) {
 242  1 _addError("The right side of this expression is not a number. " +
 243    "Therefore, you cannot apply a numeric assignment (-=, %=, *=, /=) to it", that);
 244  1 error = true;
 245    }
 246   
 247    // Make sure the lhs is parent type of rhs NOTE: technically this is allowable in full java but inconsistent
 248    // with the fact that you cannot say int i = 0; i = i + 4.2; To avoid student confusion, we will not allow it.
 249  10 if (!error && !valueRes.getSymbolData().isAssignableTo(nameRes.getSymbolData(),
 250    JAVA_VERSION)) {
 251  1 _addError("You cannot use a numeric assignment (-=, %=, *=, /=) on something of type " + nameRes.getName() +
 252    " with something of type " + valueRes.getName(), that);
 253    }
 254    }
 255  12 return nameRes.getInstanceData();
 256    }
 257   
 258    /** Not currently supported. */
 259  1 public TypeData forShiftAssignmentExpressionOnly(ShiftAssignmentExpression that, TypeData nameRes,
 260    TypeData valueRes) {
 261  1 throw new RuntimeException ("Internal Program Error: Shift assignment operators are not supported. " +
 262    "This should have been caught before the TypeChecker. Please report this bug.");
 263    }
 264   
 265    /** Not currently supported. */
 266  1 public TypeData forBitwiseAssignmentExpressionOnly(BitwiseAssignmentExpression that, TypeData nameRes, TypeData valueRes) {
 267  1 throw new RuntimeException ("Internal Program Error: Bitwise assignment operators are not supported. " +
 268    "This should have been caught before the TypeChecker. Please report this bug.");
 269    }
 270   
 271    /** Checks if this BooleanExpression is well-formed, i.e., that left and right arguments are well-formed boolean
 272    * expressions. Throws an appropriate error if ill-formed. Always returns the boolean instance type.
 273    * @param that The BooleanExpression being checked
 274    * @param left_result The result from visiting the left side of the BooleanExpression
 275    * @param right_result The result from visiting the right side of the BooleanExpression
 276    * @return The boolean instance type
 277    */
 278  5 public TypeData forBooleanExpressionOnly(BooleanExpression that, TypeData left_result, TypeData right_result) {
 279  0 if (left_result == null || right_result == null) return null;
 280   
 281    // Make sure that both lhs and rhs could be resolved (not PackageDatas)
 282  0 if (! assertFound(left_result, that) || ! assertFound(right_result, that)) return null;
 283   
 284  5 if (assertInstanceType(left_result, "The left side of this expression is a type, not an instance", that) &&
 285    !left_result.getSymbolData().isAssignableTo(SymbolData.BOOLEAN_TYPE, JAVA_VERSION)) {
 286   
 287  1 _addError("The left side of this expression is not a boolean value. " +
 288    "Therefore, you cannot apply a Boolean Operator (&&, ||) to it", that);
 289    }
 290   
 291  5 if (assertInstanceType(right_result, "The right side of this expression is a type, not an instance", that) &&
 292    ! right_result.getSymbolData().isAssignableTo(SymbolData.BOOLEAN_TYPE, JAVA_VERSION)) {
 293   
 294  1 _addError("The right side of this expression is not a boolean value. " +
 295    "Therefore, you cannot apply a Boolean Operator (&&, ||) to it", that);
 296    }
 297   
 298   
 299  5 return SymbolData.BOOLEAN_TYPE.getInstanceData();
 300    }
 301   
 302    /** Not currently supported. */
 303  1 public TypeData forBitwiseBinaryExpressionOnly(BitwiseBinaryExpression that, TypeData left_result,
 304    TypeData right_result) {
 305  1 throw new RuntimeException ("Internal Program Error: Bitwise operators are not supported. " +
 306    "This should have been caught before the TypeChecker. Please report this bug.");
 307    }
 308   
 309    /** This EqualityExpression is badly formed if left_result and right_result have incompatible types. Both left
 310    * and the right should be instance datas. Throws an error if ill-formed. Returns the InstanceData corresponding
 311    * to boolean, the return type from an equality check.
 312    * @param that The EqualityExpression being checked
 313    * @param left_result The result of visiting the left side of the expression
 314    * @param right_result The result of visiting the right side of the expression
 315    * @return SymbolData.BOOLEAN_TYPE.getInstanceData()
 316    */
 317  18 public TypeData forEqualityExpressionOnly(EqualityExpression that, TypeData left_result, TypeData right_result) {
 318  0 if (left_result == null || right_result == null) return null;
 319   
 320    //make sure that both lhs and rhs could be resolved (not PackageDatas)
 321  0 if (!assertFound(left_result, that) || !assertFound(right_result, that)) return null;
 322   
 323    //if either left or right are primitive, the must either be both numeric or both boolean
 324  18 SymbolData left = left_result.getSymbolData();
 325  18 SymbolData right = right_result.getSymbolData();
 326  18 if (left.isPrimitiveType() || right.isPrimitiveType()) {
 327  15 if (!((left.isNumberType(JAVA_VERSION) &&
 328    right.isNumberType(JAVA_VERSION)) ||
 329    (left.isAssignableTo(SymbolData.BOOLEAN_TYPE, JAVA_VERSION)
 330    && right.isAssignableTo(SymbolData.BOOLEAN_TYPE, JAVA_VERSION)))) {
 331  3 _addError("At least one of the arguments to this Equality Operator (==, !=) is primitive. Therefore, they " +
 332    "must either both be number types or both be boolean types. You have specified expressions with type " +
 333    left_result.getName() + " and " + right_result.getName(), that);
 334    }
 335    }
 336   
 337    //otherwise, anything goes...just check for instance types
 338   
 339  18 assertInstanceType(left_result, "The arguments to this Equality Operator(==, !=) must both be instances. " +
 340    "Instead, you have referenced a type name on the left side", that);
 341  18 assertInstanceType(right_result, "The arguments to this Equality Operator(==, !=) must both be instances. " +
 342    "Instead, you have referenced a type name on the right side", that);
 343   
 344  18 return SymbolData.BOOLEAN_TYPE.getInstanceData();
 345    }
 346   
 347    /** Verify that both the left and right of this comparison expression are number types and InstanceDatas. Give an
 348    * error if this is not the case. Return the InstanceData for boolean, since that is the result of a comparison
 349    * expression.
 350    * @param that The Comparison expression being type-checked
 351    * @param left_result The result of visiting the left side of the expression
 352    * @param right_result The result of visiting the right side of the expression
 353    * @return SymbolData.BOOLEAN_TYPE.getInstanceData()
 354    */
 355  38 public TypeData forComparisonExpressionOnly(ComparisonExpression that, TypeData left_result, TypeData right_result) {
 356  0 if (left_result == null || right_result == null) {return null;}
 357   
 358    //make sure that both lhs and rhs could be resolved (not PackageDatas)
 359  1 if (!assertFound(left_result, that) || !assertFound(right_result, that)) return null;
 360   
 361  37 if (!left_result.getSymbolData().isNumberType(JAVA_VERSION)) {
 362  1 _addError("The left side of this expression is not a number. Therefore, you cannot apply a Comparison Operator" +
 363    " (<, >; <=, >=) to it", that);
 364    }
 365    else {
 366  36 assertInstanceType(left_result, "The left side of this expression is a type, not an instance", that);
 367    }
 368   
 369  37 if (!right_result.getSymbolData().isNumberType(JAVA_VERSION)) {
 370  1 _addError("The right side of this expression is not a number. Therefore, you cannot apply a Comparison Operator" +
 371    " (<, >; <=, >=) to it", that);
 372    }
 373    else {
 374  36 assertInstanceType(right_result, "The right side of this expression is a type, not an instance", that);
 375    }
 376   
 377  37 return SymbolData.BOOLEAN_TYPE.getInstanceData();
 378    }
 379   
 380    /**
 381    * Not currently supported
 382    */
 383  1 public TypeData forShiftBinaryExpressionOnly(ShiftBinaryExpression that, TypeData left_result, TypeData right_result) {
 384  1 throw new RuntimeException ("Internal Program Error: BinaryShifts are not supported. " +
 385    "This should have been caught before the TypeChecker. Please report this bug.");
 386    }
 387   
 388   
 389    /**
 390    * A plus operator can either be used on a string and any other type of object or on two numbers. If one of the arguments
 391    * is of String type, check to make sure that both types are InstanceDatas and then return an InstanceData for String.
 392    * If neither of the arguments are a String type, verify that they are both number types and both InstanceDatas, and return
 393    * the Instance Data corresponding to their least restrictive type.
 394    * @param that The PlusExpression being type-checked.
 395    * @param left_result The result of visiting the left side of this plus expression
 396    * @param right_result The result of visiting the right side of this plus expression
 397    */
 398  44 public TypeData forPlusExpressionOnly(PlusExpression that, TypeData left_result, TypeData right_result) {
 399  0 if (left_result == null || right_result == null) {return null;}
 400   
 401    //make sure that both lhs and rhs could be resolved (not PackageDatas)
 402  44 if (!assertFound(left_result, that) || !assertFound(right_result, that)) {
 403  0 return null;
 404    }
 405   
 406  44 SymbolData string = getSymbolData("java.lang.String", that, false, false);
 407   
 408  44 if (left_result.getSymbolData().isAssignableTo(string, JAVA_VERSION) ||
 409    right_result.getSymbolData().isAssignableTo(string, JAVA_VERSION)) {
 410    //one of these is a String, so just make sure they are both instance types.
 411  14 assertInstanceType(left_result, "The arguments to the Plus Operator (+) must both be instances, " +
 412    "but you have specified a type name", that);
 413  14 assertInstanceType(right_result, "The arguments to the Plus Operator (+) must both be instances, " +
 414    "but you have specified a type name", that);
 415  14 return string.getInstanceData();
 416    }
 417   
 418    else { //neither is a string, so they must both be numbers
 419  30 if (!left_result.getSymbolData().isNumberType(JAVA_VERSION) ||
 420    !right_result.getSymbolData().isNumberType(JAVA_VERSION)) {
 421  1 _addError("The arguments to the Plus Operator (+) must either include an instance of a String or both be" +
 422    " numbers. You have specified arguments of type " + left_result.getName() + " and " +
 423    right_result.getName(), that);
 424  1 return string.getInstanceData(); //return String by default
 425    }
 426    else {
 427  29 assertInstanceType(left_result, "The arguments to the Plus Operator (+) must both be instances, but you have" +
 428    " specified a type name", that);
 429  29 assertInstanceType(right_result, "The arguments to the Plus Operator (+) must both be instances, but you have" +
 430    " specified a type name", that);
 431    }
 432   
 433  29 return _getLeastRestrictiveType(left_result.getSymbolData(), right_result.getSymbolData()).getInstanceData();
 434   
 435    }
 436    }
 437   
 438    /**
 439    * Check if this NumericBinaryExpression was okay. It is not okay if either the left or the right result are not number types
 440    * or if they are not instance datas. Throw an appropriate error if any of these is the case. Always return the least
 441    * restrictive subtype of the left and the right.
 442    * @param that The NumericBinaryExpression being checked
 443    * @param left_result The result from visiting the left side of the NumericBinaryExpression
 444    * @param right_result The result from visiting the right side of the NumericBinaryExpression
 445    * @return An InstanceData of the least restrictive type of the left and right sides.
 446    */
 447  10 public TypeData forNumericBinaryExpressionOnly(NumericBinaryExpression that, TypeData left_result, TypeData right_result) {
 448  0 if (left_result == null || right_result == null) {return null;}
 449   
 450    //make sure that both lhs and rhs could be resolved (not PackageDatas)
 451  10 if (!assertFound(left_result, that) || !assertFound(right_result, that)) {
 452  0 return null;
 453    }
 454   
 455  10 if (assertInstanceType(left_result, "The left side of this expression is a type, not an instance", that) &&
 456    !left_result.getSymbolData().isNumberType(JAVA_VERSION)) {
 457   
 458  1 _addError("The left side of this expression is not a number. Therefore, you cannot apply a Numeric Binary" +
 459    " Operator (*, /, -, %) to it", that);
 460  1 return right_result.getInstanceData();
 461    }
 462   
 463  9 if (assertInstanceType(right_result, "The right side of this expression is a type, not an instance", that) &&
 464    !right_result.getSymbolData().isNumberType(JAVA_VERSION)) {
 465   
 466  1 _addError("The right side of this expression is not a number. Therefore, you cannot apply a Numeric Binary " +
 467    "Operator (*, /, -, %) to it", that);
 468  1 return left_result.getInstanceData();
 469    }
 470   
 471   
 472  8 return _getLeastRestrictiveType(left_result.getSymbolData(), right_result.getSymbolData()).getInstanceData();
 473    }
 474   
 475    /**
 476    * This should have been caught in the first pass. Throw a RuntimeException.
 477    */
 478  1 public TypeData forNoOpExpressionOnly(NoOpExpression that, TypeData left_result, TypeData right_result) {
 479  1 throw new RuntimeException("Internal Program Error: The student is missing an operator. " +
 480    "This should have been caught before the TypeChecker. Please report this bug.");
 481    }
 482   
 483   
 484    /**
 485    * Visit the value of this increment expression with the LValueWithValueTypeChecker, since
 486    * whatever it represents should already have a value before we try to increment it.
 487    */
 488  14 public TypeData forIncrementExpression(IncrementExpression that) {
 489  14 TypeData valueRes = that.getValue().visit(new LValueWithValueTypeChecker(this));
 490  14 return forIncrementExpressionOnly(that, valueRes);
 491    }
 492   
 493   
 494    /**
 495    * For these concrete instantiations of IncrementExpression, delegate to abstract method
 496    */
 497  9 public TypeData forPositivePrefixIncrementExpression(PositivePrefixIncrementExpression that) {
 498  9 return forIncrementExpression(that);
 499    }
 500   
 501  0 public TypeData forNegativePrefixIncrementExpression(NegativePrefixIncrementExpression that) {
 502  0 return forIncrementExpression(that);
 503    }
 504   
 505  0 public TypeData forPositivePostfixIncrementExpression(PositivePostfixIncrementExpression that) {
 506  0 return forIncrementExpression(that);
 507    }
 508   
 509  5 public TypeData forNegativePostfixIncrementExpression(NegativePostfixIncrementExpression that) {
 510  5 return forIncrementExpression(that);
 511    }
 512   
 513   
 514    /** An IncrementExpression is badly formatted if the thing being incremented is a type (valueRes is not an
 515    * InstanceData) or if the value being incremented cannot be assigned to. Throw an error in either of these cases.
 516    * @param that The IncrementExpression that is being type checked.
 517    * @param valueRes The result of evaluating the argument to the increment expression.
 518    * @return The type of what is being incremented.
 519    */
 520  19 public TypeData forIncrementExpressionOnly(IncrementExpression that, TypeData valueRes) {
 521  2 if (valueRes == null) {return null;}
 522   
 523    //make sure that lhs could be resolved (not PackageData)
 524  17 if (!assertFound(valueRes, that)) {
 525  1 return null;
 526    }
 527   
 528  16 if (assertInstanceType(valueRes, "You cannot increment or decrement " + valueRes.getName() +
 529    ", because it is a class name not an instance", that)) {
 530  11 if (!valueRes.getSymbolData().isNumberType(JAVA_VERSION)) {
 531  2 _addError("You cannot increment or decrement something that is not a number type." +
 532    " You have specified something of type " + valueRes.getName(), that);
 533    }
 534    }
 535  16 return valueRes.getInstanceData();
 536    }
 537   
 538    /** A NumericUnaryExpression was well-formed if its valueRes is an instance type and if its valueRes's symbol
 539    * data is a number type (to which a double can be assigned). If this numeric unary expression was not well formed,
 540    * throw an error.
 541    * @param that The NumericUnaryExpression being evaluated
 542    * @param valueRes The result of evaluating the argument to this expression.
 543    * @return The new result of this expression.
 544    */
 545  11 public TypeData forNumericUnaryExpressionOnly(NumericUnaryExpression that, TypeData valueRes) {
 546  0 if (valueRes==null) {return null;}
 547   
 548    //make sure that lhs could be resolved (not PackageData)
 549  11 if (!assertFound(valueRes, that)) {
 550  0 return null;
 551    }
 552   
 553  11 if (assertInstanceType(valueRes, "You cannot use a numeric unary operator (+, -) with " + valueRes.getName() +
 554    ", because it is a class name, not an instance", that) &&
 555    !valueRes.getSymbolData().isNumberType(JAVA_VERSION)) {
 556   
 557  1 _addError("You cannot apply this unary operator to something of type " + valueRes.getName() +
 558    ". You can only apply it to a numeric type such as double, int, or char", that);
 559  1 return valueRes;
 560    }
 561   
 562    //call this so that chars and bytes are widened to an int.
 563  10 return _getLeastRestrictiveType(valueRes.getSymbolData(), SymbolData.INT_TYPE).getInstanceData();
 564    }
 565   
 566    /** Not Currently Supported. */
 567  1 public TypeData forBitwiseNotExpressionOnly(BitwiseNotExpression that, TypeData valueRes) {
 568  1 throw new RuntimeException("Internal Program Error: BitwiseNot is not supported. " +
 569    "It should have been caught before getting to the TypeChecker. Please report this bug.");
 570    }
 571   
 572   
 573    /** A NotExpression is illformed if its argument is not an instance type or its argument is not of type boolean. Give
 574    * an error if this is the case. Always return SymbolData.BOOLEAN_TYPE.getInstanceData() since this is the correct
 575    * type for this expression.
 576    * @param that The NotExpression being type-checked
 577    * @param valueRes The type of the argument to the NotExpression
 578    * @return SymbolData.BOOLEAN_TYPE.getInstanceData()
 579    */
 580  3 public TypeData forNotExpressionOnly(NotExpression that, TypeData valueRes) {
 581  0 if (valueRes == null) {return null;}
 582   
 583    //make sure that lhs could be resolved (not PackageData)
 584  3 if (!assertFound(valueRes, that)) {
 585  0 return null;
 586    }
 587   
 588  3 if (assertInstanceType(valueRes,
 589    "You cannot use the not (!) operator with " + valueRes.getName() +
 590    ", because it is a class name, not an instance", that) &&
 591    ! valueRes.getSymbolData().isAssignableTo(SymbolData.BOOLEAN_TYPE,
 592    JAVA_VERSION)) {
 593   
 594  1 _addError("You cannot use the not (!) operator with something of type " + valueRes.getName() +
 595    ". Instead, it should be used with an expression of boolean type", that);
 596    }
 597   
 598  3 return SymbolData.BOOLEAN_TYPE.getInstanceData(); //it should always be a boolean type.
 599   
 600    }
 601   
 602    /** Not currently supported */
 603  1 public TypeData forConditionalExpressionOnly(ConditionalExpression that, TypeData condition_result,
 604    TypeData forTrue_result, TypeData forFalse_result) {
 605  1 throw new RuntimeException ("Internal Program Error: Conditional expressions are not supported. " +
 606    "This should have been caught before the TypeChecker. Please report this bug.");
 607    }
 608   
 609    /** Checks to see if this InstanceofExpression is okay. It is not okay if typeRes is not a SymbolData,
 610    * valueRes is not an InstanceData, or if valueRes cannot be cast to typeRes. If any of these are true,
 611    * give an appropriate error message. Return an instance data corresponding to typeRes.
 612    * @param that The CastExpression being examined.
 613    * @param typeRes The type to be checked
 614    * @param valueRes The instance type of what is being checked
 615    * @return typeRes's instance data.
 616    */
 617  4 public TypeData forInstanceofExpressionOnly(InstanceofExpression that, TypeData typeRes, TypeData valueRes) {
 618  0 if (typeRes == null) return null;
 619   
 620    // Make sure that lhs could be resolved (not PackageData)
 621  0 if (! assertFound(valueRes, that) || ! assertFound(typeRes, that)) return null;
 622   
 623  4 if (typeRes.isInstanceType()) {
 624  0 _addError("You are trying to test if an expression value belongs to an instance of a type, which is not allowed."
 625    + " Perhaps you meant to check membership in the type itself, " + typeRes.getName(),
 626    that);
 627    }
 628   
 629  4 else if (assertInstanceType(valueRes, "You are trying to test if " + valueRes.getName() +
 630    " belongs to type, but it is a class or interface type, not an instance", that)
 631    && ! valueRes.getSymbolData().isCastableTo(typeRes.getSymbolData(), JAVA_VERSION)) {
 632   
 633  1 _addError("You cannot test whether an expression of type " + valueRes.getName() + " belongs to type "
 634    + typeRes.getName() + " because they are not related",
 635    that);
 636    }
 637   
 638  4 return SymbolData.BOOLEAN_TYPE.getInstanceData();
 639    }
 640   
 641    /** Checks to see if this CastExpression is okay. It is not okay if typeRes is not a SymbolData, valueRes is
 642    * not an InstanceData, or if valueRes cannot be cast to typeRes. If any of these are the case, give an
 643    * appropriate error message. Return an instance data corresponding to typeRes.
 644    * @param that The CastExpression being examined.
 645    * @param typeRes The type of the cast expression
 646    * @param valueRes The instance type of what is being cast
 647    * @return typeRes's instance data.
 648    */
 649  10 public TypeData forCastExpressionOnly(CastExpression that, TypeData typeRes, TypeData valueRes) {
 650  0 if (typeRes == null || valueRes == null) return null;
 651   
 652    //make sure that lhs could be resolved (not PackageData)
 653  0 if (! assertFound(valueRes, that) || ! assertFound(typeRes, that)) return null;
 654   
 655  10 if (typeRes.isInstanceType()) {
 656  0 _addError("You are trying to cast to an instance of a type, which is not allowed. " +
 657    "Perhaps you meant to cast to the type itself, " + typeRes.getName(), that);
 658    }
 659   
 660  10 else if (assertInstanceType(valueRes, "You are trying to cast " + valueRes.getName() +
 661    ", which is a class or interface type, not an instance", that) &&
 662    !valueRes.getSymbolData().isCastableTo(typeRes.getSymbolData(),
 663    JAVA_VERSION)) {
 664   
 665  1 _addError("You cannot cast an expression of type " + valueRes.getName() + " to type " +
 666    typeRes.getName() + " because they are not related", that);
 667    }
 668   
 669  10 return typeRes.getInstanceData();
 670    }
 671   
 672   
 673    /** Gives a Runtime Exception, because the fact that there is an EmptyExpression here should have been caught before
 674    * the TypeChecker pass.
 675    */
 676  1 public TypeData forEmptyExpressionOnly(EmptyExpression that) {
 677  1 throw new RuntimeException("Internal Program Error: EmptyExpression encountered. Student is missing something." +
 678    " Should have been caught before TypeChecker. Please report this bug.");
 679    }
 680   
 681    /** Visit the ClassInstantiation's arguments. Lookup the required constructor matching the ClassInstantiation's
 682    * argument types. Check accessibility of the constructor. In all cases, returns classToInstantiate.getInstanceData.
 683    */
 684  93 public InstanceData classInstantiationHelper(ClassInstantiation that, SymbolData classToInstantiate) {
 685  1 if (classToInstantiate == null) {return null;}
 686  92 Expression[] expr = that.getArguments().getExpressions();
 687  92 InstanceData[] args = new InstanceData[expr.length];
 688  92 for (int i = 0; i<expr.length; i++) {
 689  59 Expression e = expr[i];
 690  59 TypeData type = e.visit(this);
 691  59 if (type == null || !assertFound(type, expr[i]) ||
 692    ! assertInstanceType(type, "Cannot pass a class or interface name as a constructor argument", e)) {
 693    // by default, return an instance type of context
 694  1 return classToInstantiate.getInstanceData();
 695    }
 696  58 args[i] = type.getInstanceData();
 697    }
 698   
 699  91 MethodData md =
 700    _lookupMethod(LanguageLevelVisitor.getUnqualifiedClassName(that.getType().getName()), classToInstantiate, args,
 701    that, "No constructor found in class " + Data.dollarSignsToDots(classToInstantiate.getName()) +
 702    " with signature: ", true, _getData().getSymbolData());
 703   
 704  4 if (md == null) {return classToInstantiate.getInstanceData();}
 705   
 706    //if MethodData is declared to throw exceptions, add them to thrown list:
 707  87 String[] thrown = md.getThrown();
 708  87 for (int i = 0; i<thrown.length; i++) {
 709  2 _thrown.addLast(new Pair<SymbolData, JExpression>(getSymbolData(thrown[i], _getData(), that), that));
 710    }
 711   
 712  87 return classToInstantiate.getInstanceData();
 713    }
 714   
 715   
 716   
 717   
 718    /** Handles a simple class instantiation. If the type of the instantiation is not resolved, returns null because an
 719    * error has already been thrown. Also checks to see if the class being instantiated is non-static, is not a top
 720    * level class, and the name used has a dot in it. If so, then a non-static inner class is being referenced like
 721    * a static inner class, and an error is thrown. After performing these checks, delegates to the class Instantion
 722    * helper, which will resolve the type of the class.
 723    * @return The InstanceData corresponding to the instantiation
 724    */
 725  63 public TypeData forSimpleNamedClassInstantiation(SimpleNamedClassInstantiation that) {
 726  63 SymbolData type = getSymbolData(that.getType().getName(), _getData(), that);
 727  1 if (type == null) {return null;}
 728    // Cannot instantiate a non-static inner class from a static context (i.e. new A.B() where B is dynamic).
 729    // Here, we make sure that if B is non-static, it is not an inner class of anything.
 730  62 String name = that.getType().getName();
 731  62 int lastIndexOfDot = name.lastIndexOf('.');
 732  62 if (!type.hasModifier("static") && (type.getOuterData() != null) && lastIndexOfDot != -1) {
 733  1 String firstPart = name.substring(0, lastIndexOfDot);
 734  1 String secondPart = name.substring(lastIndexOfDot + 1, name.length()); //skip the dot itself
 735  1 _addError(Data.dollarSignsToDots(type.getName()) + " is not a static inner class, and thus cannot be " +
 736    "instantiated from this context. Perhaps you meant to use an instantiation of the form new " +
 737    firstPart + "().new " + secondPart + "()", that);
 738    }
 739  62 InstanceData result = classInstantiationHelper(that, type);
 740  62 if (result != null && result.getSymbolData().hasModifier("abstract")) {
 741  1 _addError(Data.dollarSignsToDots(type.getName()) + " is abstract and thus cannot be instantiated", that);
 742    }
 743  62 return result;
 744    }
 745   
 746    /** Handles this complex named class instantiation. First, visit the lhs and get the enclosing type. If the
 747    * enclosing type is null, or a PackageData, return null, because an error has already been thrown. Otherwise,
 748    * call the classInstantiationHelper to get a new instance of the rhs, from the context of the lhs. It is an
 749    * error if the class being instantiated is non-static, but it is called from a static context. It is an error
 750    * if the class being instantiated is static but it is being called as a.new B();
 751    * @param that The ComplexNamedClassInstantiation being created
 752    * @return An InstanceData corresponding to the instantiation
 753    */
 754  9 public TypeData forComplexNamedClassInstantiation(ComplexNamedClassInstantiation that) {
 755  9 TypeData enclosingType = that.getEnclosing().visit(this);
 756  1 if ((enclosingType == null) || ! assertFound(enclosingType, that.getEnclosing())) { return null; }
 757   
 758    else {
 759    //make sure we can see enclosingType
 760  8 checkAccess(that, enclosingType.getSymbolData().getMav(), enclosingType.getSymbolData().getName(),
 761    enclosingType.getSymbolData(), _data.getSymbolData(), "class or interface", true);
 762   
 763    // TODO: will getSymbolData correctly handle all cases here?
 764    //TODO: We still do not handle static fields on the lhs correctly. I think.
 765    //this call to getSymbolData will throw ambiguous reference error, if appropriate
 766  8 SymbolData innerClass = getSymbolData(that.getType().getName(), enclosingType.getSymbolData(), that.getType());
 767  1 if (innerClass == null) {return null;}
 768   
 769    //make sure we can see inner class
 770  7 checkAccess(that, innerClass.getMav(), innerClass.getName(), innerClass, _data.getSymbolData(),
 771    "class or interface", true);
 772  7 InstanceData result = classInstantiationHelper(that, innerClass);
 773  0 if (result == null) {return null;}
 774  7 boolean resultIsStatic = result.getSymbolData().hasModifier("static");
 775   
 776  7 if (!enclosingType.isInstanceType() && !resultIsStatic) {
 777  1 _addError ("The constructor of a non-static inner class can only be called on an instance of its" +
 778    " containing class (e.g. new " + Data.dollarSignsToDots(enclosingType.getName()) + "().new " +
 779    that.getType().getName() + "())", that);
 780    }
 781  6 else if (resultIsStatic) {
 782  1 _addError("You cannot instantiate a static inner class or interface with this syntax. Instead, try new " +
 783    Data.dollarSignsToDots(result.getName()) + "()", that);
 784    }
 785   
 786  7 if (result.getSymbolData().hasModifier("abstract")) {
 787  1 _addError(Data.dollarSignsToDots(result.getName()) + " is abstract and thus cannot be instantiated", that);
 788    }
 789  7 return result;
 790    }
 791    }
 792   
 793   
 794    /** Do the work that is shared between SimpleAnonymousClassInstantiation and ComplexAnonymousClassInstantiation.
 795    * Basically, update the anonymous inner class corresponding to the enclosing data and the superC with superC
 796    * and accessors, if necessary.
 797    * @param that The AnonymousClassInstantiation being processed.
 798    * @param superC The SymbolData corresponding to the super class of this instantiation (the type being created)
 799    */
 800  19 public SymbolData handleAnonymousClassInstantiation(AnonymousClassInstantiation that, SymbolData superC) {
 801    // SymbolData sd = _data.getNextAnonymousInnerClass();
 802    /* The preceding line changed to following because anonymous class is filed under its enclosing class not
 803    * enclosing method. */
 804  19 SymbolData sd = superC.getNextAnonymousInnerClass();
 805    // System.err.println("***** In handleACI(" + that.getType().getName() + ", " + superC + ") sd = " + sd);
 806    // System.err.println("Inner classes of " + superC + " are: " + superC.getInnerClasses());
 807  19 if (sd == null) {
 808  0 _addError("Nested anonymous classes are not supported at any language lavel", that);
 809  0 return sd;
 810    // throw new RuntimeException("Internal Program Error: Couldn't find the SymbolData for the anonymous inner class." +
 811    // " Please report this bug.");
 812    }
 813  19 if (sd.getSuperClass() == null) {
 814  2 if (superC == null) {
 815  0 throw new RuntimeException("Internal Program Error: Superclass data for " + sd + " is null." +
 816    " Please report this bug.");
 817    }
 818  2 if (superC.isInterface()) {
 819  0 sd.setSuperClass(symbolTable.get("java.lang.Object"));
 820  0 sd.addInterface(superC);
 821    }
 822  2 else { sd.setSuperClass(superC);}
 823    }
 824  19 LanguageLevelVisitor.createAccessors(sd, _file);
 825   
 826  19 return sd;
 827    }
 828   
 829    /** Resolve the type of this anonymous class. Look it up in the enclosing data, check that
 830    * it is using a valid constructor through the classInstantiationHelper and visit the body.
 831    * Make sure that all abstract methods are overwritten.
 832    * @param that The SimpleAnonymousClassInstantiation being type-checked
 833    * @return The result of type checking the class instantiation.
 834    */
 835  9 public TypeData forSimpleAnonymousClassInstantiation(SimpleAnonymousClassInstantiation that) {
 836    /* Note: _data should be the enclosing class. */
 837    // System.err.println("******** Type-checking the anonymous class " + that);
 838    // if (! (_data instanceof SymbolData) )
 839    // System.err.println("********* Type-checking following anon class blows up " + that);
 840    //
 841    // assert _data instanceof SymbolData;
 842   
 843  9 SymbolData enclosing = _data.getSymbolData(); // grabs the enclosing class if _data not already a SymbolData
 844   
 845  9 if (enclosing.isDoublyAnonymous()) {
 846  0 _addError(enclosing + "is a nested anonymous class, which is not supported at any language level", that);
 847  0 return null;
 848    }
 849    // System.err.println("***** forSACInst called for anon class in " + enclosing);
 850  9 final SymbolData superClass = getSymbolData(that.getType().getName(), enclosing, that); // resolve super class
 851    // System.err.println("**** SuperClass symbol is " + superClass);
 852    // Get this anonymous inner class's SymbolData, and finish resolving it.
 853  9 SymbolData myData = handleAnonymousClassInstantiation(that, enclosing /*.getEnclosingClass() */);
 854    // System.err.println("This anonymous class's symbol is: " + myData);
 855  0 if (myData == null) return null;
 856   
 857    // Cannot instantiate a non-static inner class from a static context (i.e. new A.B() where B is dynamic).
 858    // Here, we make sure that if B is non-static, it is not an inner class of anything.
 859  9 String name = that.getType().getName();
 860  9 int lastIndexOfDot = name.lastIndexOf('.');
 861  9 if (!superClass.hasModifier("static") && !superClass.isInterface() &&
 862    (superClass.getOuterData() != null) && lastIndexOfDot != -1) {
 863  1 String firstPart = name.substring(0, lastIndexOfDot);
 864  1 String secondPart = name.substring(lastIndexOfDot + 1, name.length());
 865  1 _addError(Data.dollarSignsToDots(superClass.getName()) +
 866    " is not a static inner class, and thus cannot be instantiated from this context." +
 867    " Perhaps you meant to use an instantiation of the form new " + Data.dollarSignsToDots(firstPart) +
 868    "().new " + Data.dollarSignsToDots(secondPart) + "()", that);
 869    }
 870   
 871   
 872    //if superClass is an interface, then the constructor that should be used is Object--i.e. no arguments
 873  9 if (superClass.isInterface()) {
 874  0 Expression[] expr = that.getArguments().getExpressions();
 875  0 if (expr.length > 0) {
 876  0 _addError("You are creating an anonymous inner class that directly implements an interface, thus you should" +
 877    " use the Object constructor which takes in no arguments. However, you have specified " +
 878    expr.length + " arguments", that);}
 879    }
 880   
 881  9 else classInstantiationHelper(that, superClass); //use super class here, since it has constructors in it
 882   
 883   
 884    //clone the variables and visit the body.
 885  9 LinkedList<VariableData> vars = cloneVariableDataList(_vars);
 886  9 vars.addAll(myData.getVars());
 887  9 final TypeData bodyRes = that.getBody().visit(new ClassBodyTypeChecker(myData, _file, _package, _importedFiles,
 888    _importedPackages, vars, _thrown));
 889   
 890   
 891  9 _checkAbstractMethods(myData, that);
 892  9 return myData.getInstanceData(); //but actually return an instance of the anonymous inner class
 893    }
 894   
 895    /** Resolve the type of this anonymous class. Look it up in enclosing data, check that it is using a valid constructor
 896    * through the classInstantiationHelper and visit the body. Make sure that all abstract methods are overwritten. The
 897    * enclosing data is found by first resolving the enclosing data. Make sure that if this is an inner class it is being
 898    * called from the appropriate static/non-static context (see ComplexNamedClassInstantiation for more details).
 899    * @param that The SimpleAnonymousClassInstantiation being type-checked
 900    * @return The result of type checking the class instantiation.
 901    */
 902  10 public TypeData forComplexAnonymousClassInstantiation(ComplexAnonymousClassInstantiation that) {
 903    /* Note: _data should be the enclosing class. */
 904    // System.err.println("******** Type-checking the anonymous class " + that);
 905    // if (! (_data instanceof SymbolData) )
 906    // System.err.println("********* Type-checking following anon class blows up " + that);
 907    //
 908    // assert _data instanceof SymbolData;
 909   
 910   
 911  10 if (_data.isDoublyAnonymous()) {
 912  0 _addError(_data + "is a nested anonymous class, which is not supported at any language level", that);
 913  0 return null;
 914    }
 915   
 916  10 SymbolData lexEnclosing = _data.getSymbolData(); // grabs the enclosing class if _data not already a SymbolData
 917   
 918  10 Expression receiver = that.getEnclosing();
 919   
 920    // Get the enclosing type as specified by the "receiver" expression.
 921  10 TypeData enclosingType = receiver.visit(this);
 922   
 923  0 if ((enclosingType == null) || ! assertFound(enclosingType, that.getEnclosing())) { return null; }
 924   
 925  10 SymbolData enclosing = enclosingType.getSymbolData();
 926   
 927    // Make sure we can see enclosing SymbolData from within lexEnclosing
 928  10 checkAccess(that, enclosing.getMav(), enclosing.getName(), enclosing, lexEnclosing, "class or interface", true);
 929   
 930  10 final SymbolData superClass = getSymbolData(that.getType().getName(), enclosing, that.getType());
 931   
 932    // Get this anonymous inner class's SymbolData; passing lexEnclosing is a hack. It almost certainly should be
 933    // enclosing, but the LLV processing contains the same error. We need to be consistent.
 934  10 SymbolData myData = handleAnonymousClassInstantiation(that, lexEnclosing); // TODO: the wrong enclosing context?
 935  0 if (myData == null) return null;
 936   
 937    // TODO: will getSymbolData correctly handle all cases here?
 938    //TODO: We still do not handle static fields on the lhs correctly. I think.
 939   
 940  10 boolean resultIsStatic;
 941   
 942  10 if (superClass.isInterface()) {
 943  0 Expression[] expr = that.getArguments().getExpressions();
 944  0 if (expr.length > 0) {
 945  0 _addError("You are creating an anonymous inner class that directly implements an interface, thus you should" +
 946    " use the Object constructor which takes in no arguments. However, you have specified " +
 947    expr.length + " arguments", that);
 948    }
 949  0 resultIsStatic = true;
 950    }
 951   
 952   
 953    else { // superClass is an interface...need to do some extra checking for static types.
 954  10 InstanceData result = classInstantiationHelper(that, superClass); //use super class here, since it has constructors in it
 955  0 if (result == null) return null;
 956   
 957  10 resultIsStatic = result.getSymbolData().hasModifier("static");
 958    }
 959   
 960  10 if (!enclosingType.isInstanceType() && !resultIsStatic) {
 961  1 _addError ("The constructor of a non-static inner class can only be called on an instance of its containing" +
 962    " class (e.g. new " + Data.dollarSignsToDots(enclosingType.getName()) + "().new " +
 963    that.getType().getName() + "())", that);
 964    }
 965   
 966  9 else if (enclosingType.isInstanceType() && resultIsStatic) {
 967  1 _addError("You cannot instantiate a static inner class or interface with this syntax. Instead, try new " +
 968    Data.dollarSignsToDots(superClass.getName()) + "()", that);
 969    }
 970   
 971    //clone the variables and visit the body.
 972  10 LinkedList<VariableData> vars = cloneVariableDataList(_vars);
 973  10 vars.addAll(myData.getVars());
 974   
 975  10 final TypeData bodyRes = that.getBody().visit(new ClassBodyTypeChecker(myData, _file, _package, _importedFiles,
 976    _importedPackages, vars, _thrown));
 977   
 978    //make sure all abstract super class methods are overwritten
 979  10 _checkAbstractMethods(myData, that);
 980   
 981  10 return myData.getInstanceData(); //actually return an intance of the anonymous inner class
 982    }
 983   
 984   
 985    /** SimpleThisConstructorInvocations are not allowed outside of the first line of a constructor. */
 986  1 public TypeData forSimpleThisConstructorInvocation(SimpleThisConstructorInvocation that) {
 987  1 _addError("This constructor invocations are only allowed as the first statement of a constructor body", that);
 988  1 return null;
 989    }
 990   
 991    /** ComplexThisConstructorInvocations are not ever allowed. */
 992  1 public TypeData forComplexThisConstructorInvocation(ComplexThisConstructorInvocation that) {
 993  1 _addError("Constructor invocations of this form are never allowed", that);
 994  1 return null;
 995    }
 996   
 997    /** Try to resolve this SimpleNameReference. It is either:
 998    * 1. a field or variable reference (return the instance type of the field/variable)
 999    * 2. a class or interface name reference (return the type of the class or interface)
 1000    * 3. part of a package reference or an error (return a new package data corresponding to the reference.
 1001    * No need to call forSimpleNameReference only, since all the checking is done here.
 1002    */
 1003  292 public TypeData forSimpleNameReference(SimpleNameReference that) {
 1004  292 Word myWord = that.getName();
 1005  292 myWord.visit(this);
 1006   
 1007    // first, try to resolve this name as a field or variable reference
 1008   
 1009  292 VariableData reference = getFieldOrVariable(myWord.getText(), _data, _data.getSymbolData(), that, _vars, true, true);
 1010  292 if (reference != null) {
 1011  232 if (! reference.hasValue()) {
 1012  4 _addError("You cannot use " + reference.getName() + " because it may not have been given a value", that.getName());
 1013    }
 1014   
 1015    // if reference is non-static (and not a local variable), but context is static, give error
 1016  232 if (inStaticMethod() && ! reference.hasModifier("static") && ! reference.isLocalVariable()) {
 1017  2 _addError("Non-static variable or field " + reference.getName() + " cannot be referenced from a static context", that);
 1018    }
 1019    // if (reference.getType() == null || reference.getType().getInstanceData() == null)
 1020    // System.err.println("Expression type checking in " + _data + " blows up; AST = " + that);
 1021  232 return reference.getType().getInstanceData();
 1022    }
 1023   
 1024    //next, try to resolve this name as a class or interface reference
 1025  60 SymbolData classR = findClassReference(null, myWord.getText(), that);
 1026  60 if (classR != null && classR != SymbolData.AMBIGUOUS_REFERENCE) {
 1027    //Only return the symbolData if it is accessible--otherwise, return PackageData
 1028  31 if (checkAccess(that, classR.getMav(), classR.getName(), classR, _data.getSymbolData(),
 1029    "class or interface", false)) {
 1030  30 return classR;
 1031    }
 1032    }
 1033  1 if (classR == SymbolData.AMBIGUOUS_REFERENCE) {return null;}
 1034   
 1035  29 PackageData packageD = new PackageData(myWord.getText());
 1036  29 return packageD;
 1037    }
 1038   
 1039   
 1040    /** To resolve this ComplexNameReference, first visit the lhs with an instance of this visitor in order to get its
 1041    * type. Then, try to figure out how the name reference on the right fits with the type on the left.
 1042    * 1. If the lhs is a package data, then either the rhs is a class reference, or the whole thing is another
 1043    * PackageData.
 1044    * 2. If the rhs is a variable or field visible from the context of the lhs, it must be static if the lhs is a
 1045    * SymbolData, and regardless, it must have a value to be referenced here.
 1046    * 3. If the rhs references an inner class of the lhs, the lhs must be a SymbolData if the rhs is a static inner
 1047    * class, and the rhs must be static if the lhs is a SymbolData.
 1048    * 4. Otherwise, give an error because we couldn't resolve the symbol.
 1049    */
 1050  73 public TypeData forComplexNameReference(ComplexNameReference that) {
 1051  73 TypeData lhs = that.getEnclosing().visit(this);
 1052  0 if (lhs == null) return null; // defensive code based on NullPointerException that MAY be due to lhs == null
 1053   
 1054  73 Word myWord = that.getName();
 1055   
 1056    //if lhs is a package data, either we found a class reference or this piece is still part of the package
 1057  73 if (lhs instanceof PackageData) {
 1058  37 SymbolData classRef = findClassReference(lhs, myWord.getText(), that);
 1059  17 if (classRef != null) { return classRef; }
 1060  20 return new PackageData((PackageData) lhs, myWord.getText());
 1061    }
 1062  0 if (_data == null) return null; // intermittent NullPointerException in next line; lhs == null or _data == null
 1063  36 checkAccess(that, lhs.getSymbolData().getMav(), lhs.getSymbolData().getName(), lhs.getSymbolData(),
 1064    _data.getSymbolData(), "class or interface", true);
 1065   
 1066    // if the word is a variable reference, make sure it can be seen from this context
 1067  36 VariableData reference = getFieldOrVariable(myWord.getText(), lhs.getSymbolData(), _data.getSymbolData(), that);
 1068  36 if (reference != null) {
 1069  29 if (lhs instanceof SymbolData) {
 1070    //does this reference a field? if so, it must be static
 1071  13 if (! reference.hasModifier("static")) {
 1072  1 _addError("Non-static variable " + reference.getName() + " cannot be accessed from the static context " +
 1073    Data.dollarSignsToDots(lhs.getName()) + ". Perhaps you meant to instantiate an instance of " +
 1074    Data.dollarSignsToDots(lhs.getName()), that);
 1075  1 return reference.getType().getInstanceData();
 1076    }
 1077    }
 1078   
 1079    //make sure it already had a value
 1080  28 if (!reference.hasValue()) {
 1081  4 _addError("You cannot use " + reference.getName() + " here, because it may not have been given a value",
 1082    that.getName());
 1083    }
 1084   
 1085  28 return reference.getType().getInstanceData();
 1086    }
 1087   
 1088    //does this reference an inner class? if so, it must be static
 1089  7 SymbolData sd = getSymbolData(true, myWord.getText(), lhs.getSymbolData(), that, false); // may report error below
 1090  7 if (sd != null && sd != SymbolData.AMBIGUOUS_REFERENCE) {
 1091  5 if (!checkAccess(that, sd.getMav(), sd.getName(), sd, _data.getSymbolData(), "class or interface")) {
 1092  1 return null;
 1093    }
 1094  4 if (!sd.hasModifier("static")) {
 1095  2 _addError("Non-static inner class " + Data.dollarSignsToDots(sd.getName()) +
 1096    " cannot be accessed from this context. Perhaps you meant to instantiate it", that);
 1097    }
 1098   
 1099    //you cannot reference static inner classes from the context of an instantiation of their outer class
 1100  2 else if (lhs instanceof InstanceData) {
 1101  1 _addError("You cannot reference the static inner class " + Data.dollarSignsToDots(sd.getName()) +
 1102    " from an instance of " + Data.dollarSignsToDots(lhs.getName()) + ". Perhaps you meant to say "
 1103    + Data.dollarSignsToDots(sd.getName()), that);
 1104    }
 1105  4 return sd;
 1106    }
 1107   
 1108  2 if (sd != SymbolData.AMBIGUOUS_REFERENCE) {
 1109  1 _addError("Could not resolve " + myWord.getText() + " from the context of " + Data.dollarSignsToDots(lhs.getName()),
 1110    that);
 1111    }
 1112  2 return null;
 1113    }
 1114   
 1115   
 1116    /**
 1117    * Make sure we are in a non-static context.
 1118    * @return an instance data corresponding to the enclosing class of this context.
 1119    */
 1120  7 public TypeData forSimpleThisReference(SimpleThisReference that) {
 1121  7 if (inStaticMethod()) {
 1122  1 _addError("'this' cannot be referenced from within a static method", that);
 1123    }
 1124  7 return _getData().getSymbolData().getInstanceData();
 1125    }
 1126   
 1127    /**
 1128    * Check to make sure that the enclosing result could be resolved and that it a type name.
 1129    * Insure that an enclosing instance of that name exists in the current (non-static) context.
 1130    * Return the instance data corresponding to its "this" field.
 1131    * @param that The ComplexThisReference we are type-checking
 1132    * @param enclosing_result The TypeData whose this field is being referenced
 1133    * @return An InstanceData corresponding to the enclosing_result.
 1134    */
 1135  7 public TypeData forComplexThisReferenceOnly(ComplexThisReference that, TypeData enclosing_result) {
 1136    //make sure that enclosingResult is not null and not a PackageData. If it is, return null
 1137  2 if ((enclosing_result == null) || ! assertFound(enclosing_result, that.getEnclosing())) { return null; }
 1138   
 1139  5 if (inStaticMethod()) {
 1140  1 _addError("'this' cannot be referenced from within a static method", that);
 1141    }
 1142   
 1143  5 if (enclosing_result.isInstanceType()) {
 1144  1 _addError("'this' can only be referenced from a type name, but you have specified an instance of that type.", that);
 1145    }
 1146   
 1147  5 SymbolData myData = _getData().getSymbolData();
 1148  5 if (!myData.isInnerClassOf(enclosing_result.getSymbolData(), true)) {
 1149    // Test whether myData is an inner class of enclosing_result at all. Somewhat inefficient, but only happens when errors occur.
 1150  2 if (myData.isInnerClassOf(enclosing_result.getSymbolData(), false)) {
 1151  1 _addError("You cannot reference " + enclosing_result.getName() + ".this from here, because " + myData.getName() +
 1152    " or one of its enclosing classes " +
 1153    "is static. Thus, an enclosing instance of " + enclosing_result.getName() + " does not exist", that);
 1154    }
 1155    else {
 1156  1 _addError("You cannot reference " + enclosing_result.getName() + ".this from here, because " + enclosing_result.getName() +
 1157    " is not an outer class of " + myData.getName(), that);
 1158    }
 1159    }
 1160   
 1161  5 return enclosing_result.getInstanceData();
 1162    }
 1163   
 1164    /** All classes should have a super class, which is java.lang.Object by default. Looks up this class's super class.
 1165    * If it is null, generates an error (this should never happen). Otherwise, returns the instance data corresponding
 1166    * to the super class.
 1167    * @param that The SimpleSuperReference we are resolving.
 1168    * @return InstanceData corresponding to the super class
 1169    */
 1170  3 public TypeData forSimpleSuperReference(SimpleSuperReference that) {
 1171  3 if (inStaticMethod()) {
 1172  1 _addError("'super' cannot be referenced from within a static method", that);
 1173    }
 1174  3 SymbolData superClass = _getData().getSymbolData().getSuperClass();
 1175  3 if (superClass == null) { //this should never happen, because all classes should have a super class
 1176  0 _addError("The class " + _getData().getSymbolData().getName() + " does not have a super class", that);
 1177  0 return null;
 1178    }
 1179  3 return superClass.getInstanceData();
 1180    }
 1181   
 1182    /** Makes sure that the enclosing result is not null--if it is, return null. Insure that an
 1183    * enclosing instance of that name exists in the current (non-static) context. Give an error if the enclosing_result
 1184    * is not an instance type. Get its super class, and return an instance data corresponding to it.
 1185    * @param that The ComplexSuperReference being typechecked
 1186    * @param enclosing_result The type of the left hand side of this reference.
 1187    * @return An InstanceData corresponding to the super class of enclosing_result.
 1188    */
 1189  7 public TypeData forComplexSuperReferenceOnly(ComplexSuperReference that, TypeData enclosing_result) {
 1190    //make sure that enclosing_result is not null and not a PackageData. If it is, return null
 1191  2 if ((enclosing_result == null) || ! assertFound(enclosing_result, that.getEnclosing())) { return null; }
 1192   
 1193  5 if (inStaticMethod()) {
 1194  1 _addError("'super' cannot be referenced from within a static method", that);
 1195    }
 1196  5 if (enclosing_result.isInstanceType()) {
 1197  1 _addError("'super' can only be referenced from a type name, but you have specified an instance of that type.", that);
 1198    }
 1199   
 1200  5 SymbolData myData = _getData().getSymbolData();
 1201  5 if (!myData.isInnerClassOf(enclosing_result.getSymbolData(), true)) {
 1202    // Test whether myData is an inner class of enclosing_result. Inefficient, but only happens when errors occur.
 1203  2 if (myData.isInnerClassOf(enclosing_result.getSymbolData(), false)) {
 1204  1 _addError("You cannot reference " + enclosing_result.getName() + ".super from here, because " + myData.getName() +
 1205    " or one of its enclosing classes " +
 1206    "is static. Thus, an enclosing instance of " + enclosing_result.getName() + " does not exist", that);
 1207    }
 1208    else {
 1209  1 _addError("You cannot reference " + enclosing_result.getName() + ".super from here, because " +
 1210    enclosing_result.getName() + " is not an outer class of " + myData.getName(), that);
 1211    }
 1212    }
 1213   
 1214  5 SymbolData superClass = enclosing_result.getSymbolData().getSuperClass();
 1215  5 if (superClass == null) { //this should never happen, because all classes should have a super class
 1216  0 _addError("The class " + enclosing_result.getName() + " does not have a super class", that);
 1217  0 return null;
 1218    }
 1219   
 1220  5 return superClass.getInstanceData();
 1221    }
 1222   
 1223   
 1224   
 1225   
 1226    /** Make sure the lhs is actually an array type and that the index is an int. */
 1227  17 public TypeData forArrayAccessOnly(ArrayAccess that, TypeData lhs, TypeData index) {
 1228    //if either lhs or index is null then an error has already been caught--return null
 1229  2 if (lhs == null || index == null) {return null;}
 1230   
 1231    //if either lhs or index cannot be resolved, give error
 1232  15 if (!assertFound(lhs, that) || !assertFound(index, that)) {
 1233  2 return null;
 1234    }
 1235   
 1236  13 if (assertInstanceType(lhs, "You cannot access an array element of a type name", that) &&
 1237    ! (lhs.getSymbolData() instanceof ArrayData)) {
 1238  1 _addError("The variable referred to by this array access is a " + lhs.getSymbolData().getName() + ", not an array",
 1239    that);
 1240  1 return lhs.getInstanceData();
 1241    }
 1242   
 1243  12 if (assertInstanceType(index, "You have used a type name in place of an array index", that) &&
 1244    ! index.getSymbolData().isAssignableTo(SymbolData.INT_TYPE, JAVA_VERSION)) {
 1245  1 _addError("You cannot reference an array element with an index of type " + index.getSymbolData().getName() +
 1246    ". Instead, you must use an int", that);
 1247    }
 1248   
 1249  12 return ((ArrayData)lhs.getSymbolData()).getElementType().getInstanceData();
 1250    }
 1251   
 1252    //*** Primitives and Literals *******//
 1253  53 public TypeData forStringLiteralOnly(StringLiteral that) {
 1254  53 assert symbolTable.get("java.lang.String") != null;
 1255  53 return symbolTable.get("java.lang.String").getInstanceData();
 1256    }
 1257   
 1258  267 public TypeData forIntegerLiteralOnly(IntegerLiteral that) {
 1259  267 return SymbolData.INT_TYPE.getInstanceData();//forLiteralOnly(that);
 1260    }
 1261   
 1262  1 public TypeData forLongLiteralOnly(LongLiteral that) {
 1263  1 return SymbolData.LONG_TYPE.getInstanceData();
 1264    }
 1265   
 1266  1 public TypeData forFloatLiteralOnly(FloatLiteral that) {
 1267  1 return SymbolData.FLOAT_TYPE.getInstanceData();
 1268    }
 1269   
 1270  13 public TypeData forDoubleLiteralOnly(DoubleLiteral that) {
 1271  13 return SymbolData.DOUBLE_TYPE.getInstanceData();
 1272    }
 1273   
 1274  25 public TypeData forCharLiteralOnly(CharLiteral that) {
 1275  25 return SymbolData.CHAR_TYPE.getInstanceData();
 1276    }
 1277   
 1278  25 public TypeData forBooleanLiteralOnly(BooleanLiteral that) {
 1279  25 return SymbolData.BOOLEAN_TYPE.getInstanceData();
 1280    }
 1281   
 1282  9 public TypeData forNullLiteralOnly(NullLiteral that) {
 1283  9 return SymbolData.NULL_TYPE.getInstanceData();
 1284    }
 1285   
 1286  1 public TypeData forClassLiteralOnly(ClassLiteral that) {
 1287  1 return symbolTable.get("java.lang.Class").getInstanceData();
 1288    }
 1289   
 1290   
 1291    /**
 1292    * Check a few constraints on this Parenthesized
 1293    */
 1294  11 public TypeData forParenthesizedOnly(Parenthesized that, TypeData valueRes) {
 1295  1 if (valueRes == null) {return null;}
 1296   
 1297  10 if (!assertFound(valueRes, that.getValue())) {
 1298  1 return null;
 1299    }
 1300   
 1301  9 assertInstanceType(valueRes, "This class or interface name cannot appear in parentheses", that);
 1302  9 return valueRes.getInstanceData();
 1303    }
 1304   
 1305    /** Look up the method called in the method invocation within the context of the context TypeData.
 1306    * Resolve all arguments to the method, and make sure they are instance datas.
 1307    * If an argument is a type, the method cannot be found, or the method is called from a static context but is
 1308    * not static, give appropriate error.
 1309    * If the method is declared to throw any exceptions, add them to the thrown list.
 1310    * @param that The MethodInvocation we are type checking
 1311    * @param context The TypeData that should contain the method being invoked.
 1312    */
 1313  67 public TypeData methodInvocationHelper(MethodInvocation that, TypeData context) {
 1314  67 Expression[] exprs = that.getArguments().getExpressions();
 1315  67 TypeData[] args = new TypeData[exprs.length];
 1316  67 InstanceData[] newArgs = new InstanceData[exprs.length];
 1317  67 for (int i = 0; i < exprs.length; i++) {
 1318  57 args[i] = exprs[i].visit(this);
 1319  57 if (args[i] == null) {
 1320  0 return null;
 1321    }
 1322   
 1323  0 if (! assertFound(args[i], that)) return null;
 1324  57 if (! args[i].isInstanceType()) {
 1325  1 _addError("Cannot pass a class or interface name as an argument to a method." +
 1326    " Perhaps you meant to create an instance or use " + args[i].getName() + ".class", exprs[i]);
 1327    }
 1328  57 newArgs[i]=args[i].getInstanceData();
 1329   
 1330    }
 1331   
 1332    // Pass in both sd and the current SymbolData so that lookupMethod can check
 1333    // if we have access to the method from here.
 1334  67 MethodData md = _lookupMethod(that.getName().getText(), context.getSymbolData(), newArgs, that,
 1335    "No method found in class " + context.getName() + " with signature: ",
 1336    false, _getData().getSymbolData());
 1337   
 1338  3 if (md == null) return null;
 1339   
 1340  64 if (! context.isInstanceType() && ! md.hasModifier("static")) {
 1341  3 _addError("Cannot access the non-static method " + md.getName() + " from a static context", that);
 1342    }
 1343   
 1344    // If MethodData is declared to throw exceptions, add them to thrown list:
 1345  64 String[] thrown = md.getThrown();
 1346  64 for (int i = 0; i < thrown.length; i++) {
 1347  2 _thrown.addLast(new Pair<SymbolData, JExpression>(getSymbolData(thrown[i], _getData(), that), that));
 1348    }
 1349   
 1350  64 SymbolData returnType = md.getReturnType();
 1351  64 if (returnType == null) {
 1352  0 _addError("Internal error: the returnType for " + md + " is null", that);
 1353    // Utilities.show("****** null return type for " + md + " Receiver type is " + context + " File is " + _file
 1354    // + " MethodData is " + md);
 1355    // assert false;
 1356  0 return null;
 1357    }
 1358   
 1359  64 return returnType.getInstanceData();
 1360    }
 1361   
 1362    /** Tries to match this method invocation to a method in the context. Here, the context is the enclosing data for
 1363    * where this is being invoked.
 1364    * @param that SimpleMethodInvocation we are typechecking
 1365    * @return The return type of the method, or null if method cannot be seen or found.
 1366    */
 1367    //TODO: We should handle static fields too!
 1368  31 public TypeData forSimpleMethodInvocation(SimpleMethodInvocation that) {
 1369  31 TypeData context = _getData().getSymbolData().getInstanceData();
 1370  2 if (inStaticMethod()) context = context.getSymbolData(); // Need SymbolData for context, not instance data.
 1371  31 return methodInvocationHelper(that, context);
 1372    }
 1373   
 1374    /** Tries to match this method invocation to a method in the context. Here, the context is the enclosing field of
 1375    * the method invocation.
 1376    * @param that ComplexMethodInvocation we are typechecking
 1377    * @return The return type of the method, or null if method cannot be seen or found.
 1378    */
 1379    //TODO: We should handle static fields too!
 1380  30 public TypeData forComplexMethodInvocation(ComplexMethodInvocation that) {
 1381  30 TypeData context = that.getEnclosing().visit(this);
 1382  0 if (! assertFound(context, that.getEnclosing()) || context == null) return null;
 1383   
 1384    //make sure we can see enclosingType
 1385  30 checkAccess(that, context.getSymbolData().getMav(), context.getSymbolData().getName(),
 1386    context.getSymbolData(), _data.getSymbolData(), "class or interface", true);
 1387   
 1388    // This check insures that only static methods can be called from static contexts; forces rhs to be a static context.
 1389    // WHICH IS WRONG. If the method call has an explicit receiver object, this property is IRRELEVANT.g
 1390    // if (inStaticMethod()) { context = context.getSymbolData();}
 1391  30 return methodInvocationHelper(that, context);
 1392    }
 1393   
 1394   
 1395    /** A variable data can be assigned to if it is not final or it does not have a value.
 1396    * (in other words, only final variables that have already been assigned are the only type that cannot be given a value.
 1397    * @param vd The VariableData to check.
 1398    */
 1399  28 protected boolean canBeAssigned(VariableData vd) { return ! vd.isFinal() || ! vd.hasValue(); }
 1400   
 1401    /** Returns the least restrictive numerical type. According to the JLS: "If an integer
 1402    * operator other than a shift operator has at least one operand of type long, then the
 1403    * operation is carried out using 64-bit precision, and the result of the numerical operator
 1404    * is of type long. If the other operand is not long, it is first widened (��5.1.4) to type
 1405    * long by numeric promotion (��5.6). Otherwise, the operation is carried out using 32-bit
 1406    * precision, and the result of the numerical operator is of type int. If either operand
 1407    * is not an int, it is first widened to type int by numeric promotion."
 1408    * So, check to see if one fo the SymboLDatas is a type less restrictive than int. If so, return that type,
 1409    * otherwise return INT_TYPE.
 1410    */
 1411  51 protected SymbolData _getLeastRestrictiveType(SymbolData sd1, SymbolData sd2) {
 1412  51 if ((sd1.isDoubleType(JAVA_VERSION) &&
 1413    sd2.isNumberType(JAVA_VERSION)) ||
 1414    (sd2.isDoubleType(JAVA_VERSION) &&
 1415    sd1.isNumberType(JAVA_VERSION))) {
 1416  5 return SymbolData.DOUBLE_TYPE;
 1417    }
 1418  46 else if ((sd1.isFloatType(JAVA_VERSION) &&
 1419    sd2.isNumberType(JAVA_VERSION)) ||
 1420    (sd2.isFloatType(JAVA_VERSION) &&
 1421    sd1.isNumberType(JAVA_VERSION))) {
 1422  2 return SymbolData.FLOAT_TYPE;
 1423    }
 1424  44 else if ((sd1.isLongType(JAVA_VERSION) &&
 1425    sd2.isNumberType(JAVA_VERSION)) ||
 1426    (sd2.isLongType(JAVA_VERSION) &&
 1427    sd1.isNumberType(JAVA_VERSION))) {
 1428  0 return SymbolData.LONG_TYPE;
 1429    }
 1430  44 else if (sd1.isBooleanType(JAVA_VERSION) &&
 1431    sd2.isBooleanType(JAVA_VERSION)) {
 1432  0 return SymbolData.BOOLEAN_TYPE;
 1433    }
 1434  44 else return SymbolData.INT_TYPE; // NOTE: It seems like any binary operation on number types with only ints, shorts, chars, or bytes will return an int
 1435    }
 1436   
 1437   
 1438   
 1439   
 1440    /**
 1441    * Throw runtime exception, since conditional expressions are not allowed, and this should have been caught
 1442    * before the TypeChecker.
 1443    */
 1444  0 public TypeData forConditionalExpression(ConditionalExpression that) {
 1445  0 throw new RuntimeException("Internal Program Error: Conditional expressions are not supported. This should have been caught before the Type Checker. Please report this bug.");
 1446    }
 1447   
 1448    /** Try to look up the type of the instanceof, and visit the expression that is being tested.
 1449    * If the type of the instanceof is null, add an error, and return null.
 1450    * If what is being tested cannot be resolved, just return the type boolean to allow further type checking.
 1451    * If everything is okay, call forInstanceofExpressionOnly to do other checks.
 1452    * @param that The InstanceofExpression being typeChecked
 1453    * @return The TypeData for boolean, or null
 1454    */
 1455  0 public TypeData forInstanceofExpression(InstanceofExpression that) {
 1456    //this call to getSymbolData will not throw any errors, but may return null. If null is returned, an error needs to be added.
 1457  0 final SymbolData typeRes = getSymbolData(that.getType().getName(), _data.getSymbolData(), that.getType(), false);
 1458  0 final TypeData valueRes = that.getValue().visit(this);
 1459   
 1460  0 if (typeRes == null) {
 1461  0 _addError(that.getType().getName()
 1462    + " cannot appear as the type of a instanceof expression because it is not a valid type",
 1463    that.getType());
 1464  0 return null;
 1465    }
 1466   
 1467  0 if (! assertFound(valueRes, that.getValue())) {
 1468    // An error occurred type-checking the value; return the expected type to
 1469    // allow type-checking to continue.
 1470  0 return SymbolData.BOOLEAN_TYPE.getInstanceData();
 1471    }
 1472   
 1473    // Neither typeRes nor valueRes are null.
 1474  0 return forInstanceofExpressionOnly(that, typeRes, valueRes);
 1475    }
 1476   
 1477   
 1478   
 1479    /** Try to look up the type of the cast, and visit the expression that is being cast.
 1480    * If the type being cast to is null, add an error, and return null.
 1481    * If what is being cast cannot be resolved, just return the expected result of the cast, to allow type checking.
 1482    * If everything is okay, call forCastExpressionOnly to do other checks.
 1483    * @param that The CastExpression being typeChecked
 1484    * @return The TypeData result of the cast, or null
 1485    */
 1486  8 public TypeData forCastExpression(CastExpression that) {
 1487    //this call to getSymbolData will not throw any errors, but may return null. If null is returned, an error needs to be added.
 1488  8 final SymbolData typeRes = getSymbolData(that.getType().getName(), _data.getSymbolData(), that.getType(), false);
 1489  8 final TypeData valueRes = that.getValue().visit(this);
 1490   
 1491  8 if (typeRes == null) {
 1492  1 _addError(that.getType().getName() + " cannot appear as the type of a cast expression because it is not a valid type", that.getType());
 1493  1 return null;
 1494    }
 1495   
 1496  7 if (valueRes == null || !assertFound(valueRes, that.getValue())) {
 1497    // An error occurred type-checking the value; return the expected type to
 1498    // allow type-checking to continue.
 1499  1 return typeRes.getInstanceData();
 1500    }
 1501   
 1502    // Neither typeRes nor valueRes are null.
 1503  6 return forCastExpressionOnly(that, typeRes, valueRes);
 1504    }
 1505   
 1506   
 1507    /**
 1508    * Make sure the dimensions of the array instantiation are all instances and subtypes of int, and then return
 1509    * an instance of the array.
 1510    * @param that The UninitializedArrayInstantiation being type checked
 1511    * @param typeRes The type of the array
 1512    * @param dimensions_result The array of the result of type-checking all the dimensions of this array.
 1513    * @return an instance of the array.
 1514    */
 1515  10 public TypeData forUninitializedArrayInstantiationOnly(UninitializedArrayInstantiation that, TypeData typeRes,
 1516    TypeData[] dimensions_result) {
 1517    //make sure all of the dimensions_result dimensions are instance datas
 1518  10 Expression[] dims = that.getDimensionSizes().getExpressions();
 1519  10 for (int i = 0; i<dimensions_result.length; i++) {
 1520  27 if (dimensions_result[i] != null && assertFound(dimensions_result[i], dims[i])) {
 1521  27 if (!dimensions_result[i].getSymbolData().isAssignableTo(SymbolData.INT_TYPE,
 1522    JAVA_VERSION)) {
 1523  2 _addError("The dimensions of an array instantiation must all be ints. You have specified something of type " +
 1524    dimensions_result[i].getName(), dims[i]);
 1525    }
 1526    else {
 1527  25 assertInstanceType(dimensions_result[i], "All dimensions of an array instantiation must be instances." +
 1528    " You have specified the type " + dimensions_result[i].getName(), dims[i]);
 1529    }
 1530    }
 1531    }
 1532   
 1533  10 if (typeRes instanceof ArrayData) {
 1534  9 int dim = ((ArrayData) typeRes).getDimensions();
 1535  9 if (dimensions_result.length > dim) {
 1536    //uh oh! Dimensions list is too long!
 1537  1 _addError("You are trying to initialize an array of type " + typeRes.getName() + " which requires " + dim +
 1538    " dimensions, but you have specified " + dimensions_result.length + " dimensions--the wrong number",
 1539    that);
 1540    }
 1541    }
 1542   
 1543    //return an instance of the new type
 1544  1 if (typeRes == null || !assertFound(typeRes, that)) {return null;}
 1545  9 return typeRes.getInstanceData();
 1546    }
 1547   
 1548    /**
 1549    * Resolve the type of the array and visit its dimensions. Call Only method to check instances in dimensions.
 1550    * @param that The SimpleUninitializedArrayInstantiation being type-checked.
 1551    * @return The type of the array, or null if there was an error.
 1552    */
 1553  6 public TypeData forSimpleUninitializedArrayInstantiation(SimpleUninitializedArrayInstantiation that) {
 1554  6 final SymbolData typeRes = getSymbolData(that.getType().getName(), _data.getSymbolData(), that.getType());
 1555  6 final TypeData[] dimensions_result = makeArrayOfRetType(that.getDimensionSizes().getExpressions().length);
 1556   
 1557  6 for (int i = 0; i<that.getDimensionSizes().getExpressions().length; i++) {
 1558  15 dimensions_result[i] = that.getDimensionSizes().getExpressions()[i].visit(this);
 1559    }
 1560  6 return forUninitializedArrayInstantiationOnly(that, typeRes, dimensions_result);
 1561    }
 1562   
 1563   
 1564    /**
 1565    * This is not legal java--should have been caught before the TypeChecker. Give a runtime exception
 1566    */
 1567  1 public TypeData forComplexUninitializedArrayInstantiation(ComplexUninitializedArrayInstantiation that) {
 1568  1 throw new RuntimeException("Internal Program Error: Complex Uninitialized Array Instantiations are not legal Java." +
 1569    " This should have been caught before the Type Checker. Please report this bug.");
 1570    }
 1571   
 1572   
 1573    /**
 1574    * The array initializer needs the type of the array to ensure it is properly handled. Because of this, we use a
 1575    * helper instead of calling this method directly.
 1576    */
 1577  1 public TypeData forArrayInitializer(ArrayInitializer that) {
 1578  1 throw new RuntimeException("Internal Program Error: forArrayInitializer should never be called, but it was." +
 1579    " Please report this bug.");
 1580    }
 1581   
 1582    /**
 1583    * Lookup the type of the array instantiation, and if there are any errors with it, give them.
 1584    * Then, check the array initializer.
 1585    * @param that The SimpleInitializedArrayAllocationInstantiation that is being type-checked
 1586    * @return An instance of the array
 1587    */
 1588  7 public TypeData forSimpleInitializedArrayInstantiation(SimpleInitializedArrayInstantiation that) {
 1589  7 SymbolData typeRes = getSymbolData(that.getType().getName(), _data, that.getType());
 1590  7 TypeData elementResult = forArrayInitializerHelper(that.getInitializer(), typeRes);
 1591  1 if (typeRes == null) {return null;}
 1592  6 return typeRes.getInstanceData();
 1593    }
 1594   
 1595    /**
 1596    * This is not legal java--should have been caught before the TypeChecker. Give a runtime exception
 1597    */
 1598  0 public TypeData forComplexInitializedArrayInstantiation(ComplexInitializedArrayInstantiation that) {
 1599  0 throw new RuntimeException("Internal Program Error: Complex Initialized Array Instantiations are not legal Java." +
 1600    " This should have been caught before the Type Checker. Please report this bug.");
 1601    }
 1602   
 1603   
 1604    // Moved from TypeChecker
 1605  0 public TypeData forInnerClassDef(InnerClassDef that) {
 1606  0 String className = that.getName().getText();
 1607  0 SymbolData sd = _data.getInnerClassOrInterface(className); // className is always a qualified name
 1608    // Check for cyclic inheritance
 1609  0 if (checkForCyclicInheritance(sd, new LinkedList<SymbolData>(), that)) {
 1610  0 return null;
 1611    }
 1612  0 final TypeData mavRes = that.getMav().visit(this);
 1613  0 final TypeData nameRes = that.getName().visit(this);
 1614  0 final TypeData[] typeParamRes = makeArrayOfRetType(that.getTypeParameters().length);
 1615  0 for (int i = 0; i < that.getTypeParameters().length; i++) {
 1616  0 typeParamRes[i] = that.getTypeParameters()[i].visit(this);
 1617    }
 1618  0 final TypeData superClass = that.getSuperclass().visit(this);
 1619  0 final TypeData[] interfacesRes = makeArrayOfRetType(that.getInterfaces().length);
 1620  0 for (int i = 0; i < that.getInterfaces().length; i++) {
 1621  0 interfacesRes[i] = that.getInterfaces()[i].visit(this);
 1622    }
 1623  0 final TypeData bodyRes = that.getBody().visit(new ClassBodyTypeChecker(sd, _file, _package, _importedFiles,
 1624    _importedPackages, _vars, _thrown));
 1625    // return forInnerClassDefOnly(that, mavRes, nameRes, typeParamRes, superClass,
 1626    // typeParamRes, bodyRes);
 1627  0 return null;
 1628    }
 1629   
 1630    /** Compares the two lists of variable datas, and if a data is in both lists, mark it as having been assigned.
 1631    * @param l1 One of the lists of variable datas
 1632    * @param l2 The other list of variable datas.
 1633    */
 1634  0 void reassignVariableDatas(LinkedList<VariableData> l1, LinkedList<VariableData> l2) {
 1635  0 for (int i = 0; i<l1.size(); i++) {
 1636  0 if (l2.contains(l1.get(i))) l1.get(i).gotValue();
 1637    }
 1638    }
 1639   
 1640    /** Compare a list of variable datas and a list of list of variable datas. If a variable data is in the list and in each list of the lists of lists, mark it as having been
 1641    * assigned.
 1642    * @param tryBlock The list of variable datas.
 1643    * @param catchBlocks The list of list of variable datas.
 1644    */
 1645  0 void reassignLotsaVariableDatas(LinkedList<VariableData> tryBlock, LinkedList<LinkedList<VariableData>> catchBlocks) {
 1646  0 for (int i = 0; i<tryBlock.size(); i++) {
 1647  0 boolean seenIt = true;
 1648  0 for (int j = 0; j<catchBlocks.size(); i++) {
 1649  0 if (! catchBlocks.get(j).contains(tryBlock.get(i))) {seenIt = false;}
 1650    }
 1651   
 1652  0 if (seenIt) { //find the variable data in vars and give it a value!
 1653  0 tryBlock.get(i).gotValue();
 1654    }
 1655    }
 1656    }
 1657   
 1658    /**
 1659    * Throw the appropriate error, based on the type of the JExpression where the exception was unchecked
 1660    * @param sd The SymbolData corresponding to the exception that is thrown
 1661    * @param j The JExpression corresponding to the context of where the exception is thrown from.
 1662    */
 1663  0 public void handleUncheckedException(SymbolData sd, JExpression j) {
 1664  0 if (j instanceof MethodInvocation) {
 1665  0 _addError("The method " + ((MethodInvocation)j).getName().getText() + " is declared to throw the exception " + sd.getName() + " which needs to be caught or declared to be thrown", j);
 1666    }
 1667  0 else if (j instanceof ThrowStatement) {
 1668  0 _addError("This statement throws the exception " + sd.getName() + " which needs to be caught or declared to be thrown", j);
 1669    }
 1670  0 else if (j instanceof ClassInstantiation) {
 1671  0 _addError("The constructor for the class " + ((ClassInstantiation)j).getType().getName() + " is declared to throw the exception " + sd.getName() + " which needs to be caught or declared to be thrown.", j);
 1672    }
 1673    else {
 1674  0 throw new RuntimeException("Internal Program Error: Something besides a method invocation or throw statement threw an exception. Please report this bug.");
 1675    }
 1676    }
 1677   
 1678   
 1679    /**
 1680    * Returns whether the sd is a checked exception, i.e. one that needs to be caught or declared to be thrown.
 1681    * This is defined as all subclasses of java.lang.Throwable except for subclasses of java.lang.RuntimeException
 1682    */
 1683  0 public boolean isCheckedException(SymbolData sd, JExpression that) {
 1684  0 return sd.isSubClassOf(getSymbolData("java.lang.Throwable", _data, that, false)) &&
 1685    ! sd.isSubClassOf(getSymbolData("java.lang.RuntimeException", _data, that, false)) &&
 1686    ! sd.isSubClassOf(getSymbolData("java.lang.Error", _data, that, false));
 1687    }
 1688   
 1689    /**
 1690    * Return true if the Exception is a checked exception yet is not caught or declared to be thrown, and false otherwise.
 1691    * An exception is a checked if it does not extend either java.lang.RuntimeException or java.lang.Error,
 1692    * and is not declared to be thrown by the enclosing method.
 1693    * @param sd The SymbolData of the Exception we are checking.
 1694    * @param that The JExpression passed to getSymbolData for error purposes.
 1695    */
 1696  0 public boolean isUncaughtCheckedException(SymbolData sd, JExpression that) {
 1697  0 return isCheckedException(sd, that);
 1698    }
 1699   
 1700    //TODO: To optimize this, should 2nd for loop be moved outside of first for loop?
 1701  0 public TypeData forBracedBody(BracedBody that) {
 1702  0 final TypeData[] items_result = makeArrayOfRetType(that.getStatements().length);
 1703  0 for (int i = 0; i < that.getStatements().length; i++) {
 1704  0 items_result[i] = that.getStatements()[i].visit(this);
 1705    //walk over what has been thrown and throw an error if it contains an unchecked exception
 1706  0 for (int j = 0; j<this._thrown.size(); j++) {
 1707  0 if (isUncaughtCheckedException(this._thrown.get(j).getFirst(), that)) {
 1708  0 handleUncheckedException(this._thrown.get(j).getFirst(), this._thrown.get(j).getSecond());
 1709    }
 1710    }
 1711    }
 1712   
 1713  0 return forBracedBodyOnly(that, items_result);
 1714    }
 1715   
 1716    /** @return true type by default. */
 1717  2 public TypeData forEmptyForCondition(EmptyForCondition that) {
 1718  2 return SymbolData.BOOLEAN_TYPE.getInstanceData();
 1719    }
 1720   
 1721    /** Test class for the methods defined in the above (enclosing) class. */
 1722    public static class ExpressionTypeCheckerTest extends TestCase {
 1723   
 1724    private ExpressionTypeChecker _etc;
 1725   
 1726    private SymbolData _sd1;
 1727    private SymbolData _sd2;
 1728    private SymbolData _sd3;
 1729    private SymbolData _sd4;
 1730    private SymbolData _sd5;
 1731    private SymbolData _sd6;
 1732    private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
 1733    private ModifiersAndVisibility _protectedMav =
 1734    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
 1735    private ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
 1736    private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
 1737    private ModifiersAndVisibility _abstractMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
 1738    private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
 1739    private ModifiersAndVisibility _finalPublicMav =
 1740    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final", "public"});
 1741    private ModifiersAndVisibility _publicAbstractMav =
 1742    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "abstract"});
 1743    private ModifiersAndVisibility _publicStaticMav =
 1744    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "static"});
 1745   
 1746   
 1747  0 public ExpressionTypeCheckerTest() { this(""); }
 1748  54 public ExpressionTypeCheckerTest(String name) { super(name); }
 1749   
 1750  54 public void setUp() {
 1751  54 errors = new LinkedList<Pair<String, JExpressionIF>>();
 1752  54 LanguageLevelConverter.symbolTable.clear();
 1753  54 LanguageLevelConverter._newSDs.clear();
 1754  54 LanguageLevelConverter.loadSymbolTable();
 1755  54 _etc =
 1756    new ExpressionTypeChecker(null, new File(""), "", new LinkedList<String>(), new LinkedList<String>(),
 1757    new LinkedList<VariableData>(), new LinkedList<Pair<SymbolData, JExpression>>());
 1758  54 LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, EmptyIterable.<File>make());
 1759  54 _etc._importedPackages.addFirst("java.lang");
 1760  54 _sd1 = new SymbolData("i.like.monkey");
 1761  54 _sd2 = new SymbolData("i.like.giraffe");
 1762  54 _sd3 = new SymbolData("zebra");
 1763  54 _sd4 = new SymbolData("u.like.emu");
 1764  54 _sd5 = new SymbolData("");
 1765  54 _sd6 = new SymbolData("cebu");
 1766  54 _etc._data = _sd1;
 1767    }
 1768   
 1769  1 public void testForCastExpression() {
 1770  1 CastExpression ce = new CastExpression(SourceInfo.NONE, new PrimitiveType(SourceInfo.NONE, "dan"), NULL_LITERAL);
 1771   
 1772    // if cast type is not a valid type, casting should not be allowed
 1773  1 assertEquals("Should return null", null, ce.visit(_etc));
 1774  1 assertEquals("There should be one error", 1, errors.size());
 1775  1 assertEquals("Error message should be correct",
 1776    "dan cannot appear as the type of a cast expression because it is not a valid type",
 1777    errors.getLast().getFirst());
 1778   
 1779    //if cast expression cannot be resolved, return cast type instance to allow type checking to continue
 1780  1 CastExpression ce2 =
 1781    new CastExpression(SourceInfo.NONE,
 1782    new PrimitiveType(SourceInfo.NONE, "int"),
 1783    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "notReal")));
 1784  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), ce2.visit(_etc));
 1785  1 assertEquals("There should be 2 errors", 2, errors.size());
 1786  1 assertEquals("Error message should be correct", "Could not resolve symbol notReal", errors.getLast().getFirst());
 1787   
 1788    //now, try one that should work
 1789  1 CastExpression ce3 = new CastExpression(SourceInfo.NONE,
 1790    new PrimitiveType(SourceInfo.NONE, "int"),
 1791    new DoubleLiteral(SourceInfo.NONE, 5));
 1792  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), ce3.visit(_etc));
 1793  1 assertEquals("There should still be 2 errors", 2, errors.size());
 1794   
 1795   
 1796    }
 1797   
 1798  1 public void testForCastExpressionOnly() {
 1799  1 SymbolData sd1 = SymbolData.DOUBLE_TYPE;
 1800  1 SymbolData sd2 = SymbolData.BOOLEAN_TYPE;
 1801  1 SymbolData sd3 = SymbolData.INT_TYPE;
 1802   
 1803  1 CastExpression cd = new CastExpression(SourceInfo.NONE, JExprParser.NO_TYPE, NULL_LITERAL);
 1804  1 assertEquals("When valueRes is subtype of typeRes, return typeRes.", sd1.getInstanceData(),
 1805    _etc.forCastExpressionOnly(cd, sd1, sd3.getInstanceData()));
 1806  1 assertEquals("Should not throw an error.", 0, errors.size());
 1807  1 assertEquals("When typeRes is subtype of valueRes, return typeRes.", sd3.getInstanceData(),
 1808    _etc.forCastExpressionOnly(cd, sd3, sd1.getInstanceData()));
 1809  1 assertEquals("Should not throw an error.", 0, errors.size());
 1810  1 assertEquals("When typeRes and valueRes are not subtypes of each other, return typeRes",
 1811    sd2.getInstanceData(), _etc.forCastExpressionOnly(cd, sd2, sd1.getInstanceData()));
 1812  1 assertEquals("Should now be one error.", 1, errors.size());
 1813  1 assertEquals("Error message should be correct.", "You cannot cast an expression of type " + sd1.getName()
 1814    + " to type " + sd2.getName() + " because they are not related",
 1815    errors.getLast().getFirst());
 1816  1 SymbolData foo = new SymbolData("Foo");
 1817  1 SymbolData fooMama = new SymbolData("FooMama");
 1818  1 foo.setSuperClass(fooMama);
 1819  1 assertEquals("When valueRes is a SymbolData, return typeRes", fooMama.getInstanceData(),
 1820    _etc.forCastExpressionOnly(cd, fooMama, foo));
 1821  1 assertEquals("There should be 2 errors.", 2, errors.size());
 1822  1 assertEquals("Error message should be correct.",
 1823    "You are trying to cast Foo, which is a class or interface type, not an instance. "
 1824    + "Perhaps you meant to create a new instance of Foo",
 1825    errors.getLast().getFirst());
 1826    }
 1827   
 1828  1 public void testForEmptyExpressionOnly() {
 1829  1 EmptyExpression ee = new EmptyExpression(SourceInfo.NONE);
 1830  1 try {
 1831  1 _etc.forEmptyExpressionOnly(ee);
 1832  0 fail("Should have thrown exception");
 1833    }
 1834    catch (RuntimeException e) {
 1835  1 assertEquals("Error message should be correct",
 1836    "Internal Program Error: EmptyExpression encountered. Student is missing something. "
 1837    + "Should have been caught before TypeChecker. Please report this bug.",
 1838    e.getMessage());
 1839    }
 1840    }
 1841   
 1842  1 public void test_getLeastRestrictiveType() {
 1843    // Assumes both number types
 1844  1 assertEquals("Should return double.", SymbolData.FLOAT_TYPE,
 1845    _etc._getLeastRestrictiveType(SymbolData.INT_TYPE, SymbolData.FLOAT_TYPE));
 1846  1 assertEquals("Should return double.", SymbolData.FLOAT_TYPE,
 1847    _etc._getLeastRestrictiveType(SymbolData.FLOAT_TYPE, SymbolData.FLOAT_TYPE));
 1848  1 assertEquals("Should return int.", SymbolData.INT_TYPE,
 1849    _etc._getLeastRestrictiveType(SymbolData.INT_TYPE, SymbolData.CHAR_TYPE));
 1850  1 assertEquals("Should return char.", SymbolData.INT_TYPE,
 1851    _etc._getLeastRestrictiveType(SymbolData.CHAR_TYPE, SymbolData.CHAR_TYPE));
 1852    }
 1853   
 1854  1 public void test_isAssignableFrom() {
 1855  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(SymbolData.DOUBLE_TYPE, SymbolData.DOUBLE_TYPE));
 1856  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(SymbolData.DOUBLE_TYPE, SymbolData.INT_TYPE));
 1857  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(SymbolData.DOUBLE_TYPE, SymbolData.CHAR_TYPE));
 1858  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(SymbolData.INT_TYPE, SymbolData.INT_TYPE));
 1859  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(SymbolData.INT_TYPE, SymbolData.CHAR_TYPE));
 1860  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(SymbolData.CHAR_TYPE, SymbolData.CHAR_TYPE));
 1861   
 1862  1 _sd2.setSuperClass(_sd1);
 1863  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(_sd1, _sd1));
 1864  1 assertTrue("Should be assignable.", _etc._isAssignableFrom(_sd1, _sd2));
 1865    }
 1866   
 1867   
 1868    //for expressions we want to check, but don't fit neatly into a category
 1869  1 public void testRandomExpressions() {
 1870    //a string of + and - before a number
 1871  1 PositiveExpression pe = new PositiveExpression(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5));
 1872  1 PositiveExpression pe2 = new PositiveExpression(SourceInfo.NONE, pe);
 1873  1 NegativeExpression pe3 = new NegativeExpression(SourceInfo.NONE, pe2);
 1874  1 PositiveExpression pe4 = new PositiveExpression(SourceInfo.NONE, pe3);
 1875  1 PositiveExpression pe5 = new PositiveExpression(SourceInfo.NONE, pe4);
 1876  1 NegativeExpression pe6 = new NegativeExpression(SourceInfo.NONE, pe5);
 1877   
 1878  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), pe6.visit(_etc));
 1879  1 assertEquals("Should be no errors", 0, errors.size());
 1880    }
 1881   
 1882  1 public void testForSimpleUninitializedArrayInstantiation() {
 1883  1 LanguageLevelVisitor llv =
 1884    new LanguageLevelVisitor(_etc._file,
 1885    _etc._package,
 1886    null, // enclosingClassName for top level traversal
 1887    _etc._importedFiles,
 1888    _etc._importedPackages,
 1889    new HashSet<String>(),
 1890    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 1891    new LinkedList<Command>());
 1892    // LanguageLevelConverter.symbolTable = llv.symbolTable = _etc.symbolTable;
 1893    // LanguageLevelConverter._newSDs = new Hashtable<SymbolData, LanguageLevelVisitor>();
 1894   
 1895  1 SourceInfo si = SourceInfo.NONE;
 1896   
 1897  1 ArrayData intArray = new ArrayData(SymbolData.INT_TYPE, llv, si);
 1898  1 intArray.setIsContinuation(false);
 1899  1 symbolTable.remove("int[]");
 1900  1 symbolTable.put("int[]", intArray);
 1901   
 1902  1 ArrayData intArrayArray = new ArrayData(intArray, llv, si);
 1903  1 intArrayArray.setIsContinuation(false);
 1904  1 symbolTable.put("int[][]", intArrayArray);
 1905   
 1906  1 ArrayData intArray3 = new ArrayData(intArrayArray, llv, si);
 1907  1 intArray3.setIsContinuation(false);
 1908  1 symbolTable.put("int[][][]", intArray3);
 1909   
 1910  1 Expression i1 = new IntegerLiteral(si, 5);
 1911  1 Expression i2 = new PlusExpression(si, new IntegerLiteral(si, 5), new IntegerLiteral(si, 7));
 1912  1 Expression i3 = new CharLiteral(si, 'c');
 1913  1 Expression badIndexD = new DoubleLiteral(si, 4.2);
 1914  1 Expression badIndexL = new LongLiteral(si, 4l);
 1915   
 1916    // Test one that works
 1917  1 SimpleUninitializedArrayInstantiation sa1 =
 1918    new SimpleUninitializedArrayInstantiation(si, new ArrayType(si, "int[][][]",
 1919    new ArrayType(si, "int[][]",
 1920    new ArrayType(si, "int[]", new PrimitiveType(si, "int")))),
 1921    new DimensionExpressionList(si, new Expression[] {i1, i2, i3}));
 1922  1 assertEquals("Should return instance of int[][][]", intArray3.getInstanceData(), sa1.visit(_etc));
 1923  1 assertEquals("There should be no errors", 0, errors.size());
 1924   
 1925    // Test one with a bad index
 1926  1 SimpleUninitializedArrayInstantiation sa2 =
 1927    new SimpleUninitializedArrayInstantiation(si, new ArrayType(si, "int[][][]",
 1928    new ArrayType(si, "int[][]", new ArrayType(si, "int[]", new PrimitiveType(si, "int")))),
 1929    new DimensionExpressionList(si, new Expression[] {i1, i2, badIndexD}));
 1930  1 assertEquals("Should return instance of int[][][]", intArray3.getInstanceData(), sa2.visit(_etc));
 1931    /* The preceding test only confirms structural equality not identity of the result. The TypeData equals method
 1932    * has been overridden to confirm that its argument belongs to the same class as this and then perform an equals
 1933    * comparison of the only field of the argument and this. */
 1934   
 1935  1 assertEquals("There should be one error", 1, errors.size());
 1936  1 assertEquals("The error message should be correct",
 1937    "The dimensions of an array instantiation must all be ints. You have specified something of type double",
 1938    errors.getLast().getFirst());
 1939   
 1940    //Test one with a bad type
 1941  1 SimpleUninitializedArrayInstantiation sa3 =
 1942    new SimpleUninitializedArrayInstantiation(si, new ArrayType(si, "Jonathan[]",
 1943    new ClassOrInterfaceType(si, "Jonathan", new Type[0])),
 1944    new DimensionExpressionList(si, new Expression[]{i1}));
 1945  1 assertEquals("Should return null", null, sa3.visit(_etc));
 1946  1 assertEquals("There should be 2 errors", 2, errors.size());
 1947  1 assertEquals("Error message should be correct",
 1948    "Class or variable Jonathan[] not found.",
 1949    errors.getLast().getFirst());
 1950    // Test one with wrong dimensions--too many
 1951  1 SimpleUninitializedArrayInstantiation sa4 =
 1952    new SimpleUninitializedArrayInstantiation(si, new ArrayType(si, "int[][]",
 1953    new ArrayType(si, "int[]", new PrimitiveType(si, "int"))),
 1954    new DimensionExpressionList(si, new Expression[] {i1, i2, i3}));
 1955  1 assertEquals("Should return instance of int[][]", intArrayArray.getInstanceData(), sa4.visit(_etc));
 1956  1 assertEquals("There should be 3 errors", 3, errors.size());
 1957  1 assertEquals("Error message should be correct",
 1958    "You are trying to initialize an array of type int[][] which requires 2 dimensions, but you have "
 1959    + "specified 3 dimensions--the wrong number",
 1960    errors.getLast().getFirst());
 1961    // Test one with wrong dimensions--too few--should be no additional errors
 1962  1 SimpleUninitializedArrayInstantiation sa5 =
 1963    new SimpleUninitializedArrayInstantiation(si, new ArrayType(si, "int[][][]",
 1964    new ArrayType(si, "int[][]", new ArrayType(si, "int[]",
 1965    new PrimitiveType(si, "int")))),
 1966    new DimensionExpressionList(si, new Expression[] {i1, i2}));
 1967  1 assertEquals("Should return instance of int[][][]", intArray3.getInstanceData(), sa5.visit(_etc));
 1968  1 assertEquals("There should still be 3 errors", 3, errors.size());
 1969   
 1970    //Test one where type is not accessible
 1971  1 intArray3.setMav(_privateMav);
 1972  1 assertEquals("Should return instance of int[][][]", intArray3.getInstanceData(), sa1.visit(_etc));
 1973  1 assertEquals("There should be one new error", 4, errors.size());
 1974  1 assertEquals("Error message should be correct",
 1975    "The class or interface int[][][] in int[][][] is private and cannot be accessed from i.like.monkey",
 1976    errors.getLast().getFirst());
 1977  1 intArray3.setMav(_publicMav);
 1978    }
 1979   
 1980  1 public void testForComplexUninitializedArrayInstantiation() {
 1981  1 ComplexUninitializedArrayInstantiation ca1 = new ComplexUninitializedArrayInstantiation(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "my")),
 1982    new ArrayType(SourceInfo.NONE, "type[][][]", new ArrayType(SourceInfo.NONE, "type[][]", new ArrayType(SourceInfo.NONE, "type[]", new ClassOrInterfaceType(SourceInfo.NONE, "type", new Type[0])))),
 1983    new DimensionExpressionList(SourceInfo.NONE, new Expression[0]));
 1984    //This should always give a runtime exception
 1985  1 try {
 1986  1 ca1.visit(_etc);
 1987  0 fail("Should have throw runtime exception");
 1988    }
 1989    catch (RuntimeException e) {
 1990  1 assertEquals("Correct exception should have been thrown","Internal Program Error: Complex Uninitialized Array Instantiations are not legal Java. This should have been caught before the Type Checker. Please report this bug." , e.getMessage());
 1991    }
 1992    }
 1993   
 1994  1 public void testForUninitializedArrayInstantiationOnly() {
 1995  1 LanguageLevelVisitor llv =
 1996    new LanguageLevelVisitor(_etc._file,
 1997    _etc._package,
 1998    null, // enclosingClassName for top level traversal
 1999    _etc._importedFiles,
 2000    _etc._importedPackages,
 2001    new HashSet<String>(),
 2002    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 2003    new LinkedList<Command>());
 2004   
 2005    // LanguageLevelConverter.symbolTable = llv.symbolTable = _etc.symbolTable;
 2006    // LanguageLevelConverter._newSDs = new Hashtable<SymbolData, LanguageLevelVisitor>();
 2007   
 2008  1 SourceInfo si = SourceInfo.NONE;
 2009   
 2010  1 ArrayData intArray = new ArrayData(SymbolData.INT_TYPE, llv, si);
 2011  1 intArray.setIsContinuation(false);
 2012  1 symbolTable.remove("int[]");
 2013  1 symbolTable.put("int[]", intArray);
 2014   
 2015  1 ArrayData intArrayArray = new ArrayData(intArray, llv, si);
 2016  1 intArrayArray.setIsContinuation(false);
 2017  1 symbolTable.put("int[][]", intArrayArray);
 2018   
 2019  1 ArrayData intArray3 = new ArrayData(intArrayArray, llv, si);
 2020  1 intArray3.setIsContinuation(false);
 2021  1 symbolTable.put("int[][][]", intArray3);
 2022   
 2023    // One that works--int instance index
 2024  1 SimpleUninitializedArrayInstantiation sa1 =
 2025    new SimpleUninitializedArrayInstantiation(si, new ArrayType(si, "int[][][]",
 2026    new ArrayType(si, "int[][]", new ArrayType(si, "int[]", new PrimitiveType(si, "int")))),
 2027    new DimensionExpressionList(si, new Expression[] {new NullLiteral(si), new NullLiteral(si), new NullLiteral(si)}));
 2028   
 2029  1 TypeData[] arrayInitTypes1 =
 2030    new TypeData[] { SymbolData.INT_TYPE.getInstanceData(),
 2031    SymbolData.INT_TYPE.getInstanceData(),
 2032    SymbolData.INT_TYPE.getInstanceData()};
 2033  1 assertEquals("Should return int[][][] instance", intArray3.getInstanceData(),
 2034    _etc.forUninitializedArrayInstantiationOnly(sa1, intArray3, arrayInitTypes1));
 2035  1 assertEquals("Should be no errors", 0, errors.size());
 2036   
 2037    //one that works--char instance index
 2038  1 TypeData[] arrayInitTypes2 =
 2039    new TypeData[] { SymbolData.INT_TYPE.getInstanceData(),
 2040    SymbolData.INT_TYPE.getInstanceData(),
 2041    SymbolData.CHAR_TYPE.getInstanceData()};
 2042  1 assertEquals("Should return int[][][] instance", intArray3.getInstanceData(),
 2043    _etc.forUninitializedArrayInstantiationOnly(sa1, intArray3, arrayInitTypes2));
 2044  1 assertEquals("Should be no errors", 0, errors.size());
 2045   
 2046    // one with bad index: not instance type
 2047  1 TypeData[] arrayInitTypes3 =
 2048    new TypeData[] { SymbolData.INT_TYPE.getInstanceData(),
 2049    SymbolData.INT_TYPE,
 2050    SymbolData.CHAR_TYPE.getInstanceData()};
 2051  1 assertEquals("Should return int[][][] instance", intArray3.getInstanceData(),
 2052    _etc.forUninitializedArrayInstantiationOnly(sa1, intArray3, arrayInitTypes3));
 2053  1 assertEquals("Should be one error", 1, errors.size());
 2054  1 assertEquals("Error message should be correct", "All dimensions of an array instantiation must be instances. You have specified the type int. Perhaps you meant to create a new instance of int", errors.getLast().getFirst());
 2055   
 2056    // one with bad index: not int type
 2057  1 assertEquals("Should return int[][][] instance", intArray3.getInstanceData(), _etc.forUninitializedArrayInstantiationOnly(sa1, intArray3, new TypeData[] {SymbolData.INT_TYPE.getInstanceData(), SymbolData.BOOLEAN_TYPE, SymbolData.CHAR_TYPE.getInstanceData()}));
 2058  1 assertEquals("Should be 2 errors", 2, errors.size());
 2059  1 assertEquals("Error message should be correct", "The dimensions of an array instantiation must all be ints. You have specified something of type boolean" , errors.getLast().getFirst());
 2060   
 2061   
 2062    }
 2063   
 2064  1 public void testForArrayInitializer() {
 2065  1 ArrayInitializer ai = new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {new IntegerLiteral(SourceInfo.NONE, 2)});
 2066  1 try {
 2067  1 ai.visit(_etc);
 2068  0 fail("Should have throw runtime exception");
 2069    }
 2070    catch(RuntimeException e) {
 2071  1 assertEquals("Exception message should be correct", "Internal Program Error: forArrayInitializer should never be called, but it was. Please report this bug.", e.getMessage());
 2072    }
 2073   
 2074    }
 2075   
 2076  1 public void testForSimpleInitializedArrayInstantiation() {
 2077  1 IntegerLiteral e1 = new IntegerLiteral(SourceInfo.NONE, 5);
 2078  1 IntegerLiteral e2 = new IntegerLiteral(SourceInfo.NONE, 7);
 2079  1 SimpleNameReference e3 = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int"));
 2080  1 BooleanLiteral e4 = new BooleanLiteral(SourceInfo.NONE, true);
 2081  1 DoubleLiteral e5 = new DoubleLiteral(SourceInfo.NONE, 4.2);
 2082  1 CharLiteral e6 = new CharLiteral(SourceInfo.NONE, 'e');
 2083  1 SimpleNameReference e7 = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int"));
 2084   
 2085  1 ArrayType intArrayType = new ArrayType(SourceInfo.NONE, "int[]", new PrimitiveType(SourceInfo.NONE, "int"));
 2086   
 2087  1 LanguageLevelVisitor llv =
 2088    new LanguageLevelVisitor(_etc._file,
 2089    _etc._package,
 2090    null, // enclosingClassName for top level traversal
 2091    _etc._importedFiles,
 2092    _etc._importedPackages,
 2093    new HashSet<String>(),
 2094    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 2095    new LinkedList<Command>());
 2096   
 2097  1 ArrayData intArray = new ArrayData(SymbolData.INT_TYPE, llv, SourceInfo.NONE);
 2098  1 intArray.setIsContinuation(false);
 2099  1 symbolTable.remove("int[]");
 2100  1 symbolTable.put("int[]", intArray);
 2101   
 2102    //try one that should work:
 2103  1 InitializedArrayInstantiation good = new SimpleInitializedArrayInstantiation(SourceInfo.NONE, intArrayType, new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {e1, e2}));
 2104  1 assertEquals("Should return int array instance", intArray.getInstanceData(), good.visit(_etc));
 2105  1 assertEquals("Should be no errors", 0, errors.size());
 2106   
 2107    //char is a subtype of int, so it can be used here
 2108  1 good = new SimpleInitializedArrayInstantiation(SourceInfo.NONE, intArrayType, new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {e1, e2, e6}));
 2109  1 assertEquals("Should return int array instance", intArray.getInstanceData(), good.visit(_etc));
 2110  1 assertEquals("Should be no errors", 0, errors.size());
 2111   
 2112    //lhs is not an array type
 2113  1 InitializedArrayInstantiation bad = new SimpleInitializedArrayInstantiation(SourceInfo.NONE, new PrimitiveType(SourceInfo.NONE, "int"), new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {e1, e2}));
 2114  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), bad.visit(_etc));
 2115  1 assertEquals("Should be 1 error", 1, errors.size());
 2116  1 assertEquals("Error message should be correct", "You cannot initialize the non-array type int with an array initializer", errors.getLast().getFirst());
 2117   
 2118    //one of the elements is the wrong type
 2119    //boolean
 2120  1 bad = new SimpleInitializedArrayInstantiation(SourceInfo.NONE, intArrayType, new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {e1, e4, e2, e6}));
 2121  1 assertEquals("Should return int array instance", intArray.getInstanceData(), bad.visit(_etc));
 2122  1 assertEquals("Should be 2 errors", 2, errors.size());
 2123  1 assertEquals("Error message should be correct", "The elements of this initializer should have type int but element 1 has type boolean", errors.getLast().getFirst());
 2124   
 2125    //double
 2126  1 bad = new SimpleInitializedArrayInstantiation(SourceInfo.NONE, intArrayType, new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {e1, e5, e2, e6}));
 2127  1 assertEquals("Should return int array instance", intArray.getInstanceData(), bad.visit(_etc));
 2128  1 assertEquals("Should be 3 errors", 3, errors.size());
 2129  1 assertEquals("Error message should be correct", "The elements of this initializer should have type int but element 1 has type double", errors.getLast().getFirst());
 2130   
 2131    //cannot resolve lhs
 2132  1 bad = new SimpleInitializedArrayInstantiation(SourceInfo.NONE, new PrimitiveType(SourceInfo.NONE, "ej"), new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {e1, e2}));
 2133  1 assertEquals("Should return null", null, bad.visit(_etc));
 2134  1 assertEquals("Should be 4 error", 4, errors.size());
 2135  1 assertEquals("Error message should be correct", "Class or variable ej not found.", errors.getLast().getFirst());
 2136   
 2137    //one of the things in the initializer is a type name!
 2138  1 bad = new SimpleInitializedArrayInstantiation(SourceInfo.NONE, intArrayType, new ArrayInitializer(SourceInfo.NONE, new VariableInitializerI[] {e1, e7}));
 2139  1 assertEquals("Should return instance of int[]", intArray.getInstanceData(), bad.visit(_etc));
 2140  1 assertEquals("Should now be 5 error messages", 5, errors.size());
 2141  1 assertEquals("Error message should be correct", "The elements of this initializer should all be instances, but you have specified the type name int. Perhaps you meant to create a new instance of int", errors.getLast().getFirst());
 2142   
 2143   
 2144    }
 2145   
 2146   
 2147   
 2148   
 2149  1 public void testForSimpleAssignmentExpressionOnly() {
 2150  1 SimpleAssignmentExpression sae = new SimpleAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")), new IntegerLiteral(SourceInfo.NONE, 5));
 2151   
 2152    //if lhs is assignable to rhs, and both instances, do not give any errors
 2153  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), _etc.forSimpleAssignmentExpressionOnly(sae, SymbolData.DOUBLE_TYPE.getInstanceData(), SymbolData.INT_TYPE.getInstanceData()));
 2154  1 assertEquals("Should be no errors", 0, errors.size());
 2155   
 2156    //if either input is null, return null
 2157  1 assertEquals("Should return null", null, _etc.forSimpleAssignmentExpressionOnly(sae, null, SymbolData.INT_TYPE));
 2158  1 assertEquals("Should return null", null, _etc.forSimpleAssignmentExpressionOnly(sae, SymbolData.INT_TYPE, null));
 2159  1 assertEquals("Should be no errors", 0, errors.size());
 2160   
 2161    //if lhs is a PackageData, give error and return null
 2162  1 PackageData pd = new PackageData("bad_reference");
 2163  1 assertEquals("Should return null", null, _etc.forSimpleAssignmentExpressionOnly(sae, pd, SymbolData.INT_TYPE));
 2164  1 assertEquals("Should be 1 error", 1, errors.size());
 2165  1 assertEquals("Error message should be correct", "Could not resolve symbol bad_reference", errors.get(0).getFirst());
 2166   
 2167   
 2168    //if rhs is a PackageData, give an error and return null
 2169  1 assertEquals("Should return null", null, _etc.forSimpleAssignmentExpressionOnly(sae, SymbolData.INT_TYPE, pd));
 2170  1 assertEquals("Should only be 1 error", 1, errors.size()); // Generated error is duplicate
 2171  1 assertEquals("Error message should be correct", "Could not resolve symbol bad_reference", errors.get(0).getFirst());
 2172   
 2173    //if rhs or lhs are not instance datas, give appropriate errors
 2174  1 assertEquals("Should return double instance",
 2175    SymbolData.DOUBLE_TYPE.getInstanceData(),
 2176    _etc.forSimpleAssignmentExpressionOnly(sae,
 2177    SymbolData.DOUBLE_TYPE,
 2178    SymbolData.INT_TYPE.getInstanceData()));
 2179  1 assertEquals("Should now be 2 errors", 2, errors.size()); // Generated one new error; one duplicate
 2180  1 assertEquals("Error message should be correct",
 2181    "You cannot assign a value to the type double. Perhaps you meant to create a new instance of double",
 2182    errors.get(1).getFirst());
 2183   
 2184  1 assertEquals("Should return double instance",
 2185    SymbolData.DOUBLE_TYPE.getInstanceData(),
 2186    _etc.forSimpleAssignmentExpressionOnly(sae,
 2187    SymbolData.DOUBLE_TYPE.getInstanceData(),
 2188    SymbolData.INT_TYPE));
 2189  1 assertEquals("Should now be 3 errors", 3, errors.size());
 2190  1 assertEquals("Error message should be correct",
 2191    "You cannot use the type name int on the right hand side of an assignment. " +
 2192    "Perhaps you meant to create a new instance of int",
 2193    errors.get(2).getFirst());
 2194   
 2195    //if rhs cannot be assigned to lhs, give error
 2196  1 assertEquals("Should return int instance",
 2197    SymbolData.INT_TYPE.getInstanceData(),
 2198    _etc.forSimpleAssignmentExpressionOnly(sae,
 2199    SymbolData.INT_TYPE.getInstanceData(),
 2200    SymbolData.DOUBLE_TYPE.getInstanceData()));
 2201  1 assertEquals("Should now be 4 errors", 4, errors.size());
 2202  1 assertEquals("Error message should be correct",
 2203    "You cannot assign something of type double to something of type int",
 2204    errors.get(3).getFirst());
 2205   
 2206    }
 2207   
 2208   
 2209  1 public void testForPlusAssignmentExpressionOnly() {
 2210  1 PlusAssignmentExpression pae =
 2211    new PlusAssignmentExpression(SourceInfo.NONE,
 2212    new IntegerLiteral(SourceInfo.NONE, 5), new IntegerLiteral(SourceInfo.NONE, 6));
 2213   
 2214    //if lhs is a string, and lhs and rhs both instances, no errors
 2215  1 SymbolData string = new SymbolData("java.lang.String");
 2216  1 string.setIsContinuation(false);
 2217  1 string.setPackage("java.lang");
 2218  1 string.setMav(_publicMav);
 2219  1 symbolTable.put("java.lang.String", string);
 2220   
 2221  1 assertEquals("Should return string instance",
 2222    string.getInstanceData(),
 2223    _etc.forPlusAssignmentExpressionOnly(pae, string.getInstanceData(),
 2224    SymbolData.INT_TYPE.getInstanceData()));
 2225  1 assertEquals("Should be no errors", 0, errors.size());
 2226   
 2227    //if both number instances, no errors
 2228  1 assertEquals("Should return double instance",
 2229    SymbolData.DOUBLE_TYPE.getInstanceData(),
 2230    _etc.forPlusAssignmentExpressionOnly(pae,
 2231    SymbolData.DOUBLE_TYPE.getInstanceData(),
 2232    SymbolData.INT_TYPE.getInstanceData()));
 2233  1 assertEquals("Should be no errors", 0, errors.size());
 2234   
 2235    //if either input is null, return null
 2236  1 assertEquals("Should return null", null, _etc.forPlusAssignmentExpressionOnly(pae, null, SymbolData.INT_TYPE));
 2237  1 assertEquals("Should return null", null, _etc.forPlusAssignmentExpressionOnly(pae, SymbolData.INT_TYPE, null));
 2238  1 assertEquals("Should be no errors", 0, errors.size());
 2239   
 2240    //if lhs is a PackageData, give error and return null
 2241  1 PackageData pd = new PackageData("bad_reference");
 2242  1 assertEquals("Should return null", null, _etc.forPlusAssignmentExpressionOnly(pae, pd, SymbolData.INT_TYPE));
 2243  1 assertEquals("Should be 1 error", 1, errors.size());
 2244  1 assertEquals("Error message should be correct", "Could not resolve symbol bad_reference", errors.getLast().getFirst());
 2245   
 2246   
 2247    //if rhs is a PackageData, give an error and return null
 2248  1 assertEquals("Should return null", null, _etc.forPlusAssignmentExpressionOnly(pae, SymbolData.INT_TYPE, pd));
 2249  1 assertEquals("Should be 1 error", 1, errors.size()); // Generated duplicate error message
 2250  1 assertEquals("Error message should be correct", "Could not resolve symbol bad_reference", errors.get(0).getFirst());
 2251   
 2252    //if lhs is a string, but not an instance data, give error
 2253  1 assertEquals("Should return string instance",
 2254    string.getInstanceData(),
 2255    _etc.forPlusAssignmentExpressionOnly(pae, string,
 2256    SymbolData.INT_TYPE.getInstanceData()));
 2257  1 assertEquals("Should now be 2 errors", 2, errors.size());
 2258  1 assertEquals("Error message should be correct",
 2259    "The arguments to a Plus Assignment Operator (+=) must both be instances, but you have specified " +
 2260    "a type name. Perhaps you meant to create a new instance of java.lang.String",
 2261    errors.get(1).getFirst());
 2262   
 2263    //if lhs is a string, but rhs is not an instance, give error
 2264  1 assertEquals("Should return string instance", string.getInstanceData(),
 2265    _etc.forPlusAssignmentExpressionOnly(pae, string.getInstanceData(),
 2266    SymbolData.INT_TYPE));
 2267  1 assertEquals("Should now be 3 errors", 3, errors.size());
 2268  1 assertEquals("Error message should be correct",
 2269    "The arguments to a Plus Assignment Operator (+=) must both be instances, " +
 2270    "but you have specified a type name. Perhaps you meant to create a new instance of int" ,
 2271    errors.get(2).getFirst());
 2272   
 2273    // if rhs is not a number or string, give error
 2274  1 assertEquals("Should return string, by default", string.getInstanceData(),
 2275    _etc.forPlusAssignmentExpressionOnly(pae, _sd2.getInstanceData(),
 2276    SymbolData.INT_TYPE.getInstanceData()));
 2277  1 assertEquals("Should now be 4 errors", 4, errors.size());
 2278  1 assertEquals("Error message should be correct",
 2279    "The arguments to the Plus Assignment Operator (+=) must either include an instance of a String " +
 2280    "or both be numbers. You have specified arguments of type " + _sd2.getName() + " and int",
 2281    errors.get(3).getFirst());
 2282   
 2283    // if rhs is number but lhs is not, give error
 2284  1 assertEquals("should return string, by default", string.getInstanceData(),
 2285    _etc.forPlusAssignmentExpressionOnly(pae, SymbolData.INT_TYPE.getInstanceData(),
 2286    _sd2.getInstanceData()));
 2287  1 assertEquals("Should now be 5 errors", 5, errors.size()); // Generated slightly different error message
 2288  1 assertEquals("Error message should be correct",
 2289    "The arguments to the Plus Assignment Operator (+=) must either include an instance of a String " +
 2290    "or both be numbers. You have specified arguments of type int and " + _sd2.getName(),
 2291    errors.get(4).getFirst());
 2292   
 2293  1 assertEquals("Should return int instance",
 2294    SymbolData.INT_TYPE.getInstanceData(),
 2295    _etc.forPlusAssignmentExpressionOnly(pae, SymbolData.INT_TYPE.getInstanceData(),
 2296    SymbolData.DOUBLE_TYPE.getInstanceData()));
 2297  1 assertEquals("Should now be 6 errors", 6, errors.size());
 2298  1 assertEquals("Error message should be correct",
 2299    "You cannot increment something of type int with something of type double",
 2300    errors.get(5).getFirst());
 2301   
 2302    //if both numbers, but not instances, give errors
 2303  1 assertEquals("Should return double instance",
 2304    SymbolData.DOUBLE_TYPE.getInstanceData(),
 2305    _etc.forPlusAssignmentExpressionOnly(pae, SymbolData.DOUBLE_TYPE, SymbolData.INT_TYPE));
 2306  1 assertEquals("Should now be 8 errors", 8, errors.size());
 2307  1 assertEquals("Second error message should be new",
 2308    "The arguments to the Plus Assignment Operator (+=) must both be instances, but you have specified " +
 2309    "a type name. Perhaps you meant to create a new instance of double",
 2310    errors.get(6).getFirst());
 2311  1 assertEquals("First error message should be new",
 2312    "The arguments to the Plus Assignment Operator (+=) must both be instances, but you have specified " +
 2313    "a type name. Perhaps you meant to create a new instance of int",
 2314    errors.get(7).getFirst());
 2315    }
 2316   
 2317  1 public void testForNumericAssignmentExpressionOnly() {
 2318  1 NumericAssignmentExpression nae =
 2319    new MinusAssignmentExpression(SourceInfo.NONE,
 2320    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")),
 2321    new IntegerLiteral(SourceInfo.NONE, 5));
 2322   
 2323    //if both lhs and rhs are instances of numbers, and lhs is assignable to rhs, should be no errors
 2324  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), _etc.forNumericAssignmentExpressionOnly(nae, SymbolData.INT_TYPE.getInstanceData(), SymbolData.CHAR_TYPE.getInstanceData()));
 2325  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), _etc.forNumericAssignmentExpressionOnly(nae, SymbolData.DOUBLE_TYPE.getInstanceData(), SymbolData.INT_TYPE.getInstanceData()));
 2326  1 assertEquals("Should be no errors", 0, errors.size());
 2327   
 2328   
 2329    //if either input is null, return null
 2330  1 assertEquals("Should return null", null, _etc.forNumericAssignmentExpressionOnly(nae, null, SymbolData.INT_TYPE));
 2331  1 assertEquals("Should return null", null, _etc.forNumericAssignmentExpressionOnly(nae, SymbolData.INT_TYPE, null));
 2332  1 assertEquals("Should be no errors", 0, errors.size());
 2333   
 2334    //if lhs is a PackageData, give error and return null
 2335  1 PackageData pd = new PackageData("bad_reference");
 2336  1 assertEquals("Should return null", null, _etc.forNumericAssignmentExpressionOnly(nae, pd, SymbolData.INT_TYPE));
 2337  1 assertEquals("Should be 1 error", 1, errors.size());
 2338  1 assertEquals("Error message should be correct", "Could not resolve symbol bad_reference", errors.get(0).getFirst());
 2339   
 2340    //if rhs is a PackageData, give an error and return null
 2341  1 assertEquals("Should return null", null, _etc.forNumericAssignmentExpressionOnly(nae, SymbolData.INT_TYPE, pd));
 2342  1 assertEquals("Should still be 1 error", 1, errors.size()); // Generated duplicate error message
 2343  1 assertEquals("Error message should be correct", "Could not resolve symbol bad_reference", errors.get(0).getFirst());
 2344   
 2345    //if lhs not an instance data, give error
 2346  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), _etc.forNumericAssignmentExpressionOnly(nae, SymbolData.INT_TYPE, SymbolData.CHAR_TYPE.getInstanceData()));
 2347  1 assertEquals("Should be 2 errors", 2, errors.size()); // Generated a duplicate error message
 2348  1 assertEquals("Error message should be correct",
 2349    "You cannot use a numeric assignment (-=, %=, *=, /=) on the type int. Perhaps you meant to create " +
 2350    "a new instance of int",
 2351    errors.get(1).getFirst());
 2352    // if rhs not instance data, give error
 2353  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), _etc.forNumericAssignmentExpressionOnly(nae, SymbolData.INT_TYPE.getInstanceData(), SymbolData.CHAR_TYPE));
 2354  1 assertEquals("Should now be 3 errors", 3, errors.size());
 2355  1 assertEquals("Error message should be correct",
 2356    "You cannot use the type name char on the left hand side of a numeric assignment (-=, %=, *=, /=)." +
 2357    " Perhaps you meant to create a new instance of char",
 2358    errors.get(2).getFirst());
 2359   
 2360    //if lhs not a number type, give error
 2361  1 assertEquals("Should return sd2 instance", _sd2.getInstanceData(),
 2362    _etc.forNumericAssignmentExpressionOnly(nae, _sd2.getInstanceData(),
 2363    SymbolData.CHAR_TYPE.getInstanceData()));
 2364  1 assertEquals("Should now be 4 errors", 4, errors.size());
 2365  1 assertEquals("Error message should be correct",
 2366    "The left side of this expression is not a number. Therefore, you cannot apply " +
 2367    "a numeric assignment (-=, %=, *=, /=) to it",
 2368    errors.get(3).getFirst());
 2369   
 2370    //if rhs is not a number type, give error
 2371  1 assertEquals("Should return int instance",
 2372    SymbolData.INT_TYPE.getInstanceData(),
 2373    _etc.forNumericAssignmentExpressionOnly(nae,
 2374    SymbolData.INT_TYPE.getInstanceData(),
 2375    _sd2.getInstanceData()));
 2376  1 assertEquals("Should still be 5 errors", 5, errors.size()); // Generated a duplicate error message
 2377  1 assertEquals("Error message should be correct",
 2378    "The right side of this expression is not a number. Therefore, you cannot apply " +
 2379    "a numeric assignment (-=, %=, *=, /=) to it",
 2380    errors.get(4).getFirst());
 2381   
 2382    //if rhs is not assignable to lhs, give error
 2383  1 assertEquals("Should return int instance",
 2384    SymbolData.INT_TYPE.getInstanceData(),
 2385    _etc.forNumericAssignmentExpressionOnly(nae,
 2386    SymbolData.INT_TYPE.getInstanceData(),
 2387    SymbolData.DOUBLE_TYPE.getInstanceData()));
 2388  1 assertEquals("Should be 6 errors", 6, errors.size());
 2389  1 assertEquals("Error message should be correct",
 2390    "You cannot use a numeric assignment (-=, %=, *=, /=) on something of type int with something of " +
 2391    "type double",
 2392    errors.get(5).getFirst());
 2393    }
 2394   
 2395   
 2396  1 public void testForShiftAssignmentExpressionOnly() {
 2397  1 ShiftAssignmentExpression sae = new LeftShiftAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")), new IntegerLiteral(SourceInfo.NONE, 2));
 2398  1 try {
 2399  1 _etc.forShiftAssignmentExpressionOnly(sae, _sd1, _sd2);
 2400  0 fail("forShiftAssignmentExpressionOnly should have thrown a runtime exception");
 2401    }
 2402    catch (RuntimeException e) {
 2403  1 assertEquals("Exception message should be correct", "Internal Program Error: Shift assignment operators are not supported. This should have been caught before the TypeChecker. Please report this bug.", e.getMessage());
 2404    }
 2405    }
 2406   
 2407  1 public void testForBitwiseAssignmentExpressionOnly() {
 2408  1 BitwiseAssignmentExpression bae = new BitwiseXorAssignmentExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")), new IntegerLiteral(SourceInfo.NONE, 2));
 2409  1 try {
 2410  1 _etc.forBitwiseAssignmentExpressionOnly(bae, _sd1, _sd2);
 2411  0 fail("forBitwiseAssignmentExpressionOnly should have thrown a runtime exception");
 2412    }
 2413    catch (RuntimeException e) {
 2414  1 assertEquals("Exception message should be correct", "Internal Program Error: Bitwise assignment operators are not supported. This should have been caught before the TypeChecker. Please report this bug.", e.getMessage());
 2415    }
 2416    }
 2417   
 2418   
 2419  1 public void testForBooleanExpressionOnly() {
 2420  1 BooleanExpression be = new OrExpression(SourceInfo.NONE, new BooleanLiteral(SourceInfo.NONE, true), new BooleanLiteral(SourceInfo.NONE, false));
 2421   
 2422    //if both left and right are boolean instance types, everything is good
 2423   
 2424  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), _etc.forBooleanExpressionOnly(be, SymbolData.BOOLEAN_TYPE.getInstanceData(), SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2425  1 assertEquals("There should be no errors", 0, errors.size());
 2426   
 2427    //if the left type is not an instance type, give an error
 2428  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), _etc.forBooleanExpressionOnly(be, SymbolData.BOOLEAN_TYPE, SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2429  1 assertEquals("There should now be 1 error", 1, errors.size());
 2430  1 assertEquals("The error message should be correct", "The left side of this expression is a type, not an instance. Perhaps you meant to create a new instance of boolean", errors.getLast().getFirst());
 2431   
 2432    //if the left type is an instance type but not a boolean type, give an error
 2433  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), _etc.forBooleanExpressionOnly(be, SymbolData.INT_TYPE.getInstanceData(), SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2434  1 assertEquals("There should now be 2 errors", 2, errors.size());
 2435  1 assertEquals("The error message should be correct", "The left side of this expression is not a boolean value. Therefore, you cannot apply a Boolean Operator (&&, ||) to it", errors.getLast().getFirst());
 2436   
 2437    //if the right type is not an instance type, give an error
 2438  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), _etc.forBooleanExpressionOnly(be, SymbolData.BOOLEAN_TYPE.getInstanceData(), SymbolData.BOOLEAN_TYPE));
 2439  1 assertEquals("There should now be 3 errors", 3, errors.size());
 2440  1 assertEquals("The error message should be correct", "The right side of this expression is a type, not an instance. Perhaps you meant to create a new instance of boolean", errors.getLast().getFirst());
 2441   
 2442    //if the right type is an instance type but not a boolean give an error
 2443  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), _etc.forBooleanExpressionOnly(be, SymbolData.BOOLEAN_TYPE.getInstanceData(), SymbolData.DOUBLE_TYPE.getInstanceData()));
 2444  1 assertEquals("There should now be 4 errors", 4, errors.size());
 2445  1 assertEquals("The error message should be correct",
 2446    "The right side of this expression is not a boolean value. Therefore, you cannot apply a Boolean Operator (&&, ||) to it", errors.getLast().getFirst());
 2447   
 2448    }
 2449   
 2450  1 public void testForBitwiseBinaryExpressionOnly() {
 2451  1 BitwiseBinaryExpression bbe =
 2452    new BitwiseAndExpression(SourceInfo.NONE,
 2453    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
 2454    new IntegerLiteral(SourceInfo.NONE, 2));
 2455  1 try {
 2456  1 _etc.forBitwiseBinaryExpressionOnly(bbe, _sd2, _sd3);
 2457  0 fail("forBitwiseBinaryExpressionOnly should have thrown a runtime exception");
 2458    }
 2459    catch (RuntimeException e) {
 2460  1 assertEquals("Exception message should be correct",
 2461    "Internal Program Error: Bitwise operators are not supported. This should have been caught "
 2462    + "before the TypeChecker. Please report this bug.", e.getMessage());
 2463    }
 2464    }
 2465   
 2466   
 2467  1 public void testForEqualityExpressionOnly() {
 2468  1 EqualityExpression ee = new EqualsExpression(SourceInfo.NONE, NULL_LITERAL, NULL_LITERAL);
 2469   
 2470    //left and right are both primitive and both boolean type--should work
 2471  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2472    _etc.forEqualityExpressionOnly(ee, SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2473    SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2474  1 assertEquals("Should be no errors", 0, errors.size());
 2475   
 2476    //left and right are both primitive and both int type--should work
 2477  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2478    _etc.forEqualityExpressionOnly(ee, SymbolData.INT_TYPE.getInstanceData(),
 2479    SymbolData.INT_TYPE.getInstanceData()));
 2480  1 assertEquals("Should be no errors", 0, errors.size());
 2481   
 2482   
 2483    //left and right are both number types, only left is primitive--should work
 2484  1 SymbolData integer = new SymbolData("java.lang.Integer");
 2485  1 integer.setIsContinuation(false);
 2486  1 symbolTable.put("java.lang.Integer", integer);
 2487   
 2488  1 SymbolData bool = new SymbolData("java.lang.Boolean");
 2489  1 bool.setIsContinuation(false);
 2490  1 symbolTable.put("java.lang.Boolean", bool);
 2491   
 2492  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2493    _etc.forEqualityExpressionOnly(ee, SymbolData.INT_TYPE.getInstanceData(), integer.getInstanceData()));
 2494  1 assertEquals("Should be no errors", 0, errors.size());
 2495   
 2496    //left and right are both number types, only right is primitive--should work
 2497  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2498    _etc.forEqualityExpressionOnly(ee, integer.getInstanceData(), SymbolData.INT_TYPE.getInstanceData()));
 2499  1 assertEquals("Should be no errors", 0, errors.size());
 2500   
 2501    //left and right are both boolean types, only left is primitive--should work
 2502  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2503    _etc.forEqualityExpressionOnly(ee, SymbolData.BOOLEAN_TYPE.getInstanceData(), bool.getInstanceData()));
 2504  1 assertEquals("Should be no errors", 0, errors.size());
 2505   
 2506    //left and right are both boolean types, only right is primitive--should work
 2507  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2508    _etc.forEqualityExpressionOnly(ee, bool.getInstanceData(), SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2509  1 assertEquals("Should be no errors", 0, errors.size());
 2510   
 2511   
 2512    //left and right are both instances of reference types--should work
 2513  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2514    _etc.forEqualityExpressionOnly(ee, _sd1.getInstanceData(), _sd2.getInstanceData()));
 2515  1 assertEquals("Should be no errors", 0, errors.size());
 2516   
 2517    //left and right are both primitive, but one is int and one is boolean--does not work
 2518  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2519    _etc.forEqualityExpressionOnly(ee, SymbolData.INT_TYPE.getInstanceData(),
 2520    SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2521  1 assertEquals("Should be 1 error", 1, errors.size());
 2522  1 assertEquals("Error message should be correct",
 2523    "At least one of the arguments to this Equality Operator (==, !=) is primitive. Therefore, "
 2524    + "they must either both be number types or both be boolean types. You have specified "
 2525    + "expressions with type int and boolean",
 2526    errors.getLast().getFirst());
 2527   
 2528    //left is primitive, right is not, not both number types--does not work
 2529  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), _etc.forEqualityExpressionOnly(ee, SymbolData.INT_TYPE.getInstanceData(), _sd1.getInstanceData()));
 2530  1 assertEquals("There should now be 2 errors", 2, errors.size());
 2531  1 assertEquals("Error message should be correct",
 2532    "At least one of the arguments to this Equality Operator (==, !=) is primitive. Therefore, "
 2533    + "they must either both be number types or both be boolean types. You have specified "
 2534    + "expressions with type int and i.like.monkey", errors.getLast().getFirst());
 2535   
 2536    //left is not primitive, right is, not both primitives--does not work
 2537  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2538    _etc.forEqualityExpressionOnly(ee, _sd1.getInstanceData(), SymbolData.INT_TYPE.getInstanceData()));
 2539  1 assertEquals("There should now be 3 errors", 3, errors.size());
 2540  1 assertEquals("Error message should be correct",
 2541    "At least one of the arguments to this Equality Operator (==, !=) is primitive. Therefore, they "
 2542    + "must either both be number types or both be boolean types. You have specified expressions "
 2543    + "with type i.like.monkey and int",
 2544    errors.getLast().getFirst());
 2545   
 2546    //neither left nor right are primitive, but left side not an instance type
 2547  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2548    _etc.forEqualityExpressionOnly(ee, _sd1, _sd2.getInstanceData()));
 2549  1 assertEquals("There should now be 4 errors", 4, errors.size());
 2550  1 assertEquals("Error message should be correct",
 2551    "The arguments to this Equality Operator(==, !=) must both be instances. Instead, you have "
 2552    +"referenced a type name on the left side. Perhaps you meant to create a new instance of " +
 2553    _sd1.getName(),
 2554    errors.getLast().getFirst());
 2555   
 2556    //neither left nor right are primitive, but right side not an instance type
 2557  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2558    _etc.forEqualityExpressionOnly(ee, _sd1.getInstanceData(), _sd2));
 2559  1 assertEquals("There should now be 5 errors", 5, errors.size());
 2560  1 assertEquals("Error message should be correct", "The arguments to this Equality Operator(==, !=) must both "
 2561    + "be instances. Instead, you have referenced a type name on the right side. Perhaps you "
 2562    + "meant to create a new instance of " + _sd2.getName(),
 2563    errors.getLast().getFirst());
 2564    }
 2565   
 2566  1 public void testForComparisonExpressionOnly() {
 2567  1 ComparisonExpression ce = new LessThanExpression(SourceInfo.NONE, NULL_LITERAL, NULL_LITERAL);
 2568   
 2569    //does not throw an error if both expressions are numbers and instance types
 2570  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2571    _etc.forComparisonExpressionOnly(ce, SymbolData.DOUBLE_TYPE.getInstanceData(),
 2572    SymbolData.INT_TYPE.getInstanceData()));
 2573  1 assertEquals("There should be no errors", 0, errors.size());
 2574   
 2575    //gives an error if left side is not a number
 2576  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2577    _etc.forComparisonExpressionOnly(ce, SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2578    SymbolData.INT_TYPE.getInstanceData()));
 2579  1 assertEquals("There should be one error", 1, errors.size());
 2580  1 assertEquals("Error message should be correct",
 2581    "The left side of this expression is not a number. Therefore, you cannot apply a Comparison "
 2582    + "Operator (<, >; <=, >=) to it",
 2583    errors.getLast().getFirst());
 2584   
 2585    //gives an error if left side is not an instance type
 2586  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2587    _etc.forComparisonExpressionOnly(ce, SymbolData.DOUBLE_TYPE, SymbolData.INT_TYPE.getInstanceData()));
 2588  1 assertEquals("There should be two errors", 2, errors.size());
 2589  1 assertEquals("Error message should be correct",
 2590    "The left side of this expression is a type, not an instance. Perhaps you meant to create a "
 2591    + "new instance of double",
 2592    errors.getLast().getFirst());
 2593   
 2594    //gives an error if right side is not a number
 2595  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2596    _etc.forComparisonExpressionOnly(ce, SymbolData.DOUBLE_TYPE.getInstanceData(),
 2597    _sd1.getInstanceData()));
 2598  1 assertEquals("There should be three errors", 3, errors.size());
 2599  1 assertEquals("Error message should be correct",
 2600    "The right side of this expression is not a number. Therefore, you cannot apply a Comparison "
 2601    + "Operator (<, >; <=, >=) to it",
 2602    errors.getLast().getFirst());
 2603   
 2604    // Gives an error if right side is not an instance type
 2605  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2606    _etc.forComparisonExpressionOnly(ce, SymbolData.DOUBLE_TYPE.getInstanceData(), SymbolData.INT_TYPE));
 2607  1 assertEquals("There should be four errors", 4, errors.size());
 2608  1 assertEquals("Error message should be correct", "The right side of this expression is a type, not an instance. "
 2609    + "Perhaps you meant to create a new instance of int",
 2610    errors.getLast().getFirst());
 2611    }
 2612   
 2613   
 2614  1 public void testForShiftBinaryExpressionOnly() {
 2615  1 ShiftBinaryExpression sbe =
 2616    new LeftShiftExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "j")),
 2617    new IntegerLiteral(SourceInfo.NONE, 42));
 2618  1 try {
 2619  1 _etc.forShiftBinaryExpressionOnly(sbe, _sd2, _sd3);
 2620  0 fail("forShiftBinaryExpressionOnly should have thrown a runtime exception");
 2621    }
 2622    catch (RuntimeException e) {
 2623  1 assertEquals("Exception message should be correct",
 2624    "Internal Program Error: BinaryShifts are not supported. This should have been caught before "
 2625    + "the TypeChecker. Please report this bug.", e.getMessage());
 2626    }
 2627    }
 2628   
 2629   
 2630  1 public void testForPlusExpressionOnly() {
 2631  1 PlusExpression pe = new PlusExpression(SourceInfo.NONE, NULL_LITERAL, NULL_LITERAL);
 2632  1 SymbolData string = new SymbolData("java.lang.String");
 2633  1 string.setPackage("java.lang");
 2634  1 string.setIsContinuation(false);
 2635  1 symbolTable.put("java.lang.String", string);
 2636   
 2637    //left side is a string instance data and right side is some other instance data
 2638  1 assertEquals("Should return String instance", string.getInstanceData(),
 2639    _etc.forPlusExpressionOnly(pe, string.getInstanceData(), _sd1.getInstanceData()));
 2640  1 assertEquals("Should be no errors", 0, errors.size());
 2641   
 2642    //right side is a string instance data and left side is some other instance data
 2643  1 assertEquals("Should return String instance", string.getInstanceData(),
 2644    _etc.forPlusExpressionOnly(pe, _sd1.getInstanceData(), string.getInstanceData()));
 2645  1 assertEquals("Should be no errors", 0, errors.size());
 2646   
 2647    //both left and right are string instance datas
 2648  1 assertEquals("Should return String instance", string.getInstanceData(),
 2649    _etc.forPlusExpressionOnly(pe, string.getInstanceData(), string.getInstanceData()));
 2650  1 assertEquals("Should be no errors", 0, errors.size());
 2651   
 2652    //both left and right are numbers
 2653  1 assertEquals("Should return Double instance", SymbolData.DOUBLE_TYPE.getInstanceData(),
 2654    _etc.forPlusExpressionOnly(pe, SymbolData.DOUBLE_TYPE.getInstanceData(),
 2655    SymbolData.INT_TYPE.getInstanceData()));
 2656  1 assertEquals("Should be no errors", 0, errors.size());
 2657   
 2658    //one side is a string instance data, but the other is not an instance data
 2659  1 assertEquals("Should return String instance", string.getInstanceData(),
 2660    _etc.forPlusExpressionOnly(pe, string.getInstanceData(), _sd1));
 2661  1 assertEquals("Should be one error", 1, errors.size());
 2662  1 assertEquals("Error message should be correct",
 2663    "The arguments to the Plus Operator (+) must both be instances, but you have specified a type "
 2664    + "name. Perhaps you meant to create a new instance of " + _sd1.getName(),
 2665    errors.getLast().getFirst());
 2666   
 2667    // One side is a string, not a string instance data
 2668  1 assertEquals("Should return String instance", string.getInstanceData(),
 2669    _etc.forPlusExpressionOnly(pe, string, string.getInstanceData()));
 2670  1 assertEquals("Should be two errors", 2, errors.size());
 2671  1 assertEquals("Error message should be correct",
 2672    "The arguments to the Plus Operator (+) must both be instances, but you have specified a type "
 2673    + "name. Perhaps you meant to create a new instance of java.lang.String",
 2674    errors.getLast().getFirst());
 2675   
 2676    // One side is a number, the other is not
 2677  1 assertEquals("Should return String instance", string.getInstanceData(),
 2678    _etc.forPlusExpressionOnly(pe, SymbolData.INT_TYPE.getInstanceData(),
 2679    SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2680  1 assertEquals("Should be three errors", 3, errors.size());
 2681  1 assertEquals("Error message should be correct",
 2682    "The arguments to the Plus Operator (+) must either include an instance of a String or both "
 2683    + "be numbers. You have specified arguments of type int and boolean",
 2684    errors.getLast().getFirst());
 2685   
 2686    //both sides are numbers, but the left side is not an instance data
 2687  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2688    _etc.forPlusExpressionOnly(pe, SymbolData.INT_TYPE, SymbolData.CHAR_TYPE.getInstanceData()));
 2689  1 assertEquals("Should be 4 errors", 4, errors.size());
 2690  1 assertEquals("Error message should be correct",
 2691    "The arguments to the Plus Operator (+) must both be instances, but you have specified a type "
 2692    + "name. Perhaps you meant to create a new instance of int",
 2693    errors.getLast().getFirst());
 2694   
 2695    // Both sides are numbers, but the right side is not an instance data
 2696  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2697    _etc.forPlusExpressionOnly(pe, SymbolData.INT_TYPE.getInstanceData(), SymbolData.CHAR_TYPE));
 2698  1 assertEquals("Should be 5 errors", 5, errors.size());
 2699  1 assertEquals("Error message should be correct",
 2700    "The arguments to the Plus Operator (+) must both be instances, but you have specified a type "
 2701    + "name. Perhaps you meant to create a new instance of char",
 2702    errors.getLast().getFirst());
 2703   
 2704   
 2705    }
 2706   
 2707   
 2708  1 public void testForNumericBinaryExpressionOnly() {
 2709  1 NumericBinaryExpression nbe = new ModExpression(SourceInfo.NONE, NULL_LITERAL, NULL_LITERAL);
 2710   
 2711    //two number instance expressions work--returns least restrictive type
 2712  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2713    _etc.forNumericBinaryExpressionOnly(nbe, SymbolData.INT_TYPE.getInstanceData(),
 2714    SymbolData.INT_TYPE.getInstanceData()));
 2715  1 assertEquals("There should be no errors", 0, errors.size());
 2716   
 2717  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2718    _etc.forNumericBinaryExpressionOnly(nbe, SymbolData.INT_TYPE.getInstanceData(),
 2719    SymbolData.CHAR_TYPE.getInstanceData()));
 2720  1 assertEquals("There should be no errors", 0, errors.size());
 2721   
 2722  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(),
 2723    _etc.forNumericBinaryExpressionOnly(nbe, SymbolData.INT_TYPE.getInstanceData(),
 2724    SymbolData.DOUBLE_TYPE.getInstanceData()));
 2725  1 assertEquals("There should be no errors", 0, errors.size());
 2726   
 2727    //left not an instance data
 2728  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(),
 2729    _etc.forNumericBinaryExpressionOnly(nbe, SymbolData.INT_TYPE,
 2730    SymbolData.DOUBLE_TYPE.getInstanceData()));
 2731  1 assertEquals("Should be 1 error", 1, errors.size());
 2732  1 assertEquals("Error message should be correct", "The left side of this expression is a type, not an instance. "
 2733    + "Perhaps you meant to create a new instance of int", errors.getLast().getFirst());
 2734   
 2735    //left not a number
 2736  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(),
 2737    _etc.forNumericBinaryExpressionOnly(nbe, SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2738    SymbolData.DOUBLE_TYPE.getInstanceData()));
 2739  1 assertEquals("Should be 2 errors", 2, errors.size());
 2740  1 assertEquals("Error message should be correct", "The left side of this expression is not a number. "
 2741    + "Therefore, you cannot apply a Numeric Binary Operator (*, /, -, %) to it",
 2742    errors.getLast().getFirst());
 2743   
 2744    // right not an instance data
 2745  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(),
 2746    _etc.forNumericBinaryExpressionOnly(nbe, SymbolData.INT_TYPE.getInstanceData(),
 2747    SymbolData.DOUBLE_TYPE));
 2748  1 assertEquals("Should be 3 errors", 3, errors.size());
 2749  1 assertEquals("Error message should be correct", "The right side of this expression is a type, not an instance. "
 2750    + "Perhaps you meant to create a new instance of double", errors.getLast().getFirst());
 2751   
 2752    // right not a number
 2753  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2754    _etc.forNumericBinaryExpressionOnly(nbe, SymbolData.INT_TYPE.getInstanceData(),
 2755    SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2756  1 assertEquals("Should be 4 errors", 4, errors.size());
 2757  1 assertEquals("Error message should be correct",
 2758    "The right side of this expression is not a number. Therefore, you cannot apply a "
 2759    + "Numeric Binary Operator (*, /, -, %) to it", errors.getLast().getFirst());
 2760    }
 2761   
 2762  1 public void testForNoOpExpressionOnly() {
 2763  1 NoOpExpression noe = new NoOpExpression(SourceInfo.NONE, NULL_LITERAL, NULL_LITERAL);
 2764  1 try {
 2765  1 _etc.forNoOpExpressionOnly(noe, null, null);
 2766  0 fail("Should have thrown runtime exception");
 2767    }
 2768    catch (RuntimeException e) {
 2769  1 assertEquals("Error message should be correct", "Internal Program Error: The student is missing an operator. This should have been caught before the TypeChecker. Please report this bug.", e.getMessage());
 2770    }
 2771    }
 2772   
 2773  1 public void testForIncrementExpressionOnly() {
 2774  1 IncrementExpression ie =
 2775    new PositivePrefixIncrementExpression(SourceInfo.NONE,
 2776    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "i")));
 2777   
 2778    //if value result is a number instance, should work fine
 2779  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2780    _etc.forIncrementExpressionOnly(ie, SymbolData.INT_TYPE.getInstanceData()));
 2781  1 assertEquals("Should be no errors", 0, errors.size());
 2782   
 2783   
 2784    //if valueRes is null, return null but do not give error
 2785  1 assertEquals("Should return null", null, _etc.forIncrementExpressionOnly(ie, null));
 2786  1 assertEquals("Should be no errors", 0, errors.size());
 2787   
 2788    //if valueRes is PackageData, give error and return null
 2789  1 PackageData pd = new PackageData("bad_reference");
 2790  1 assertEquals("Should return null", null, _etc.forIncrementExpressionOnly(ie, pd));
 2791  1 assertEquals("Should be 1 error", 1, errors.size());
 2792  1 assertEquals("Error message should be correct", "Could not resolve symbol bad_reference", errors.getLast().getFirst());
 2793   
 2794    // if valueRes is not an instance type, give an error
 2795  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2796    _etc.forIncrementExpressionOnly(ie, SymbolData.INT_TYPE));
 2797  1 assertEquals("Should be 2 errors", 2, errors.size());
 2798  1 assertEquals("Error message should be correct",
 2799    "You cannot increment or decrement int, because it is a class name not an instance. "
 2800    + "Perhaps you meant to create a new instance of int", errors.getLast().getFirst());
 2801   
 2802    // if value result is not a number type, give an error
 2803  1 assertEquals("Should return sd2 instance", _sd2.getInstanceData(),
 2804    _etc.forIncrementExpressionOnly(ie, _sd2.getInstanceData()));
 2805  1 assertEquals("Should be 3 errors", 3, errors.size());
 2806  1 assertEquals("Error message should be correct",
 2807    "You cannot increment or decrement something that is not a number type. You have specified "
 2808    + "something of type " + _sd2.getName(),
 2809    errors.getLast().getFirst());
 2810    }
 2811   
 2812   
 2813   
 2814  1 public void testForNumericUnaryExpressionOnly() {
 2815  1 NumericUnaryExpression nue = new PositiveExpression(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5));
 2816    //number types like char and byte should be widened to int
 2817  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2818    _etc.forNumericUnaryExpressionOnly(nue, SymbolData.CHAR_TYPE.getInstanceData()));
 2819  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2820    _etc.forNumericUnaryExpressionOnly(nue, SymbolData.BYTE_TYPE.getInstanceData()));
 2821  1 assertEquals("There should be no errors", 0, errors.size());
 2822   
 2823    //double type should be kept the same
 2824  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(),
 2825    _etc.forNumericUnaryExpressionOnly(nue, SymbolData.DOUBLE_TYPE.getInstanceData()));
 2826  1 assertEquals("There should be no errors", 0, errors.size());
 2827   
 2828    //not an instance type
 2829  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 2830    _etc.forNumericUnaryExpressionOnly(nue, SymbolData.INT_TYPE));
 2831  1 assertEquals("Should be one error", 1, errors.size());
 2832  1 assertEquals("Error message should be correct",
 2833    "You cannot use a numeric unary operator (+, -) with int, because it is a class name, "
 2834    + "not an instance. Perhaps you meant to create a new instance of int",
 2835    errors.getLast().getFirst());
 2836   
 2837    //not a number type
 2838  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2839    _etc.forNumericUnaryExpressionOnly(nue, SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2840  1 assertEquals("Should be 2 errors", 2, errors.size());
 2841  1 assertEquals("Error message should be correct",
 2842    "You cannot apply this unary operator to something of type boolean. You can only apply it "
 2843    + "to a numeric type such as double, int, or char", errors.getLast().getFirst());
 2844    }
 2845   
 2846  1 public void testForBitwiseNotExpressionOnly() {
 2847  1 BitwiseNotExpression bne =
 2848    new BitwiseNotExpression(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "t")));
 2849  1 try {
 2850  1 _etc.forBitwiseNotExpressionOnly(bne, _sd3);
 2851  0 fail("forBitwiseNotExpressionOnly should have thrown a runtime exception");
 2852    }
 2853    catch (RuntimeException e) {
 2854  1 assertEquals("Exception message should be correct", "Internal Program Error: BitwiseNot is not supported. It should have been caught before getting to the TypeChecker. Please report this bug.", e.getMessage());
 2855    }
 2856    }
 2857   
 2858   
 2859  1 public void testForNotExpressionOnly() {
 2860  1 NotExpression ne = new NotExpression(SourceInfo.NONE, NULL_LITERAL);
 2861   
 2862    //should work with a boolean instance
 2863  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2864    _etc.forNotExpressionOnly(ne, SymbolData.BOOLEAN_TYPE.getInstanceData()));
 2865  1 assertEquals("Should be no errors", 0, errors.size());
 2866   
 2867    //not an instance type
 2868  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2869    _etc.forNotExpressionOnly(ne, SymbolData.BOOLEAN_TYPE));
 2870  1 assertEquals("Should be one error", 1, errors.size());
 2871  1 assertEquals("Error message should be correct",
 2872    "You cannot use the not (!) operator with boolean, because it is a class name, not an instance. "
 2873    + "Perhaps you meant to create a new instance of boolean", errors.getLast().getFirst());
 2874   
 2875    //not a boolean type
 2876  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 2877    _etc.forNotExpressionOnly(ne, SymbolData.INT_TYPE.getInstanceData()));
 2878  1 assertEquals("Should be two errors", 2, errors.size());
 2879  1 assertEquals("Error message should be correct",
 2880    "You cannot use the not (!) operator with something of type int. Instead, it should be used "
 2881    + "with an expression of boolean type", errors.getLast().getFirst());
 2882    }
 2883   
 2884   
 2885  1 public void testForConditionalExpressionOnly() {
 2886  1 SymbolData sd1 = SymbolData.DOUBLE_TYPE;
 2887  1 SymbolData sd2 = SymbolData.BOOLEAN_TYPE;
 2888  1 SymbolData sd3 = SymbolData.INT_TYPE;
 2889  1 ConditionalExpression cd = new ConditionalExpression(SourceInfo.NONE,
 2890    new BooleanLiteral(SourceInfo.NONE, true),
 2891    new IntegerLiteral(SourceInfo.NONE, 5),
 2892    new IntegerLiteral(SourceInfo.NONE, 79));
 2893   
 2894  1 try {
 2895  1 _etc.forConditionalExpressionOnly(cd, _sd3, _sd2, _sd1);
 2896  0 fail("Should have thrown an exception.");
 2897    }
 2898    catch (Exception e) {
 2899  1 assertEquals("Exception message should be correct",
 2900    "Internal Program Error: Conditional expressions are not supported. This should have been "
 2901    + "caught before the TypeChecker. Please report this bug.", e.getMessage());
 2902   
 2903    }
 2904    }
 2905   
 2906  1 public void testForInstanceOfExpressionOnly() {
 2907  1 SymbolData sd1 = SymbolData.DOUBLE_TYPE;
 2908  1 SymbolData sd2 = SymbolData.BOOLEAN_TYPE;
 2909  1 SymbolData sd3 = SymbolData.INT_TYPE;
 2910  1 InstanceofExpression ioe = new InstanceofExpression(SourceInfo.NONE, NULL_LITERAL, JExprParser.NO_TYPE);
 2911  1 assertEquals("When valueRes is subtype of typeRes, return BOOLEAN typeRes.", sd2.getInstanceData(),
 2912    _etc.forInstanceofExpressionOnly(ioe, sd1, sd3.getInstanceData()));
 2913  1 assertEquals("Should not throw an error.", 0, errors.size());
 2914  1 assertEquals("When typeRes is subtype of valueRes, return BOOLEAN typeRes.", sd2.getInstanceData(),
 2915    _etc.forInstanceofExpressionOnly(ioe, sd3, sd1.getInstanceData()));
 2916  1 assertEquals("Should not throw an error.", 0, errors.size());
 2917  1 assertEquals("When typeRes and valueRes are not subtypes of each other, return BOOLEAN typeRes",
 2918    sd2.getInstanceData(),
 2919    _etc.forInstanceofExpressionOnly(ioe, sd2, sd1.getInstanceData()));
 2920  1 assertEquals("Should now be one error.", 1, errors.size());
 2921  1 assertEquals("Error message should be correct.", "You cannot test whether an expression of type " + sd1.getName()
 2922    + " belongs to type " + sd2.getName() + " because they are not related",
 2923    errors.getLast().getFirst());
 2924  1 SymbolData foo = new SymbolData("Foo");
 2925  1 SymbolData fooMama = new SymbolData("FooMama");
 2926  1 foo.setSuperClass(fooMama);
 2927  1 assertEquals("When valueRes is a SymbolData, return BOOLEAN typeRes", sd2.getInstanceData(),
 2928    _etc.forInstanceofExpressionOnly(ioe, foo, fooMama));
 2929  1 assertEquals("There should be 2 errors.", 2, errors.size());
 2930  1 assertEquals("Error message should be correct.",
 2931    "You are trying to test if FooMama belongs to type, but it is a class or interface type, "
 2932    + "not an instance. Perhaps you meant to create a new instance of FooMama",
 2933    errors.getLast().getFirst());
 2934    }
 2935   
 2936  1 public void testClassInstantiationHelper() {
 2937  1 ClassInstantiation simpleCI =
 2938    new SimpleNamedClassInstantiation(SourceInfo.NONE,
 2939    new ClassOrInterfaceType(SourceInfo.NONE, "testClass", new Type[0]),
 2940    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 2941  1 ClassInstantiation complexCI =
 2942    new ComplexNamedClassInstantiation(SourceInfo.NONE,
 2943    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Outer")),
 2944    new ClassOrInterfaceType(SourceInfo.NONE, "Inner", new Type[0]),
 2945    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 2946   
 2947  1 ParenthesizedExpressionList pel =
 2948    new ParenthesizedExpressionList(SourceInfo.NONE,
 2949    new Expression[] {new SimpleNameReference(SourceInfo.NONE,
 2950    new Word(SourceInfo.NONE, "int"))});
 2951  1 ClassInstantiation badArgs =
 2952    new SimpleNamedClassInstantiation(SourceInfo.NONE,
 2953    new ClassOrInterfaceType(SourceInfo.NONE, "anotherClass", new Type[0]),
 2954    pel);
 2955   
 2956  1 SymbolData testClass = new SymbolData("testClass");
 2957  1 SymbolData outer = new SymbolData("Outer");
 2958  1 SymbolData outerInner = new SymbolData("Outer.Inner");
 2959  1 outer.addInnerClass(outerInner);
 2960  1 outerInner.setOuterData(outer);
 2961   
 2962    //classToInstantiate==null
 2963  1 assertEquals("Should return null", null, _etc.classInstantiationHelper(simpleCI, null));
 2964  1 assertEquals("Should be no errors", 0, errors.size());
 2965   
 2966   
 2967    //if arg is a type instead of an instance, throw an error
 2968  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(),
 2969    _etc.classInstantiationHelper(badArgs, SymbolData.DOUBLE_TYPE));
 2970  1 assertEquals("Should be one error", 1, errors.size());
 2971  1 assertEquals("Error message should be correct",
 2972    "Cannot pass a class or interface name as a constructor argument. Perhaps you meant to create a "
 2973    + "new instance of int", errors.getLast().getFirst());
 2974   
 2975    //if no matching constructor, give error
 2976  1 assertEquals("Should return instance of testClass", testClass.getInstanceData(),
 2977    _etc.classInstantiationHelper(simpleCI, testClass));
 2978  1 assertEquals("Should be two errors", 2, errors.size());
 2979  1 assertEquals("Error message should be correct",
 2980    "No constructor found in class testClass with signature: testClass().", errors.getLast().getFirst());
 2981   
 2982  1 assertEquals("Should return instance of Outer.Inner", outerInner.getInstanceData(),
 2983    _etc.classInstantiationHelper(complexCI, outerInner));
 2984  1 assertEquals("Should be three errors", 3, errors.size());
 2985  1 assertEquals("Error message should be correct",
 2986    "No constructor found in class Outer.Inner with signature: Inner().", errors.getLast().getFirst());
 2987   
 2988   
 2989    // if everything is in order, just return
 2990  1 MethodData md = new MethodData("testClass", _publicMav, new TypeParameter[0], testClass,
 2991    new VariableData[0],
 2992    new String[0],
 2993    testClass,
 2994    null);
 2995  1 testClass.addMethod(md);
 2996  1 assertEquals("Should return instance of testClass", testClass.getInstanceData(),
 2997    _etc.classInstantiationHelper(simpleCI, testClass));
 2998  1 assertEquals("Should still be just three errors", 3, errors.size());
 2999    }
 3000   
 3001   
 3002  1 public void testForSimpleNamedClassInstantiation() {
 3003  1 ParenthesizedExpressionList pel1 =
 3004    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new IntegerLiteral(SourceInfo.NONE, 5)});
 3005  1 SimpleNamedClassInstantiation ci1 =
 3006    new SimpleNamedClassInstantiation(SourceInfo.NONE,
 3007    new ClassOrInterfaceType(SourceInfo.NONE, "simpleClass", new Type[0]),
 3008    pel1);
 3009  1 SimpleNamedClassInstantiation ci3 =
 3010    new SimpleNamedClassInstantiation(SourceInfo.NONE,
 3011    new ClassOrInterfaceType(SourceInfo.NONE, "simpleClass", new Type[0]),
 3012    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 3013   
 3014    // if the type is not in the symbolTable, an error should be added on lookup, and null should be returned:
 3015  1 assertEquals("Should return null, since simpleClass is not in symbol table", null, ci1.visit(_etc));
 3016  1 assertEquals("Should be 1 error", 1, errors.size());
 3017  1 assertEquals("Error message should be correct", "Class or variable simpleClass not found.", errors.getLast().getFirst());
 3018   
 3019    //if class is in symbol table, but not visible from this context, should give an error but still return instance of type
 3020  1 SymbolData simpleClass = new SymbolData("simpleClass");
 3021  1 simpleClass.setIsContinuation(false);
 3022  1 MethodData cons1 = new MethodData("simpleClass", _publicMav, new TypeParameter[0], simpleClass,
 3023    new VariableData[0],
 3024    new String[0],
 3025    simpleClass,
 3026    null);
 3027  1 simpleClass.addMethod(cons1);
 3028  1 symbolTable.put("simpleClass", simpleClass);
 3029   
 3030  1 assertEquals("Should return simpleClass even though it could not really access it",
 3031    simpleClass.getInstanceData(), ci3.visit(_etc));
 3032  1 assertEquals("Should be 2 errors", 2, errors.size());
 3033  1 assertEquals("Error message should be correct",
 3034    "The class or interface simpleClass is package protected because there is no access specifier and "
 3035    + "cannot be accessed from i.like.monkey",
 3036    errors.getLast().getFirst());
 3037   
 3038    // if class is in symbol table and visible, but there is not a matching constructor, should give an error
 3039    // but still return instance of type
 3040  1 simpleClass.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 3041   
 3042  1 assertEquals("Should return simpleClass even though it could not find constructor", simpleClass.getInstanceData(),
 3043    ci1.visit(_etc));
 3044  1 assertEquals("Should be 3 errors", 3, errors.size());
 3045  1 assertEquals("Error message should be correct",
 3046    "No constructor found in class simpleClass with signature: simpleClass(int).",
 3047    errors.getLast().getFirst());
 3048   
 3049    //if class is in symbol table, and there is a matching constructor, should not give any errors
 3050  1 MethodData cons2 = new MethodData("simpleClass", _publicMav, new TypeParameter[0], simpleClass,
 3051    new VariableData[] {new VariableData(SymbolData.INT_TYPE)},
 3052    new String[0],
 3053    simpleClass,
 3054    null);
 3055  1 simpleClass.addMethod(cons2);
 3056  1 assertEquals("Should return simpleClass", simpleClass.getInstanceData(), ci1.visit(_etc));
 3057  1 assertEquals("Should still be 3 errors", 3, errors.size());
 3058   
 3059   
 3060    //if class is abstract, cannot be instantiated
 3061  1 simpleClass.addModifier("abstract");
 3062  1 assertEquals("Should return simpleClass even though it cannot really be instantiated",
 3063    simpleClass.getInstanceData(), ci1.visit(_etc));
 3064  1 assertEquals("Should be 4 errors", 4, errors.size());
 3065  1 assertEquals("Error message should be correct", "simpleClass is abstract and thus cannot be instantiated",
 3066    errors.getLast().getFirst());
 3067   
 3068   
 3069    //now, what if we are dealing with an inner class?
 3070  1 SimpleNamedClassInstantiation ci2 =
 3071    new SimpleNamedClassInstantiation(SourceInfo.NONE,
 3072    new ClassOrInterfaceType(SourceInfo.NONE, "A.B", new Type[0]),
 3073    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 3074   
 3075   
 3076  1 SymbolData a = new SymbolData("A");
 3077  1 a.setIsContinuation(false);
 3078  1 SymbolData b = new SymbolData("A$B");
 3079  1 b.setIsContinuation(false);
 3080  1 b.setOuterData(a);
 3081  1 a.addInnerClass(b);
 3082  1 MethodData consb = new MethodData("B", _publicMav, new TypeParameter[0], b,
 3083    new VariableData[0],
 3084    new String[0],
 3085    b,
 3086    null);
 3087  1 b.addMethod(consb);
 3088  1 symbolTable.put("A", a);
 3089  1 a.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 3090  1 b.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 3091   
 3092    //if inner part is not static, give error
 3093  1 assertEquals("Should return A.B", b.getInstanceData(), ci2.visit(_etc));
 3094  1 assertEquals("Should be 5 errors", 5, errors.size());
 3095  1 assertEquals("Error message should be correct",
 3096    "A.B is not a static inner class, and thus cannot be instantiated from this context. Perhaps "
 3097    +"you meant to use an instantiation of the form new A().new B()",
 3098    errors.getLast().getFirst());
 3099    //if inner part is static, no problem
 3100  1 b.addModifier("static");
 3101  1 assertEquals("Should return A.B", b.getInstanceData(), ci2.visit(_etc));
 3102  1 assertEquals("Should still be just 5 errors", 5, errors.size());
 3103    }
 3104   
 3105  1 public void testForComplexNamedClassInstantiation() {
 3106  1 ParenthesizedExpressionList pel1 =
 3107    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] { new IntegerLiteral(SourceInfo.NONE, 5)});
 3108  1 ComplexNamedClassInstantiation ci1 =
 3109    new ComplexNamedClassInstantiation(SourceInfo.NONE,
 3110    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "o")),
 3111    new ClassOrInterfaceType(SourceInfo.NONE, "innerClass", new Type[0]),
 3112    pel1);
 3113   
 3114  1 ComplexNamedClassInstantiation ci2 =
 3115    new ComplexNamedClassInstantiation(SourceInfo.NONE,
 3116    new SimpleNameReference(SourceInfo.NONE,
 3117    new Word(SourceInfo.NONE, "o")),
 3118    new ClassOrInterfaceType(SourceInfo.NONE, "innerClass", new Type[0]),
 3119    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 3120   
 3121    //if outer type is not in vars list, give appropriate error
 3122  1 assertEquals("Should return null", null, ci1.visit(_etc));
 3123  1 assertEquals("Should be 1 error", 1, errors.size());
 3124  1 assertEquals("Error message should be correct", "Could not resolve symbol o", errors.getLast().getFirst());
 3125   
 3126    // if outer class is in symbol table and visible, but there is not a matching inner constructor, should give
 3127    // an error but still return instance of type
 3128  1 SymbolData outerClass = new SymbolData("outer");
 3129  1 outerClass.setIsContinuation(false);
 3130  1 SymbolData innerClass = new SymbolData("outer$innerClass");
 3131  1 innerClass.setIsContinuation(false);
 3132  1 outerClass.addInnerClass(innerClass);
 3133  1 innerClass.setOuterData(outerClass);
 3134  1 MethodData cons1 = new MethodData("innerClass", _publicMav, new TypeParameter[0], innerClass,
 3135    new VariableData[0],
 3136    new String[0],
 3137    innerClass,
 3138    null);
 3139  1 innerClass.addMethod(cons1);
 3140  1 symbolTable.put("outer", outerClass);
 3141  1 _etc._vars.addLast(new VariableData("o", _publicMav, outerClass, true, _etc._data));
 3142  1 outerClass.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 3143  1 innerClass.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 3144   
 3145  1 assertEquals("Should return innerClass even though it could not find constructor", innerClass.getInstanceData(),
 3146    ci1.visit(_etc));
 3147  1 assertEquals("Should be 2 errors", 2, errors.size());
 3148  1 assertEquals("Error message should be correct",
 3149    "No constructor found in class outer.innerClass with signature: innerClass(int).",
 3150    errors.getLast().getFirst());
 3151   
 3152    //if class is in symbol table, and there is a matching constructor, should not give any errors
 3153  1 MethodData cons2 = new MethodData("innerClass", _publicMav, new TypeParameter[0], innerClass,
 3154    new VariableData[] {new VariableData(SymbolData.INT_TYPE)},
 3155    new String[0],
 3156    innerClass,
 3157    null);
 3158  1 innerClass.addMethod(cons2);
 3159  1 assertEquals("Should return innerClass", innerClass.getInstanceData(), ci1.visit(_etc));
 3160  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3161   
 3162    //if class is abstract, cannot be instantiated
 3163  1 innerClass.addModifier("abstract");
 3164  1 assertEquals("Should return innerClass even though it cannot really be instantiated", innerClass.getInstanceData(),
 3165    ci1.visit(_etc));
 3166  1 assertEquals("Should be 3 errors", 3, errors.size());
 3167  1 assertEquals("Error message should be correct", "outer.innerClass is abstract and thus cannot be instantiated",
 3168    errors.getLast().getFirst());
 3169   
 3170    //if enclosingType is not an instance, and result is not static, give error
 3171  1 ComplexNamedClassInstantiation ci3 =
 3172    new ComplexNamedClassInstantiation(SourceInfo.NONE,
 3173    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "outer")),
 3174    new ClassOrInterfaceType(SourceInfo.NONE, "innerClass", new Type[0]),
 3175    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 3176  1 outerClass.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 3177  1 innerClass.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 3178  1 assertEquals("Should return innerClass even though the syntax was wrong", innerClass.getInstanceData(),
 3179    ci3.visit(_etc));
 3180  1 assertEquals("Should be 4 errors", 4, errors.size());
 3181  1 assertEquals("Error message should be correct",
 3182    "The constructor of a non-static inner class can only be called on an instance of its containing "
 3183    + "class (e.g. new outer().new innerClass())",
 3184    errors.getLast().getFirst());
 3185   
 3186    //if result is static, give appropriate error:
 3187  1 innerClass.addModifier("static");
 3188  1 assertEquals("Should return innerClass even though the syntax was wrong",
 3189    innerClass.getInstanceData(), ci1.visit(_etc));
 3190  1 assertEquals("Should be 5 errors", 5, errors.size());
 3191   
 3192  1 assertEquals("Error message should be correct",
 3193    "You cannot instantiate a static inner class or interface with this syntax. Instead, "
 3194    + "try new outer.innerClass()",
 3195    errors.getLast().getFirst());
 3196   
 3197   
 3198    //if inner class of that name does not exist, give an error
 3199  1 innerClass.setMav(_publicMav);
 3200  1 ParenthesizedExpressionList pel2 =
 3201    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {new IntegerLiteral(SourceInfo.NONE, 5)});
 3202  1 ComplexNamedClassInstantiation ci4 =
 3203    new ComplexNamedClassInstantiation(SourceInfo.NONE,
 3204    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "o")),
 3205    new ClassOrInterfaceType(SourceInfo.NONE, "notInnerClass", new Type[0]),
 3206    pel2);
 3207  1 assertEquals("Should return null", null, ci4.visit(_etc));
 3208  1 assertEquals("Should be 6 errors", 6, errors.size());
 3209  1 assertEquals("Error message should be correct", "Class or variable notInnerClass not found.",
 3210    errors.getLast().getFirst());
 3211   
 3212   
 3213    //if inner class is private, give error
 3214  1 innerClass.setMav(_privateMav);
 3215  1 assertEquals("Should return inner class", innerClass.getInstanceData(), ci1.visit(_etc));
 3216  1 assertEquals("Should be 7 errors", 7, errors.size());
 3217  1 assertEquals("Error message should be correct",
 3218    "The class or interface outer.innerClass in outer.innerClass is private and cannot be accessed from i.like.monkey",
 3219    errors.getLast().getFirst());
 3220   
 3221    //if outer class is private, give error
 3222  1 outerClass.setMav(_privateMav);
 3223  1 innerClass.setMav(_publicMav);
 3224  1 assertEquals("Should return inner class", innerClass.getInstanceData(), ci1.visit(_etc));
 3225  1 assertEquals("Should be 8 errors", 8, errors.size());
 3226  1 assertEquals("Error message should be correct",
 3227    "The class or interface outer in outer is private and cannot be accessed from i.like.monkey",
 3228    errors.getLast().getFirst());
 3229    }
 3230   
 3231  1 public void testForSimpleThisConstructorInvocation() {
 3232    //this should always add an error:
 3233  1 SimpleThisConstructorInvocation stci =
 3234    new SimpleThisConstructorInvocation(SourceInfo.NONE,
 3235    new ParenthesizedExpressionList(SourceInfo.NONE,
 3236    new Expression[0]));
 3237  1 assertEquals("Should return null", null, stci.visit(_etc));
 3238  1 assertEquals("Should be 1 error", 1, errors.size());
 3239  1 assertEquals("Error message should be correct",
 3240    "This constructor invocations are only allowed as the first statement of a constructor body",
 3241    errors.getLast().getFirst());
 3242    }
 3243   
 3244  1 public void testForComplexThisConstructorInvocation() {
 3245    //this should always add an error
 3246  1 ComplexThisConstructorInvocation ctci =
 3247    new ComplexThisConstructorInvocation(SourceInfo.NONE,
 3248    new SimpleNameReference(SourceInfo.NONE,
 3249    new Word(SourceInfo.NONE, "something")),
 3250    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 3251  1 assertEquals("Should return null", null, ctci.visit(_etc));
 3252  1 assertEquals("Should be 1 error", 1, errors.size());
 3253  1 assertEquals("Error message should be correct",
 3254    "Constructor invocations of this form are never allowed",
 3255    errors.getLast().getFirst());
 3256    }
 3257   
 3258  1 public void testForSimpleNameReference() {
 3259    //first, consider the case where what we have is a variable reference:
 3260  1 SimpleNameReference var = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1"));
 3261  1 VariableData varData = new VariableData("variable1", _publicMav, SymbolData.INT_TYPE, false, _etc._data);
 3262  1 _etc._vars.add(varData);
 3263   
 3264    //in this case, it has not been initialized--should throw error
 3265  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_etc));
 3266  1 assertEquals("Should be 1 error", 1, errors.size());
 3267  1 assertEquals("Error message should be correct",
 3268    "You cannot use variable1 because it may not have been given a value",
 3269    errors.getLast().getFirst());
 3270   
 3271    // if it has been initialized, do not give an error
 3272  1 varData.gotValue();
 3273  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_etc));
 3274  1 assertEquals("Should still be 1 error", 1, errors.size());
 3275   
 3276    // if variable is non-static, but you are in static context, cannot reference it. Should give error
 3277  1 MethodData newContext =
 3278    new MethodData("method", _publicStaticMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[0],
 3279    new String[0], _sd1, NULL_LITERAL);
 3280  1 _etc._data = newContext;
 3281  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_etc));
 3282  1 assertEquals("Should be 2 errors", 2, errors.size());
 3283  1 assertEquals("Error message should be correct",
 3284    "Non-static variable or field variable1 cannot be referenced from a static context",
 3285    errors.getLast().getFirst());
 3286   
 3287    // Test reference to private local variable in a method
 3288  1 SimpleNameReference var2 = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "variable1"));
 3289  1 MethodData newContext2 =
 3290    new MethodData("method2", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[0],
 3291    new String[0], _sd1, NULL_LITERAL);
 3292  1 VariableData varData2 = new VariableData("variable2", _privateMav, SymbolData.INT_TYPE, false, newContext2);
 3293  1 newContext2.addVar(varData2);
 3294   
 3295  1 varData2.gotValue(); // Give the private variable a value
 3296  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var2.visit(_etc));
 3297  1 assertEquals("Should be still be 2 errors", 2, errors.size());
 3298   
 3299  1 _etc._data = _sd1;
 3300   
 3301    // if it is a variable of your super class, it won't be in _vars. Check this case.
 3302  1 _etc._vars = new LinkedList<VariableData>();
 3303  1 _sd1.setSuperClass(_sd2);
 3304  1 _sd2.addVar(varData);
 3305  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), var.visit(_etc));
 3306  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3307   
 3308    // now, consider the case where what we have is a class reference:
 3309  1 SimpleNameReference className = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Frog"));
 3310  1 SymbolData frog = new SymbolData("Frog");
 3311  1 frog.setIsContinuation(false);
 3312  1 symbolTable.put("Frog", frog);
 3313   
 3314    //if it is not visibile from this context, return package data
 3315  1 TypeData result = className.visit(_etc);
 3316  1 assertTrue("Result should be a PackageData since Frog is not accessible", result instanceof PackageData);
 3317  1 assertEquals("Should have correct name", "Frog", result.getName());
 3318  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3319   
 3320    // if it is visibile from this context, no error
 3321  1 frog.setMav(_publicMav);
 3322  1 assertEquals("Should return Frog", frog, className.visit(_etc));
 3323  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3324   
 3325    // Finally, if the name cannot be resolved, simply return a packageData.
 3326  1 SimpleNameReference fake = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "notRealReference"));
 3327  1 assertEquals("Should return package data", "notRealReference", (fake.visit(_etc)).getName());
 3328  1 assertEquals("Should still be just 2 errors", 2, errors.size());
 3329   
 3330    // if the reference is ambiguous (matches both an interface and a class) give an error
 3331  1 SimpleNameReference ambigRef = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "ambigThing"));
 3332   
 3333  1 SymbolData interfaceD = new SymbolData("interface");
 3334  1 interfaceD.setIsContinuation(false);
 3335  1 interfaceD.setInterface(true);
 3336  1 interfaceD.setMav(_publicMav);
 3337   
 3338  1 SymbolData classD = new SymbolData("superClass");
 3339  1 classD.setIsContinuation(false);
 3340  1 classD.setMav(_publicMav);
 3341   
 3342  1 SymbolData ambigThingI = new SymbolData("ambigThing");
 3343  1 ambigThingI.setIsContinuation(false);
 3344  1 ambigThingI.setInterface(true);
 3345  1 interfaceD.addInnerInterface(ambigThingI);
 3346  1 ambigThingI.setOuterData(interfaceD);
 3347  1 ambigThingI.setMav(_publicStaticMav);
 3348   
 3349  1 SymbolData ambigThingC = new SymbolData("ambigThing");
 3350  1 ambigThingC.setIsContinuation(false);
 3351  1 classD.addInnerClass(ambigThingC);
 3352  1 ambigThingC.setOuterData(classD);
 3353  1 ambigThingC.setMav(_publicStaticMav);
 3354   
 3355  1 _sd6.addInterface(interfaceD);
 3356  1 _sd6.setSuperClass(classD);
 3357   
 3358  1 _sd6.setMav(_publicMav);
 3359  1 _sd6.setIsContinuation(false);
 3360   
 3361  1 _etc._data = _sd6;
 3362   
 3363  1 assertEquals("Should return null", null, ambigRef.visit(_etc));
 3364  1 assertEquals("Should be 3 errors", 3, errors.size());
 3365  1 assertEquals("Error message should be correct",
 3366    "Ambiguous reference to class or interface ambigThing",
 3367    errors.getLast().getFirst());
 3368    }
 3369   
 3370   
 3371  1 public void testForComplexNameReference() {
 3372    //if lhs is a package data, we want to keep building it:
 3373   
 3374    //if whole reference is just package reference, return package data
 3375  1 ComplexNameReference ref1 =
 3376    new ComplexNameReference(SourceInfo.NONE,
 3377    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "java")),
 3378    new Word(SourceInfo.NONE, "lang"));
 3379  1 assertEquals("Should return correct package data", "java.lang", ref1.visit(_etc).getName());
 3380  1 assertEquals("Should be no errors", 0, errors.size());
 3381   
 3382    // if reference builds to a class in the symbol table, return that class
 3383  1 ComplexNameReference ref2 =
 3384    new ComplexNameReference(SourceInfo.NONE, ref1, new Word(SourceInfo.NONE, "String"));
 3385  1 assertTrue("symbol table already contains String", symbolTable.containsKey("java.lang.String"));
 3386  1 SymbolData string = symbolTable.get("java.lang.String");
 3387    // SymbolData string = new SymbolData("java.lang.String");
 3388    // string.setPackage("java.lang");
 3389    // string.setMav(_publicMav);
 3390    // string.setIsContinuation(false);
 3391    // symbolTable.put("java.lang.String", string);
 3392   
 3393  1 assertEquals("Should return string", string, ref2.visit(_etc));
 3394   
 3395  1 assertEquals("Should still be no errors", 0, errors.size());
 3396   
 3397   
 3398    //if lhs is not a package data, it gets more complicated:
 3399   
 3400    // we're referencing a variable inside of symbol data lhs:
 3401  1 VariableData myVar = new VariableData("myVar", _publicStaticMav, SymbolData.DOUBLE_TYPE, true, string);
 3402  1 string.addVar(myVar);
 3403  1 ComplexNameReference varRef1 = new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "myVar"));
 3404   
 3405    // static var from static context
 3406  1 assertEquals("Should return Double_Type instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_etc));
 3407  1 assertEquals("There should still be no errors", 0, errors.size());
 3408   
 3409    // Static uninitialized var from static context
 3410  1 myVar.lostValue();
 3411  1 assertEquals("Should return Double_Type instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_etc));
 3412  1 assertEquals("There should still be one error", 1, errors.size());
 3413  1 assertEquals("Error message should be correct",
 3414    "You cannot use myVar here, because it may not have been given a value",
 3415    errors.getLast().getFirst());
 3416   
 3417    // Non-static var--this is a static context
 3418  1 myVar.gotValue();
 3419  1 myVar.setMav(_publicMav);
 3420  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef1.visit(_etc));
 3421  1 assertEquals("Should be 2 errors", 2, errors.size());
 3422  1 assertEquals("Error message should be correct",
 3423    "Non-static variable myVar cannot be accessed from the static context java.lang.String. "
 3424    + "Perhaps you meant to instantiate an instance of java.lang.String",
 3425    errors.getLast().getFirst());
 3426   
 3427    // Non-static context, okay to reference non-static var
 3428  1 VariableData stringVar = new VariableData("s", _publicMav, string, true, _etc._data);
 3429  1 _etc._vars.add(stringVar);
 3430  1 ComplexNameReference varRef2 =
 3431    new ComplexNameReference(SourceInfo.NONE,
 3432    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")),
 3433    new Word(SourceInfo.NONE, "myVar"));
 3434  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_etc));
 3435  1 assertEquals("Should still just be 2 errors", 2, errors.size());
 3436   
 3437    // Non-static context, okay to reference private non-static var
 3438  1 VariableData privateStringVar = new VariableData("ps", _privateMav, string, true, _etc._data);
 3439  1 _etc._vars.add(privateStringVar);
 3440  1 ComplexNameReference varRef25 =
 3441    new ComplexNameReference(SourceInfo.NONE,
 3442    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "ps")),
 3443    new Word(SourceInfo.NONE, "myVar"));
 3444  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef25.visit(_etc));
 3445  1 assertEquals("Should still just be 2 errors", 2, errors.size());
 3446   
 3447    // if it is a variable of the super class, you should still be able to see it. Check this case.
 3448  1 string.setVars(new LinkedList<VariableData>());
 3449  1 string.setSuperClass(_sd2);
 3450  1 _sd2.addVar(myVar);
 3451  1 assertEquals("Should return double instance", SymbolData.DOUBLE_TYPE.getInstanceData(), varRef2.visit(_etc));
 3452  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3453   
 3454    // a complex multiple variable reference case:
 3455  1 VariableData vd1 = new VariableData("Mojo", _publicMav, SymbolData.INT_TYPE, true, _sd1); // was _publicMav
 3456  1 VariableData vd2 = new VariableData("Santa's Little Helper", _publicMav, _sd1, true, _sd2); // was _publicMav
 3457  1 VariableData vd3 = new VariableData("Snowball1", _publicMav, _sd2, true, _sd3); // was _publicMav
 3458  1 _sd3.addVar(vd3);
 3459  1 _sd2.addVar(vd2);
 3460  1 _sd1.addVar(vd1);
 3461   
 3462  1 ComplexNameReference varRef3 =
 3463    new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE,
 3464    "Snowball1")),
 3465    new Word(SourceInfo.NONE, "Santa's Little Helper"));
 3466  1 ComplexNameReference varRef4 =
 3467    new ComplexNameReference(SourceInfo.NONE, varRef3, new Word(SourceInfo.NONE, "Mojo"));
 3468   
 3469  1 Data oldData = _etc._data;
 3470  1 _etc._data = _sd3;
 3471  1 _etc._vars.add(vd3);
 3472  1 _sd3.setMav(_publicMav);
 3473  1 _sd1.setMav(_publicMav);
 3474  1 _sd2.setMav(_publicMav);
 3475   
 3476  1 TypeData result = varRef4.visit(_etc);
 3477  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), result);
 3478  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3479   
 3480  1 _etc._data = oldData;
 3481   
 3482    // What if what we have is an inner class?
 3483  1 SymbolData inner = new SymbolData("java.lang.String$Inner");
 3484  1 inner.setPackage("java.lang");
 3485  1 inner.setIsContinuation(false);
 3486  1 inner.setOuterData(string);
 3487  1 string.addInnerClass(inner);
 3488   
 3489    //if inner is not visible, throw error
 3490  1 ComplexNameReference innerRef0 =
 3491    new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE,
 3492    new Word(SourceInfo.NONE, "s")),
 3493    new Word(SourceInfo.NONE, "Inner"));
 3494  1 assertEquals("Should return null", null, innerRef0.visit(_etc));
 3495  1 assertEquals("Should be 3 errors", 3, errors.size());
 3496  1 assertEquals("Error message should be correct",
 3497    "The class or interface java.lang.String.Inner is package protected because there is no access "
 3498    + "specifier and cannot be accessed from i.like.monkey",
 3499    errors.getLast().getFirst());
 3500   
 3501  1 inner.setMav(_publicMav);
 3502   
 3503   
 3504    //if inner is not static, give error:
 3505  1 ComplexNameReference innerRef1 =
 3506    new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "Inner"));
 3507  1 assertEquals("Should return inner", inner, innerRef1.visit(_etc));
 3508  1 assertEquals("Should be 4 errors", 4, errors.size());
 3509  1 assertEquals("Error message should be correct",
 3510    "Non-static inner class java.lang.String.Inner cannot be accessed from this context. "
 3511    + "Perhaps you meant to instantiate it", errors.getLast().getFirst());
 3512   
 3513    //if inner is not static and outer is not static, it's okay...
 3514  1 ComplexNameReference innerRef2 =
 3515    new ComplexNameReference(SourceInfo.NONE,
 3516    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s")),
 3517    new Word(SourceInfo.NONE, "Inner"));
 3518  1 assertEquals("Should return inner", inner, innerRef2.visit(_etc));
 3519  1 assertEquals("Should still be 5 errors", 5, errors.size());
 3520  1 assertEquals("Error message should be correct",
 3521    "Non-static inner class java.lang.String.Inner cannot be accessed from this context. "
 3522    + "Perhaps you meant to instantiate it",
 3523    errors.getLast().getFirst());
 3524   
 3525    //if inner is static and outer is not static, throw error
 3526  1 inner.setMav(_publicStaticMav);
 3527  1 assertEquals("Should return inner", inner, innerRef2.visit(_etc));
 3528  1 assertEquals("Should be 6 errors", 6, errors.size());
 3529  1 assertEquals("Error message should be correct",
 3530    "You cannot reference the static inner class java.lang.String.Inner from an instance of "
 3531    + "java.lang.String. Perhaps you meant to say java.lang.String.Inner",
 3532    errors.getLast().getFirst());
 3533   
 3534   
 3535    //if the symbol could not be matched, give an error and return null
 3536  1 ComplexNameReference noSense =
 3537    new ComplexNameReference(SourceInfo.NONE, ref2, new Word(SourceInfo.NONE, "nonsense"));
 3538  1 assertEquals("Should return null", null, noSense.visit(_etc));
 3539  1 assertEquals("Should be 7 errors", 7, errors.size());
 3540  1 assertEquals("Error message should be correct", "Could not resolve nonsense from the context of java.lang.String",
 3541    errors.getLast().getFirst());
 3542   
 3543    //if the reference is ambiguous (matches both an interface and a class) give an error
 3544  1 ComplexNameReference ambigRef =
 3545    new ComplexNameReference(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE,
 3546    new Word(SourceInfo.NONE, "cebu")),
 3547    new Word(SourceInfo.NONE, "ambigThing"));
 3548   
 3549  1 SymbolData interfaceD = new SymbolData("interface");
 3550  1 interfaceD.setIsContinuation(false);
 3551  1 interfaceD.setInterface(true);
 3552  1 interfaceD.setMav(_publicMav);
 3553   
 3554  1 SymbolData classD = new SymbolData("superClass");
 3555  1 classD.setIsContinuation(false);
 3556  1 classD.setMav(_publicMav);
 3557   
 3558  1 SymbolData ambigThingI = new SymbolData("ambigThing");
 3559  1 ambigThingI.setIsContinuation(false);
 3560  1 ambigThingI.setInterface(true);
 3561  1 interfaceD.addInnerInterface(ambigThingI);
 3562  1 ambigThingI.setOuterData(interfaceD);
 3563  1 ambigThingI.setMav(_publicStaticMav);
 3564   
 3565  1 SymbolData ambigThingC = new SymbolData("ambigThing");
 3566  1 ambigThingC.setIsContinuation(false);
 3567  1 classD.addInnerClass(ambigThingC);
 3568  1 ambigThingC.setOuterData(classD);
 3569  1 ambigThingC.setMav(_publicStaticMav);
 3570   
 3571  1 _sd6.addInterface(interfaceD);
 3572  1 _sd6.setSuperClass(classD);
 3573   
 3574  1 symbolTable.put("cebu", _sd6);
 3575  1 _sd6.setMav(_publicMav);
 3576  1 _sd6.setIsContinuation(false);
 3577   
 3578  1 assertEquals("Should return null", null, ambigRef.visit(_etc));
 3579  1 assertEquals("Should be 8 errors", 8, errors.size());
 3580  1 assertEquals("Error message should be correct",
 3581    "Ambiguous reference to class or interface ambigThing",
 3582    errors.getLast().getFirst());
 3583   
 3584    //if lhs is not visible or inner is not visible, should throw error
 3585  1 inner.setMav(_publicStaticMav);
 3586  1 string.setMav(_privateMav);
 3587   
 3588  1 assertEquals("Should return inner", inner, innerRef1.visit(_etc));
 3589  1 assertEquals("Should be 9 errors", 9, errors.size());
 3590  1 assertEquals("Error message should be correct",
 3591    "The class or interface java.lang.String in java.lang.String is private and cannot be accessed from i.like.monkey",
 3592    errors.getLast().getFirst());
 3593    }
 3594   
 3595   
 3596  1 public void testForSimpleThisReference() {
 3597  1 SimpleThisReference str = new SimpleThisReference(SourceInfo.NONE);
 3598   
 3599    //as long as we are not in a static method, this should be fine.
 3600  1 assertEquals("Should return i.like.monkey instance", _etc._data.getSymbolData().getInstanceData(), str.visit(_etc));
 3601  1 assertEquals("Should be no errors", 0, errors.size());
 3602   
 3603    //if we are in a static method, give appropriate error
 3604  1 MethodData sm = new MethodData("staticMethod", new VariableData[0]);
 3605  1 sm.setMav(_publicStaticMav);
 3606  1 sm.setOuterData(_etc._data);
 3607  1 _etc._data = sm;
 3608   
 3609  1 assertEquals("Should return i.like.monkey instance", _etc._data.getSymbolData().getInstanceData(),
 3610    str.visit(_etc));
 3611  1 assertEquals("Should be one errors", 1, errors.size());
 3612  1 assertEquals("Error message should be correct", "'this' cannot be referenced from within a static method",
 3613    errors.getLast().getFirst());
 3614    }
 3615   
 3616   
 3617  1 public void testForComplexThisReferenceOnly() {
 3618  1 ComplexThisReference ctr =
 3619    new ComplexThisReference(SourceInfo.NONE,
 3620    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "context")));
 3621   
 3622    // if enclosing_result is null, return null
 3623  1 assertEquals("Should return null", null, _etc.forComplexThisReferenceOnly(ctr, null));
 3624  1 assertEquals("Should be no errors", 0, errors.size());
 3625   
 3626    // if enclosing result is a PackageData, give appropriate error and return null
 3627  1 assertEquals("Should return null", null, _etc.forComplexThisReferenceOnly(ctr, new PackageData("context")));
 3628  1 assertEquals("Should be 1 error", 1, errors.size());
 3629  1 assertEquals("Error message should be correct","Could not resolve symbol context" , errors.getLast().getFirst());
 3630   
 3631    // if enclosing_result is not an outer data of the current context, give an error
 3632  1 SymbolData contextClass = new SymbolData("context");
 3633  1 contextClass.setIsContinuation(false);
 3634  1 contextClass.setMav(_publicMav);
 3635  1 assertEquals("Should return instance of this", contextClass.getInstanceData(),
 3636    _etc.forComplexThisReferenceOnly(ctr, contextClass));
 3637  1 assertEquals("Should be 2 errors", 2, errors.size());
 3638  1 assertEquals("The error message should be correct", "You cannot reference context.this from here, "
 3639    + "because context is not an outer class of i.like.monkey",
 3640    errors.getLast().getFirst());
 3641   
 3642    // if enclosing_result is an outer data of current context, everything is peachy
 3643  1 _etc._data.setOuterData(contextClass);
 3644  1 contextClass.addInnerClass(_etc._data.getSymbolData());
 3645  1 assertEquals("Should return instance of this", contextClass.getInstanceData(),
 3646    _etc.forComplexThisReferenceOnly(ctr, contextClass));
 3647  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3648   
 3649    // if we are in a static method, throw appropriate error
 3650  1 MethodData sm = new MethodData("staticMethod", new VariableData[0]);
 3651  1 sm.setMav(_publicStaticMav);
 3652  1 sm.setOuterData(_etc._data);
 3653  1 _etc._data = sm;
 3654  1 assertEquals("Should return instance of this", contextClass.getInstanceData(),
 3655    _etc.forComplexThisReferenceOnly(ctr, contextClass));
 3656  1 assertEquals("Should be 3 errors", 3, errors.size());
 3657  1 assertEquals("The error message should be correct", "'this' cannot be referenced from within a static method",
 3658    errors.getLast().getFirst());
 3659   
 3660    // if the enclosing result is an instance type, throw an error
 3661  1 _etc._data = sm.getOuterData();
 3662  1 assertEquals("Should return instance of this", contextClass.getInstanceData(),
 3663    _etc.forComplexThisReferenceOnly(ctr, contextClass.getInstanceData()));
 3664  1 assertEquals("Should be 4 errors", 4, errors.size());
 3665  1 assertEquals("The error message should be correct",
 3666    "'this' can only be referenced from a type name, but you have specified an instance of that type.",
 3667    errors.getLast().getFirst());
 3668   
 3669    //if current context is static, give an error
 3670  1 _etc._data.getSymbolData().addModifier("static");
 3671  1 assertEquals("Should return instance of this", contextClass.getInstanceData(),
 3672    _etc.forComplexThisReferenceOnly(ctr, contextClass));
 3673  1 assertEquals("Should be 5 errors", 5, errors.size());
 3674  1 assertEquals("Error message should be correct",
 3675    "You cannot reference context.this from here, because i.like.monkey or one of its enclosing "
 3676    + "classes is static. Thus, an enclosing instance of context does not exist",
 3677    errors.getLast().getFirst());
 3678    }
 3679   
 3680  1 public void testForSimpleSuperReference() {
 3681  1 SimpleSuperReference ssr = new SimpleSuperReference(SourceInfo.NONE);
 3682  1 _sd1.setSuperClass(_sd2);
 3683   
 3684    //normally, should work
 3685  1 assertEquals("Should return _sd2", _sd2.getInstanceData(), ssr.visit(_etc));
 3686  1 assertEquals("Should be no errors", 0, errors.size());
 3687   
 3688    //if within static method, add error
 3689  1 MethodData sm = new MethodData("staticMethod", new VariableData[0]);
 3690  1 sm.setMav(_publicStaticMav);
 3691  1 sm.setOuterData(_etc._data);
 3692  1 _etc._data = sm;
 3693   
 3694  1 assertEquals("Should return _sd2", _sd2.getInstanceData(), ssr.visit(_etc));
 3695  1 assertEquals("Should be 1 error", 1, errors.size());
 3696  1 assertEquals("Error message should be correct", "'super' cannot be referenced from within a static method",
 3697    errors.getLast().getFirst());
 3698    }
 3699   
 3700   
 3701  1 public void testForComplexSuperReference() {
 3702  1 ComplexSuperReference csr =
 3703    new ComplexSuperReference(SourceInfo.NONE,
 3704    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "context")));
 3705   
 3706    // if enclosing_result is null, return null
 3707  1 assertEquals("Should return null", null, _etc.forComplexSuperReferenceOnly(csr, null));
 3708  1 assertEquals("Should be no errors", 0, errors.size());
 3709   
 3710    // if enclosing result is a PackageData, give appropriate error and return null
 3711  1 assertEquals("Should return null", null, _etc.forComplexSuperReferenceOnly(csr, new PackageData("context")));
 3712  1 assertEquals("Should be 1 error", 1, errors.size());
 3713  1 assertEquals("Error message should be correct","Could not resolve symbol context" , errors.getLast().getFirst());
 3714   
 3715    // if enclosing_result is not an outer data of the current context, give an error
 3716  1 SymbolData contextClass = new SymbolData("context");
 3717  1 contextClass.setIsContinuation(false);
 3718  1 contextClass.setMav(_publicMav);
 3719  1 contextClass.setSuperClass(_sd2);
 3720  1 assertEquals("Should return instance of super", _sd2.getInstanceData(),
 3721    _etc.forComplexSuperReferenceOnly(csr, contextClass));
 3722  1 assertEquals("Should be 2 errors", 2, errors.size());
 3723  1 assertEquals("The error message should be correct",
 3724    "You cannot reference context.super from here, because context is not an outer class of i.like.monkey",
 3725    errors.getLast().getFirst());
 3726   
 3727   
 3728    // if enclosing_result is an outer data of current context, everything is peachy
 3729  1 _etc._data.setOuterData(contextClass);
 3730  1 contextClass.addInnerClass(_etc._data.getSymbolData());
 3731  1 assertEquals("Should return instance of super", _sd2.getInstanceData(),
 3732    _etc.forComplexSuperReferenceOnly(csr, contextClass));
 3733  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3734   
 3735    // if we are in a static method, throw appropriate error
 3736  1 MethodData sm = new MethodData("staticMethod", new VariableData[0]);
 3737  1 sm.setMav(_publicStaticMav);
 3738  1 sm.setOuterData(_etc._data);
 3739  1 _etc._data = sm;
 3740  1 assertEquals("Should return instance of super", _sd2.getInstanceData(),
 3741    _etc.forComplexSuperReferenceOnly(csr, contextClass));
 3742  1 assertEquals("Should be 3 errors", 3, errors.size());
 3743  1 assertEquals("The error message should be correct", "'super' cannot be referenced from within a static method",
 3744    errors.getLast().getFirst());
 3745   
 3746    // if the enclosing result is an instance type, throw an error
 3747  1 _etc._data = sm.getOuterData();
 3748  1 assertEquals("Should return instance of super", _sd2.getInstanceData(),
 3749    _etc.forComplexSuperReferenceOnly(csr, contextClass.getInstanceData()));
 3750  1 assertEquals("Should be 4 errors", 4, errors.size());
 3751  1 assertEquals("The error message should be correct", "'super' can only be referenced from a type name, "
 3752    + "but you have specified an instance of that type.",
 3753    errors.getLast().getFirst());
 3754   
 3755    // if current context is static, give an error
 3756  1 _etc._data.getSymbolData().addModifier("static");
 3757  1 assertEquals("Should return instance of super", _sd2.getInstanceData(),
 3758    _etc.forComplexSuperReferenceOnly(csr, contextClass));
 3759  1 assertEquals("Should be 5 errors", 5, errors.size());
 3760  1 assertEquals("Error message should be correct",
 3761    "You cannot reference context.super from here, because i.like.monkey or one of its enclosing "
 3762    + "classes is static. Thus, an enclosing instance of context does not exist",
 3763    errors.getLast().getFirst());
 3764    }
 3765   
 3766  1 public void testForArrayAccessOnly() {
 3767  1 ArrayAccess aa =
 3768    new ArrayAccess(SourceInfo.NONE, NULL_LITERAL, NULL_LITERAL);
 3769   
 3770  1 Hashtable<SymbolData, LanguageLevelVisitor> testNewSDs = LanguageLevelConverter._newSDs;
 3771  1 LanguageLevelVisitor testLLVisitor =
 3772    new LanguageLevelVisitor(_etc._file,
 3773    _etc._package,
 3774    null, // enclosingClassName for top level traversal
 3775    _etc._importedFiles,
 3776    _etc._importedPackages,
 3777    new HashSet<String>(),
 3778    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 3779    new LinkedList<Command>());
 3780   
 3781    //if lhs is an array, and index is an int instance, no errors
 3782  1 ArrayData ad = new ArrayData(SymbolData.INT_TYPE, testLLVisitor, SourceInfo.NONE);
 3783   
 3784  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(),
 3785    _etc.forArrayAccessOnly(aa, ad.getInstanceData(), SymbolData.INT_TYPE.getInstanceData()));
 3786  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(),
 3787    _etc.forArrayAccessOnly(aa, ad.getInstanceData(), SymbolData.CHAR_TYPE.getInstanceData()));
 3788  1 assertEquals("Should be no errors", 0, errors.size());
 3789   
 3790    //if either input is null, return null
 3791  1 assertEquals("Should return null", null, _etc.forArrayAccessOnly(aa, null, SymbolData.INT_TYPE));
 3792  1 assertEquals("Should return null", null, _etc.forArrayAccessOnly(aa, SymbolData.INT_TYPE, null));
 3793  1 assertEquals("Should be no errors", 0, errors.size());
 3794   
 3795    //if lhs is a PackageData, give error and return null
 3796  1 PackageData pd = new PackageData("bad_reference");
 3797  1 assertEquals("Should return null", null, _etc.forArrayAccessOnly(aa, pd, SymbolData.INT_TYPE));
 3798  1 assertEquals("Should be 1 error", 1, errors.size());
 3799  1 assertEquals("Error message should be correct",
 3800    "Could not resolve symbol bad_reference",
 3801    errors.getLast().getFirst());
 3802   
 3803   
 3804    //if rhs is a PackageData, give an error and return null
 3805  1 assertEquals("Should return null", null, _etc.forArrayAccessOnly(aa, SymbolData.INT_TYPE, pd));
 3806  1 assertEquals("Should still be 1 error", 1, errors.size()); // Generated a duplicate error
 3807  1 assertEquals("Error message should be correct",
 3808    "Could not resolve symbol bad_reference",
 3809    errors.getLast().getFirst());
 3810   
 3811    //if array type is not an instance data, give appropriate error:
 3812  1 assertEquals("Should return int",
 3813    SymbolData.INT_TYPE.getInstanceData(),
 3814    _etc.forArrayAccessOnly(aa, ad, SymbolData.INT_TYPE.getInstanceData()));
 3815  1 assertEquals("Should now be 2 errors", 2, errors.size());
 3816  1 assertEquals("Error message should be correct",
 3817    "You cannot access an array element of a type name. Perhaps you meant to create " +
 3818    "a new instance of int[]",
 3819    errors.get(1).getFirst());
 3820   
 3821    // if type is not an array data, give appropriate error:
 3822  1 assertEquals("Should return char", SymbolData.CHAR_TYPE.getInstanceData(),
 3823    _etc.forArrayAccessOnly(aa, SymbolData.CHAR_TYPE.getInstanceData(),
 3824    SymbolData.INT_TYPE.getInstanceData()));
 3825  1 assertEquals("Should now be 3 errors", 3, errors.size());
 3826  1 assertEquals("Error message should be correct",
 3827    "The variable referred to by this array access is a char, not an array",
 3828    errors.get(2).getFirst());
 3829   
 3830    // If the array index is not an instance type, give error
 3831  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(),
 3832    _etc.forArrayAccessOnly(aa, ad.getInstanceData(), SymbolData.INT_TYPE));
 3833  1 assertEquals("Should now be 4 errors", 4, errors.size());
 3834  1 assertEquals("Error message should be correct",
 3835    "You have used a type name in place of an array index. Perhaps you meant to create " +
 3836    "a new instance of int",
 3837    errors.get(3).getFirst());
 3838   
 3839    //If the array index is not an int, give error
 3840  1 assertEquals("should return int", SymbolData.INT_TYPE.getInstanceData(),
 3841    _etc.forArrayAccessOnly(aa, ad.getInstanceData(), SymbolData.DOUBLE_TYPE.getInstanceData()));
 3842  1 assertEquals("Should now be 5 errors", 5, errors.size());
 3843  1 assertEquals("Error message should be correct",
 3844    "You cannot reference an array element with an index of type double. Instead, you must use an int",
 3845    errors.get(4).getFirst());
 3846    }
 3847   
 3848   
 3849  1 public void testLiterals() {
 3850  1 StringLiteral sl = new StringLiteral(SourceInfo.NONE, "string literal!");
 3851  1 IntegerLiteral il = new IntegerLiteral(SourceInfo.NONE, 4);
 3852  1 LongLiteral ll = new LongLiteral(SourceInfo.NONE, 5);
 3853  1 FloatLiteral fl = new FloatLiteral(SourceInfo.NONE, 1.2f);
 3854  1 DoubleLiteral dl = new DoubleLiteral(SourceInfo.NONE, 4.2);
 3855  1 CharLiteral cl = new CharLiteral(SourceInfo.NONE, 'c');
 3856  1 BooleanLiteral bl = new BooleanLiteral(SourceInfo.NONE, true);
 3857  1 ClassLiteral csl =
 3858    new ClassLiteral(SourceInfo.NONE, new ClassOrInterfaceType(SourceInfo.NONE, "monkey", new Type[0]));
 3859   
 3860  1 SymbolData string = new SymbolData("java.lang.String");
 3861  1 string.setIsContinuation(false);
 3862  1 string.setPackage("java.lang");
 3863  1 string.setMav(_publicMav);
 3864  1 SymbolData classD = new SymbolData("java.lang.Class");
 3865  1 classD.setIsContinuation(false);
 3866  1 classD.setPackage("java.lang");
 3867  1 classD.setMav(_publicMav);
 3868   
 3869  1 symbolTable.put("java.lang.String", string);
 3870  1 symbolTable.put("java.lang.Class", classD);
 3871   
 3872  1 assertEquals("Should return string", string.getInstanceData(), sl.visit(_etc));
 3873  1 assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), il.visit(_etc));
 3874  1 assertEquals("Should return long", SymbolData.LONG_TYPE.getInstanceData(), ll.visit(_etc));
 3875  1 assertEquals("Should return float", SymbolData.FLOAT_TYPE.getInstanceData(), fl.visit(_etc));
 3876  1 assertEquals("Should return double", SymbolData.DOUBLE_TYPE.getInstanceData(), dl.visit(_etc));
 3877  1 assertEquals("Should return char", SymbolData.CHAR_TYPE.getInstanceData(), cl.visit(_etc));
 3878  1 assertEquals("Should return boolean", SymbolData.BOOLEAN_TYPE.getInstanceData(), bl.visit(_etc));
 3879  1 assertEquals("Should return null type", SymbolData.NULL_TYPE.getInstanceData(), NULL_LITERAL.visit(_etc));
 3880  1 assertEquals("Should return class", classD.getInstanceData(), _etc.forClassLiteralOnly(csl));
 3881    }
 3882   
 3883   
 3884  1 public void testForParenthesizedOnly() {
 3885  1 Parenthesized p = new Parenthesized(SourceInfo.NONE, NULL_LITERAL);
 3886   
 3887    // if valueRes is an intance data, no problems
 3888  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 3889    _etc.forParenthesizedOnly(p, SymbolData.BOOLEAN_TYPE.getInstanceData()));
 3890  1 assertEquals("Should be no errors", 0, errors.size());
 3891   
 3892    // if valueRes null, just return null
 3893  1 assertEquals("Should return null", null, _etc.forParenthesizedOnly(p, null));
 3894  1 assertEquals("Should be no errors", 0, errors.size());
 3895   
 3896    // if valueRes is package data, add error
 3897  1 assertEquals("Should return null", null, _etc.forParenthesizedOnly(p, new PackageData("bob")));
 3898  1 assertEquals("Should be 1 error", 1, errors.size());
 3899  1 assertEquals("Error message should be correct","Could not resolve symbol bob" , errors.getLast().getFirst());
 3900   
 3901    // if value result not instance type, give error
 3902  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(),
 3903    _etc.forParenthesizedOnly(p, SymbolData.INT_TYPE));
 3904  1 assertEquals("Should be 2 errors", 2, errors.size());
 3905  1 assertEquals("Error message should be correct",
 3906    "This class or interface name cannot appear in parentheses. Perhaps you meant to create a new "
 3907    + "instance of int" ,
 3908    errors.getLast().getFirst());
 3909   
 3910   
 3911    }
 3912   
 3913  1 public void testMethodInvocationHelper() {
 3914  1 ParenthesizedExpressionList exp1 = new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]);
 3915  1 MethodInvocation noArgs = new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myName"), exp1);
 3916  1 ParenthesizedExpressionList exp2 =
 3917    new ParenthesizedExpressionList(SourceInfo.NONE,
 3918    new Expression[]{new SimpleNameReference(SourceInfo.NONE,
 3919    new Word(SourceInfo.NONE, "int"))});
 3920  1 MethodInvocation typeArg = new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myName"), exp2);
 3921  1 ParenthesizedExpressionList exp3 =
 3922    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[]{new IntegerLiteral(SourceInfo.NONE, 5)});
 3923  1 MethodInvocation oneIntArg =
 3924    new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myName"), exp3);
 3925  1 ParenthesizedExpressionList exp4 =
 3926    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[]{new DoubleLiteral(SourceInfo.NONE, 4.2)});
 3927  1 MethodInvocation oneDoubleArg =
 3928    new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myName"), exp4);
 3929   
 3930    //should be able to match no args correctly
 3931  1 MethodData noArgsM =
 3932    new MethodData("myName", _publicMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE, new VariableData[0],
 3933    new String[0], _sd2, NULL_LITERAL);
 3934  1 _sd2.addMethod(noArgsM);
 3935  1 assertEquals("Should return boolean instance",
 3936    SymbolData.BOOLEAN_TYPE.getInstanceData(),
 3937    _etc.methodInvocationHelper(noArgs, _sd2.getInstanceData()));
 3938  1 assertEquals("Should be no errors", 0, errors.size());
 3939   
 3940    //if no matching method, give error
 3941  1 assertEquals("Should return null", null, _etc.methodInvocationHelper(oneIntArg, _sd2.getInstanceData()));
 3942  1 assertEquals("Should be one error", 1, errors.size());
 3943  1 assertEquals("Error message should be correct", "No method found in class " + _sd2.getName()
 3944    + " with signature: myName(int).",
 3945    errors.getLast().getFirst());
 3946   
 3947    // if matching method, but arg is not instance type, give error
 3948  1 MethodData intArg =
 3949    new MethodData("myName", _publicMav, new TypeParameter[0], SymbolData.LONG_TYPE,
 3950    new VariableData[] {new VariableData(SymbolData.INT_TYPE)}, new String[0], _sd2, NULL_LITERAL);
 3951  1 _sd2.addMethod(intArg);
 3952  1 assertEquals("Should return long instance", SymbolData.LONG_TYPE.getInstanceData(), _etc.methodInvocationHelper(typeArg, _sd2.getInstanceData()));
 3953  1 assertEquals("Should be 2 errors", 2, errors.size());
 3954  1 assertEquals("Error message should be correct", "Cannot pass a class or interface name as an argument to a method. Perhaps you meant to create an instance or use int.class", errors.getLast().getFirst());
 3955   
 3956    // if matching method, no error
 3957  1 assertEquals("Should return long instance", SymbolData.LONG_TYPE.getInstanceData(),
 3958    _etc.methodInvocationHelper(oneIntArg, _sd2.getInstanceData()));
 3959  1 assertEquals("Should still be 2 errors", 2, errors.size());
 3960   
 3961    // non-static method from static context gives error
 3962  1 assertEquals("Should return long instance", SymbolData.LONG_TYPE.getInstanceData(),
 3963    _etc.methodInvocationHelper(oneIntArg, _sd2));
 3964  1 assertEquals("Should be 3 errors", 3, errors.size());
 3965  1 assertEquals("Error message should be correct",
 3966    "Cannot access the non-static method myName from a static context",
 3967    errors.getLast().getFirst());
 3968   
 3969   
 3970    //static method from static context is okay
 3971  1 MethodData doubleArg =
 3972    new MethodData("myName", _publicStaticMav, new TypeParameter[0], SymbolData.CHAR_TYPE,
 3973    new VariableData[] {new VariableData(SymbolData.DOUBLE_TYPE)}, new String[0], _sd2, NULL_LITERAL);
 3974  1 _sd2.addMethod(doubleArg);
 3975  1 assertEquals("Should return char instance", SymbolData.CHAR_TYPE.getInstanceData(),
 3976    _etc.methodInvocationHelper(oneDoubleArg, _sd2));
 3977  1 assertEquals("Should still be 3 errors", 3, errors.size());
 3978    }
 3979   
 3980  1 public void testForSimpleMethodInvocation() {
 3981  1 ParenthesizedExpressionList pel1 = new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]);
 3982  1 MethodInvocation noArgs = new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myName"), pel1);
 3983  1 ParenthesizedExpressionList pel2 =
 3984    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[]{new IntegerLiteral(SourceInfo.NONE, 5)});
 3985  1 MethodInvocation oneIntArg =
 3986    new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myName"), pel2);
 3987  1 ParenthesizedExpressionList pel3 =
 3988    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[]{new DoubleLiteral(SourceInfo.NONE, 4.2)});
 3989  1 MethodInvocation oneDoubleArg =
 3990    new SimpleMethodInvocation(SourceInfo.NONE, new Word(SourceInfo.NONE, "myName"), pel3);
 3991   
 3992    // if method not in class, give error
 3993  1 assertEquals("Should return null", null, noArgs.visit(_etc));
 3994  1 assertEquals("Should be 1 error", 1, errors.size());
 3995  1 assertEquals("Error message should be correct", "No method found in class i.like.monkey with signature: myName().",
 3996    errors.getLast().getFirst());
 3997   
 3998    //if method is in class, should work fine!
 3999  1 MethodData noArgsM =
 4000    new MethodData("myName", _publicMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE,
 4001    new VariableData[0], new String[0], _sd1, NULL_LITERAL);
 4002  1 _sd1.addMethod(noArgsM);
 4003  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), noArgs.visit(_etc));
 4004  1 assertEquals("Should still just be 1 error", 1, errors.size());
 4005   
 4006    //should be able to reference a static method from instance context
 4007  1 MethodData doubleArg =
 4008    new MethodData("myName", _publicStaticMav, new TypeParameter[0], SymbolData.CHAR_TYPE,
 4009    new VariableData[] {new VariableData(SymbolData.DOUBLE_TYPE)}, new String[0], _sd1, NULL_LITERAL);
 4010  1 _sd1.addMethod(doubleArg);
 4011   
 4012  1 assertEquals("Should return char instance", SymbolData.CHAR_TYPE.getInstanceData(), oneDoubleArg.visit(_etc));
 4013  1 assertEquals("Should still be just 1 error", 1, errors.size());
 4014   
 4015    //if in context of a static method, should be able to reference static method
 4016  1 _etc._data = doubleArg;
 4017  1 assertEquals("Should return char instance", SymbolData.CHAR_TYPE.getInstanceData(), oneDoubleArg.visit(_etc));
 4018  1 assertEquals("Should still be just 1 error", 1, errors.size());
 4019   
 4020    //if in context of static method, should not be able to reference non-static method
 4021  1 MethodData intArg =
 4022    new MethodData("myName", _publicMav, new TypeParameter[0], SymbolData.LONG_TYPE,
 4023    new VariableData[] {new VariableData(SymbolData.INT_TYPE)}, new String[0], _sd1, NULL_LITERAL);
 4024  1 _sd1.addMethod(intArg);
 4025  1 assertEquals("Should return long instance", SymbolData.LONG_TYPE.getInstanceData().getName(),
 4026    oneIntArg.visit(_etc).getName());
 4027  1 assertEquals("Should be 2 errors", 2, errors.size());
 4028  1 assertEquals("Error message should be correct", "Cannot access the non-static method myName from a static context",
 4029    errors.getLast().getFirst());
 4030   
 4031    }
 4032   
 4033   
 4034  1 public void testForComplexMethodInvocation() {
 4035  1 MethodInvocation staticNoArgs =
 4036    new ComplexMethodInvocation(SourceInfo.NONE,
 4037    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "giraffe")),
 4038    new Word(SourceInfo.NONE, "myName"),
 4039    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 4040  1 MethodInvocation noArgs =
 4041    new ComplexMethodInvocation(SourceInfo.NONE,
 4042    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "g")),
 4043    new Word(SourceInfo.NONE, "myName"),
 4044    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]));
 4045  1 MethodInvocation oneIntArg =
 4046    new ComplexMethodInvocation(SourceInfo.NONE,
 4047    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "g")),
 4048    new Word(SourceInfo.NONE, "myName"),
 4049    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {
 4050    new IntegerLiteral(SourceInfo.NONE, 5)}));
 4051  1 MethodInvocation staticOneDoubleArg =
 4052    new ComplexMethodInvocation(SourceInfo.NONE,
 4053    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "giraffe")),
 4054    new Word(SourceInfo.NONE, "myName"),
 4055    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {
 4056    new DoubleLiteral(SourceInfo.NONE, 4.2)}));
 4057  1 MethodInvocation oneDoubleArg =
 4058    new ComplexMethodInvocation(SourceInfo.NONE,
 4059    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "g")),
 4060    new Word(SourceInfo.NONE, "myName"),
 4061    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {
 4062    new DoubleLiteral(SourceInfo.NONE, 4.2)}));
 4063   
 4064  1 SymbolData g = new SymbolData("giraffe");
 4065  1 g.setIsContinuation(false);
 4066  1 g.setMav(_publicMav);
 4067  1 symbolTable.put("giraffe", g);
 4068   
 4069  1 VariableData var = new VariableData("g", _publicMav, g, true, _sd1);
 4070  1 _etc._vars.addLast(var);
 4071   
 4072    //if method not in class, give error
 4073  1 assertEquals("Should return null", null, noArgs.visit(_etc));
 4074  1 assertEquals("Should be 1 error", 1, errors.size());
 4075  1 assertEquals("Error message should be correct", "No method found in class giraffe with signature: myName().",
 4076    errors.getLast().getFirst());
 4077   
 4078    // if method is in class, should work fine!
 4079  1 MethodData noArgsM = new MethodData("myName", _publicMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE,
 4080    new VariableData[0], new String[0], g, NULL_LITERAL);
 4081  1 g.addMethod(noArgsM);
 4082  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), noArgs.visit(_etc));
 4083  1 assertEquals("Should still just be 1 error", 1, errors.size());
 4084   
 4085    // should be able to reference a static method from instance context
 4086  1 MethodData doubleArg =
 4087    new MethodData("myName", _publicStaticMav, new TypeParameter[0], SymbolData.CHAR_TYPE,
 4088    new VariableData[] { new VariableData(SymbolData.DOUBLE_TYPE) },
 4089    new String[0], g, NULL_LITERAL);
 4090  1 g.addMethod(doubleArg);
 4091   
 4092  1 assertEquals("Should return char instance", SymbolData.CHAR_TYPE.getInstanceData(), oneDoubleArg.visit(_etc));
 4093  1 assertEquals("Should still be just 1 error", 1, errors.size());
 4094   
 4095    // should be able to reference a static method from static context
 4096  1 staticOneDoubleArg.visit(_etc);
 4097  1 assertEquals("Should return char instance", SymbolData.CHAR_TYPE.getInstanceData(),
 4098    staticOneDoubleArg.visit(_etc));
 4099  1 assertEquals("Should still be just 1 error", 1, errors.size());
 4100   
 4101    // should not be able to reference a non-static method from a static context
 4102  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(),
 4103    staticNoArgs.visit(_etc));
 4104  1 assertEquals("Should be 2 errors", 2, errors.size());
 4105  1 assertEquals("Error message should be correct",
 4106    "Cannot access the non-static method myName from a static context",
 4107    errors.getLast().getFirst());
 4108   
 4109    //if in context of a static method, should be able to reference static method
 4110  1 _etc._data = doubleArg;
 4111  1 var.setMav(_publicStaticMav);
 4112  1 assertEquals("Should return char instance", SymbolData.CHAR_TYPE.getInstanceData(), oneDoubleArg.visit(_etc));
 4113  1 assertEquals("Should still be just 2 errors", 2, errors.size());
 4114   
 4115    // if in context of static method, should be able to reference non-static method given a receiver
 4116  1 MethodData intArg =
 4117    new MethodData("myName", _publicMav, new TypeParameter[0], SymbolData.LONG_TYPE,
 4118    new VariableData[] { new VariableData(SymbolData.INT_TYPE)},
 4119    new String[0], g, NULL_LITERAL);
 4120  1 g.addMethod(intArg);
 4121  1 assertEquals("Should return long instance", SymbolData.LONG_TYPE.getInstanceData().getName(),
 4122    oneIntArg.visit(_etc).getName());
 4123  1 assertEquals("Should be 2 errors", 2, errors.size());
 4124    // assertEquals("Error message should be correct", "Cannot access the non-static method myName from a static context",
 4125    // errors.getLast().getFirst());
 4126   
 4127    // if enclosing class is private, should not work!
 4128  1 _etc._data = _sd1;
 4129  1 g.setMav(_privateMav);
 4130  1 noArgsM.setMav(_publicStaticMav);
 4131  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), noArgs.visit(_etc));
 4132  1 assertEquals("Should be 3 errors", 3, errors.size());
 4133  1 assertEquals("Error message should be correct",
 4134    "The class or interface giraffe in giraffe is private and cannot be accessed from i.like.monkey",
 4135    errors.getLast().getFirst());
 4136   
 4137    }
 4138   
 4139   
 4140  1 public void testCanBeAssigned() {
 4141  1 VariableData finalWithValue = new VariableData("i", _finalMav, SymbolData.INT_TYPE, true, _sd1);
 4142  1 VariableData finalWithOutValue = new VariableData("i", _finalMav, SymbolData.INT_TYPE, false, _sd1);
 4143  1 VariableData notFinalWithValue = new VariableData("i", _publicMav, SymbolData.INT_TYPE, true, _sd1);
 4144  1 VariableData notFinalWithOutValue = new VariableData("i", _publicMav, SymbolData.INT_TYPE, false, _sd1);
 4145   
 4146  1 assertFalse("Should not be assignable", _etc.canBeAssigned(finalWithValue));
 4147  1 assertTrue("Should be assignable", _etc.canBeAssigned(finalWithOutValue));
 4148  1 assertTrue("Should be assignable", _etc.canBeAssigned(notFinalWithValue));
 4149  1 assertTrue("Should be assignable", _etc.canBeAssigned(notFinalWithOutValue));
 4150   
 4151   
 4152    }
 4153   
 4154   
 4155  1 public void testForSimpleAssignment() {
 4156  1 VariableData vd4 = new VariableData("Flanders", _publicMav, SymbolData.INT_TYPE, true, _sd4);
 4157  1 VariableData vd5 = new VariableData("Ned", _publicMav, _sd4, true, _sd5);
 4158  1 _sd5.addVar(vd5);
 4159  1 _sd4.addVar(vd4);
 4160  1 _etc._vars.add(vd5);
 4161  1 _etc._data = _sd5;
 4162   
 4163  1 ComplexNameReference nf =
 4164    new ComplexNameReference(SourceInfo.NONE,
 4165    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Ned")),
 4166    new Word(SourceInfo.NONE, "Flanders"));
 4167  1 SimpleAssignmentExpression sa =
 4168    new SimpleAssignmentExpression(SourceInfo.NONE, nf, new IntegerLiteral(SourceInfo.NONE, 5));
 4169  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), sa.visit(_etc));
 4170  1 assertEquals("Should be 0 errors", 0, errors.size());
 4171   
 4172    //if variable is final, with a value cannot be reassigned
 4173  1 vd4.gotValue();
 4174  1 vd4.setMav(_finalPublicMav);
 4175  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), sa.visit(_etc));
 4176  1 assertEquals("Should now be 1 error", 1, errors.size());
 4177  1 assertEquals("Error message should be correct",
 4178    "You cannot assign a value to Flanders because it is immutable and has already been given a value",
 4179    errors.getLast().getFirst());
 4180   
 4181    // Test that an initialized value can be assigned to itself
 4182  1 vd4.setMav(_publicMav);
 4183  1 SimpleAssignmentExpression sa2 = new SimpleAssignmentExpression(SourceInfo.NONE, nf, nf);
 4184  1 _sd4.setMav(_publicMav);
 4185  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), sa2.visit(_etc));
 4186  1 assertEquals("There should be 1 error", 1, errors.size());
 4187   
 4188    // Test that an uninitialized value cannot be assigned to itself as an initialization
 4189  1 vd4.lostValue();
 4190  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), sa2.visit(_etc));
 4191  1 assertEquals("There should be 2 errors", 2, errors.size());
 4192  1 assertEquals("The error message should be correct",
 4193    "You cannot use Flanders here, because it may not have been given a value",
 4194    errors.getLast().getFirst());
 4195   
 4196    // Test that a value cannot be assigned to a type
 4197  1 SimpleAssignmentExpression sa3 =
 4198    new SimpleAssignmentExpression(SourceInfo.NONE,
 4199    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int")),
 4200    new IntegerLiteral(SourceInfo.NONE, 5));
 4201  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), sa3.visit(_etc));
 4202  1 assertEquals("Should be 3 errors", 3, errors.size());
 4203  1 assertEquals("Error message should be correct",
 4204    "You cannot assign a value to the type int. Perhaps you meant to create a new instance of int",
 4205    errors.getLast().getFirst());
 4206   
 4207    //Test that a type cannot be used on the rhs of an assignment
 4208  1 SimpleAssignmentExpression sa4 =
 4209    new SimpleAssignmentExpression(SourceInfo.NONE, nf,
 4210    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int")));
 4211  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), sa4.visit(_etc));
 4212  1 assertEquals("Should be 4 errors", 4, errors.size());
 4213  1 assertEquals("Error message should be correct",
 4214    "You cannot use the type name int on the right hand side of an assignment. Perhaps you meant to "
 4215    + "create a new instance of int",
 4216    errors.getLast().getFirst());
 4217   
 4218    //test that we can assign to an array element
 4219  1 LanguageLevelVisitor llv =
 4220    new LanguageLevelVisitor(_etc._file,
 4221    _etc._package,
 4222    null, // enclosingClassName for top level traversal
 4223    _etc._importedFiles,
 4224    _etc._importedPackages,
 4225    new HashSet<String>(),
 4226    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 4227    new LinkedList<Command>());
 4228    // LanguageLevelConverter.symbolTable = llv.symbolTable = _etc.symbolTable;
 4229    // LanguageLevelConverter._newSDs = new Hashtable<SymbolData, LanguageLevelVisitor>();
 4230  1 ArrayData boolArray = new ArrayData(SymbolData.BOOLEAN_TYPE, llv, SourceInfo.NONE);
 4231  1 boolArray.setIsContinuation(false);
 4232  1 symbolTable.remove("boolean[]");
 4233  1 symbolTable.put("boolean[]", boolArray);
 4234  1 VariableData myArrayVD = new VariableData("myArray", _publicMav, boolArray, true, _etc._data);
 4235  1 _etc._vars.addLast(myArrayVD);
 4236   
 4237  1 SimpleNameReference snr = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "myArray"));
 4238  1 SimpleAssignmentExpression sa5 =
 4239    new SimpleAssignmentExpression(SourceInfo.NONE,
 4240    new ArrayAccess(SourceInfo.NONE, snr, new IntegerLiteral(SourceInfo.NONE, 5)),
 4241    new BooleanLiteral(SourceInfo.NONE, true));
 4242  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), sa5.visit(_etc));
 4243  1 assertEquals("Should still be 4 errors", 4, errors.size());
 4244   
 4245   
 4246   
 4247    }
 4248   
 4249  1 public void testForPlusAssignmentExpression() {
 4250  1 VariableData vd4 = new VariableData("Flanders", _publicMav, SymbolData.INT_TYPE, true, _sd4);
 4251  1 VariableData vd5 = new VariableData("Ned", _publicMav, _sd4, true, _sd5);
 4252  1 _sd5.addVar(vd5);
 4253  1 _sd4.addVar(vd4);
 4254  1 _etc._vars.add(vd5);
 4255  1 _etc._data = _sd5;
 4256   
 4257    // Plus Assignment with numbers:
 4258    // test that other assignment operators work correctly
 4259  1 ComplexNameReference nf =
 4260    new ComplexNameReference(SourceInfo.NONE,
 4261    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Ned")),
 4262    new Word(SourceInfo.NONE, "Flanders"));
 4263  1 PlusAssignmentExpression pa =
 4264    new PlusAssignmentExpression(SourceInfo.NONE, nf, new IntegerLiteral(SourceInfo.NONE, 5));
 4265   
 4266  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), pa.visit(_etc));
 4267  1 assertEquals("Should be 0 errors", 0, errors.size());
 4268   
 4269    // if variable does not have value, cannot be plus assigned
 4270  1 vd4.lostValue();
 4271  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), pa.visit(_etc));
 4272  1 assertEquals("Should now be 1 error", 1, errors.size());
 4273  1 assertEquals("Error message should be correct",
 4274    "You cannot use Flanders here, because it may not have been given a value",
 4275    errors.get(0).getFirst());
 4276   
 4277    // if variable is final, with a value cannot be reassigned
 4278  1 vd4.gotValue();
 4279  1 vd4.setMav(_finalPublicMav);
 4280  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), pa.visit(_etc));
 4281  1 assertEquals("Should now be 2 errors", 2, errors.size());
 4282  1 assertEquals("Error message should be correct",
 4283    "You cannot assign a new value to Flanders because it is immutable and has already been given a value",
 4284    errors.get(1).getFirst());
 4285   
 4286    // Test that an initialized value can be assigned to itself
 4287  1 vd4.setMav(_publicMav);
 4288  1 _sd4.setMav(_publicMav);
 4289  1 PlusAssignmentExpression pa2 = new PlusAssignmentExpression(SourceInfo.NONE, nf, nf);
 4290  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), pa2.visit(_etc));
 4291  1 assertEquals("There should still be 2 errors", 2, errors.size());
 4292   
 4293    // Test that an uninitialized value cannot be assigned to itself as an initialization
 4294  1 vd4.lostValue();
 4295  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), pa2.visit(_etc));
 4296  1 assertEquals("There should still be 2 errors", 2, errors.size()); // Generated two duplicate messages.
 4297  1 assertEquals("The first error message should be correct",
 4298    "You cannot use Flanders here, because it may not have been given a value",
 4299    errors.get(0).getFirst());
 4300   
 4301    //test Plus Assignment for String concatanation
 4302  1 SymbolData stringSD = new SymbolData("java.lang.String");
 4303  1 stringSD.setIsContinuation(false);
 4304  1 stringSD.setPackage("java.lang");
 4305  1 symbolTable.remove("java.lang.String");
 4306  1 symbolTable.put("java.lang.String", stringSD);
 4307  1 VariableData s = new VariableData("s", _publicMav, stringSD, true, _etc._data);
 4308  1 _etc._vars.add(s);
 4309   
 4310  1 SimpleNameReference sRef = new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "s"));
 4311    //test string concatenation, where the string is first.
 4312  1 PlusAssignmentExpression pa3 =
 4313    new PlusAssignmentExpression(SourceInfo.NONE, sRef, new BooleanLiteral(SourceInfo.NONE, true));
 4314  1 TypeData result = pa3.visit(_etc);
 4315  1 assertEquals("string concatenation with string at the front. Should return String type",
 4316    stringSD.getInstanceData(),
 4317    pa3.visit(_etc));
 4318  1 assertEquals("Should still be 2 errors", 2, errors.size());
 4319   
 4320    // when both sides are strings
 4321  1 PlusAssignmentExpression pa4 =
 4322    new PlusAssignmentExpression(SourceInfo.NONE, sRef, new StringLiteral(SourceInfo.NONE, "cat"));
 4323  1 assertEquals("string concatenation with string on both sides. Should return String type",
 4324    stringSD.getInstanceData(), pa4.visit(_etc));
 4325  1 assertEquals("Should still be 2 errors", 2, errors.size());
 4326   
 4327    // when string is second
 4328  1 vd4.gotValue();
 4329  1 PlusAssignmentExpression pa5 =
 4330    new PlusAssignmentExpression(SourceInfo.NONE, nf, new StringLiteral(SourceInfo.NONE, "house "));
 4331  1 assertEquals("string + concatenation with string at back. Should give error",
 4332    stringSD.getInstanceData(),
 4333    pa5.visit(_etc));
 4334  1 assertEquals("Should now be 3 errors", 3, errors.size());
 4335  1 assertEquals("Error message should be correct",
 4336    "The arguments to the Plus Assignment Operator (+=) must either include an instance of a String " +
 4337    "or both be numbers. You have specified arguments of type int and java.lang.String",
 4338    errors.get(2).getFirst());
 4339    }
 4340   
 4341  1 public void testForNumericAssignmentExpression() {
 4342  1 VariableData vd4 = new VariableData("Flanders", _publicMav, SymbolData.INT_TYPE, true, _sd4);
 4343  1 VariableData vd5 = new VariableData("Ned", _publicMav, _sd4, true, _sd5);
 4344  1 _sd5.addVar(vd5);
 4345  1 _sd4.addVar(vd4);
 4346  1 _etc._vars.add(vd5);
 4347  1 _etc._data = _sd5;
 4348   
 4349    // test that numeric assignment with good values on left and right works correctly
 4350  1 ComplexNameReference nf =
 4351    new ComplexNameReference(SourceInfo.NONE,
 4352    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Ned")),
 4353    new Word(SourceInfo.NONE, "Flanders"));
 4354  1 NumericAssignmentExpression na =
 4355    new MinusAssignmentExpression(SourceInfo.NONE, nf, new IntegerLiteral(SourceInfo.NONE, 5));
 4356   
 4357  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), na.visit(_etc));
 4358  1 assertEquals("Should be 0 errors", 0, errors.size());
 4359   
 4360    //if variable does not have value, cannot be plus assigned
 4361  1 vd4.lostValue();
 4362  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), na.visit(_etc));
 4363  1 assertEquals("Should now be 1 error", 1, errors.size());
 4364  1 assertEquals("Error message should be correct",
 4365    "You cannot use Flanders here, because it may not have been given a value",
 4366    errors.get(0).getFirst());
 4367   
 4368    //if variable is final, cannot be reassigned
 4369  1 vd4.gotValue();
 4370  1 vd4.setMav(_finalPublicMav);
 4371  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), na.visit(_etc));
 4372  1 assertEquals("Should now be 2 errors", 2, errors.size());
 4373  1 assertEquals("Error message should be correct",
 4374    "You cannot assign a new value to Flanders because it is immutable and has already been given a value",
 4375    errors.get(1).getFirst());
 4376   
 4377    // Test that an initialized value can be assigned to itself
 4378  1 vd4.setMav(_publicMav);
 4379  1 _sd4.setMav(_publicMav);
 4380  1 NumericAssignmentExpression na2 = new ModAssignmentExpression(SourceInfo.NONE, nf, nf);
 4381  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), na2.visit(_etc));
 4382  1 assertEquals("There should be 2 errors", 2, errors.size());
 4383   
 4384    // Test that an uninitialized value cannot be assigned to itself as an initialization
 4385  1 vd4.lostValue();
 4386  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), na2.visit(_etc));
 4387  1 assertEquals("There should still be 2 errors", 2, errors.size()); // Generated duplicate error message
 4388  1 assertEquals("The new error message should be correct",
 4389    "You cannot use Flanders here, because it may not have been given a value",
 4390    errors.get(0).getFirst());
 4391    }
 4392   
 4393  1 public void testForIncrementExpression() {
 4394  1 VariableData vd4 = new VariableData("Flanders", _publicMav, SymbolData.INT_TYPE, true, _sd4);
 4395  1 VariableData vd5 = new VariableData("Ned", _publicMav, _sd4, true, _sd5);
 4396  1 _sd5.addVar(vd5);
 4397  1 _sd4.addVar(vd4);
 4398  1 _etc._vars.add(vd5);
 4399  1 _etc._data = _sd5;
 4400   
 4401    //test that words with a pre-increment operator before only work if they already have a value and aren't final.
 4402  1 ComplexNameReference nf =
 4403    new ComplexNameReference(SourceInfo.NONE,
 4404    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "Ned")),
 4405    new Word(SourceInfo.NONE, "Flanders"));
 4406  1 PositivePrefixIncrementExpression ppi = new PositivePrefixIncrementExpression(SourceInfo.NONE, nf);
 4407   
 4408  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), ppi.visit(_etc));
 4409  1 assertEquals("Should still be 0 errors", 0, errors.size());
 4410   
 4411    // test that attempting to increment the value of a field that doesn't have a value will throw an error
 4412  1 vd4.lostValue();
 4413  1 assertEquals("Should return int instance.", SymbolData.INT_TYPE.getInstanceData(), ppi.visit(_etc));
 4414  1 assertEquals("Should now be 1 errors", 1, errors.size());
 4415  1 assertEquals("Error message should be correct",
 4416    "You cannot use Flanders here, because it may not have been given a value",
 4417    errors.get(0).getFirst());
 4418   
 4419    // test that attempting to increment the value of a final field will throw an error
 4420  1 vd4.gotValue();
 4421  1 vd4.setMav(_finalPublicMav);
 4422  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), ppi.visit(_etc));
 4423  1 assertEquals("Should now be 2 errors", 2, errors.size());
 4424  1 assertEquals("Error message should be correct",
 4425    "You cannot assign a new value to Flanders because it is immutable and has already been given a value",
 4426    errors.get(1).getFirst());
 4427   
 4428    // Check that ++int doesn't work
 4429  1 PositivePrefixIncrementExpression ppi2 =
 4430    new PositivePrefixIncrementExpression(SourceInfo.NONE,
 4431    new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int")));
 4432  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), ppi2.visit(_etc));
 4433  1 assertEquals("There should now be 3 errors", 3, errors.size());
 4434  1 assertEquals("The error message should be correct",
 4435    "You cannot increment or decrement int, because it is a class name not an instance. " +
 4436    "Perhaps you meant to create a new instance of int",
 4437    errors.get(2).getFirst());
 4438   
 4439   
 4440    // Check that ++(int) doesn't work
 4441  1 Parenthesized p1 =
 4442    new Parenthesized(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int")));
 4443  1 PositivePrefixIncrementExpression ppi3 = new PositivePrefixIncrementExpression(SourceInfo.NONE, p1);
 4444  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), ppi3.visit(_etc));
 4445  1 assertEquals("There should now be 4 errors", 4, errors.size()); // Generated error is not a duplicate
 4446  1 assertEquals("The error message should be correct",
 4447    "You cannot increment or decrement int, because it is a class name not an instance. " +
 4448    "Perhaps you meant to create a new instance of int",
 4449    errors.get(3).getFirst());
 4450   
 4451   
 4452    // Test that words with post-decrement operator only work if they already have a value and aren't final.
 4453  1 vd4.setMav(_publicMav);
 4454  1 NegativePostfixIncrementExpression npi = new NegativePostfixIncrementExpression(SourceInfo.NONE, nf);
 4455  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), npi.visit(_etc));
 4456  1 assertEquals("Should still be 4 errors", 4, errors.size());
 4457   
 4458    // Test that attempting to decrement the value of a field that doesn't have a value will throw an error
 4459  1 vd4.lostValue();
 4460  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), npi.visit(_etc));
 4461  1 assertEquals("Should still be 4 errors", 4, errors.size());
 4462  1 assertEquals("Error message should be correct",
 4463    "You cannot use Flanders here, because it may not have been given a value",
 4464    errors.get(0).getFirst());
 4465   
 4466    // test that attempting to increment the value of a final field will throw an error
 4467  1 vd4.gotValue();
 4468  1 vd4.setMav(_finalPublicMav);
 4469  1 assertEquals("Should return int instance.", SymbolData.INT_TYPE.getInstanceData(), npi.visit(_etc));
 4470  1 assertEquals("Should still be 4 errors", 4, errors.size());
 4471  1 assertEquals("Error message should be correct",
 4472    "You cannot assign a new value to Flanders because it is immutable and has already been given a value",
 4473    errors.get(1).getFirst());
 4474   
 4475   
 4476    // Check that int-- doesn't work
 4477  1 NegativePostfixIncrementExpression npi2 =
 4478    new NegativePostfixIncrementExpression(SourceInfo.NONE,
 4479    new SimpleNameReference(SourceInfo.NONE,
 4480    new Word(SourceInfo.NONE, "int")));
 4481  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), npi2.visit(_etc));
 4482  1 assertEquals("There should be 5 errors", 5, errors.size());
 4483  1 assertEquals("The error message should be correct",
 4484    "You cannot increment or decrement int, because it is a class name not an instance. Perhaps you " +
 4485    "meant to create a new instance of int",
 4486    errors.get(4).getFirst());
 4487   
 4488    // Check that (int)-- doesn't work
 4489  1 Parenthesized p2 =
 4490    new Parenthesized(SourceInfo.NONE, new SimpleNameReference(SourceInfo.NONE, new Word(SourceInfo.NONE, "int")));
 4491  1 NegativePostfixIncrementExpression npi3 = new NegativePostfixIncrementExpression(SourceInfo.NONE, p2);
 4492  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), npi3.visit(_etc));
 4493  1 assertEquals("There should be 6 errors", 6, errors.size()); // Wny isn't this a duplicate of error #4?
 4494  1 assertEquals("The error message should be correct",
 4495    "You cannot increment or decrement int, because it is a class name not an instance. " +
 4496    "Perhaps you meant to create a new instance of int",
 4497    errors.get(5).getFirst());
 4498   
 4499   
 4500    //should break: double increment/decrement ++(--Ned.Flanders)
 4501  1 vd4.setMav(_publicMav);
 4502  1 Parenthesized p3 = new Parenthesized(SourceInfo.NONE, new NegativePrefixIncrementExpression(SourceInfo.NONE, nf));
 4503  1 PositivePrefixIncrementExpression ppi4 = new PositivePrefixIncrementExpression(SourceInfo.NONE, p3);
 4504  1 assertEquals("Should return null", null, ppi4.visit(_etc));
 4505  1 assertEquals("Should have added 1 error", 7, errors.size());
 4506  1 assertEquals("Should have correct error message",
 4507    "You cannot assign a value to an increment expression",
 4508    errors.getLast().getFirst());
 4509   
 4510    // //should break: non number being incremented
 4511  1 VariableData s = new VariableData("s", _publicMav, SymbolData.BOOLEAN_TYPE, true, _etc._data);
 4512  1 _etc._vars.addLast(s);
 4513  1 PositivePrefixIncrementExpression ppi5 =
 4514    new PositivePrefixIncrementExpression(SourceInfo.NONE,
 4515    new SimpleNameReference(SourceInfo.NONE,
 4516    new Word(SourceInfo.NONE, "s")));
 4517  1 assertEquals("Should return boolean instance", SymbolData.BOOLEAN_TYPE.getInstanceData(), ppi5.visit(_etc));
 4518  1 assertEquals("Should have added 1 error", 8, errors.size());
 4519  1 assertEquals("Should have correct error message",
 4520    "You cannot increment or decrement something that is not a number type. You have specified " +
 4521    "something of type boolean", errors.get(7).getFirst());
 4522   
 4523    //nested parentheses...should work
 4524  1 PositivePrefixIncrementExpression ppi6 =
 4525    new PositivePrefixIncrementExpression(SourceInfo.NONE, new Parenthesized(SourceInfo.NONE,
 4526    new Parenthesized(SourceInfo.NONE, nf)));
 4527  1 assertEquals("Should return int instance", SymbolData.INT_TYPE.getInstanceData(), ppi6.visit(_etc));
 4528  1 assertEquals("Should still be 8 errors", 8, errors.size());
 4529    }
 4530   
 4531   
 4532  1 public void testForSimpleAnonymousClassInstantiation() {
 4533  1 ClassOrInterfaceType objType = new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]);
 4534  1 AnonymousClassInstantiation basic =
 4535    new SimpleAnonymousClassInstantiation(SourceInfo.NONE,
 4536    objType,
 4537    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]),
 4538    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 4539   
 4540  1 SymbolData object = LanguageLevelConverter.symbolTable.get("java.lang.Object");
 4541   
 4542  1 _sd1.setAnonymousInnerClassNum(0);
 4543   
 4544    // Once our enclosing data does have an anonymous inner class, it's okay to look it up
 4545  1 SymbolData anon1 = new SymbolData("i.like.monkey$1");
 4546  1 anon1.setIsContinuation(false);
 4547  1 anon1.setPackage("i.like");
 4548  1 anon1.setMav(_publicMav);
 4549  1 anon1.setOuterData(_sd1);
 4550  1 assert object != null;
 4551  1 anon1.setSuperClass(object);
 4552  1 _sd1.addInnerClass(anon1);
 4553    // System.err.println("****** anon1 is: " + anon1);
 4554    // System.err.println("****** instance data = " + anon1.getInstanceData());
 4555  1 assertEquals("Should return anon1 instance", anon1.getInstanceData(), basic.visit(_etc));
 4556   
 4557  1 assertEquals("Should be no errors", 0, errors.size());
 4558   
 4559  1 VariableDeclaration vdecl = new VariableDeclaration(SourceInfo.NONE,
 4560    _packageMav,
 4561    new VariableDeclarator[] {
 4562    new UninitializedVariableDeclarator(SourceInfo.NONE,
 4563    new PrimitiveType(SourceInfo.NONE, "double"),
 4564    new Word (SourceInfo.NONE, "field1")),
 4565    new UninitializedVariableDeclarator(SourceInfo.NONE,
 4566    new PrimitiveType(SourceInfo.NONE, "boolean"),
 4567    new Word (SourceInfo.NONE, "field2"))});
 4568   
 4569  1 PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
 4570  1 UninitializedVariableDeclarator uvd =
 4571    new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
 4572  1 FormalParameter param =
 4573    new FormalParameter(SourceInfo.NONE,
 4574    new UninitializedVariableDeclarator(SourceInfo.NONE, intt,
 4575    new Word(SourceInfo.NONE, "j")), false);
 4576  1 BracedBody bb =
 4577    new BracedBody(SourceInfo.NONE,
 4578    new BodyItemI[] {new VariableDeclaration(SourceInfo.NONE, _packageMav,
 4579    new UninitializedVariableDeclarator[]{uvd}),
 4580    new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5))});
 4581   
 4582  1 ConcreteMethodDef cmd1 =
 4583    new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0],
 4584    intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param},
 4585    new ReferenceType[0], bb);
 4586  1 BracedBody classBb = new BracedBody(SourceInfo.NONE, new BodyItemI[] { vdecl, cmd1 });
 4587   
 4588  1 SimpleAnonymousClassInstantiation complicated =
 4589    new SimpleAnonymousClassInstantiation(SourceInfo.NONE,
 4590    new ClassOrInterfaceType(SourceInfo.NONE, "name", new Type[0]),
 4591    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]),
 4592    classBb);
 4593  1 SymbolData sd = new SymbolData("name");
 4594  1 sd.setIsContinuation(false);
 4595  1 sd.setMav(_publicMav);
 4596  1 symbolTable.put("name", sd);
 4597  1 SymbolData anon2 = new SymbolData("i.like.monkey$2");
 4598  1 anon2.setIsContinuation(false);
 4599  1 anon2.setPackage("i.like");
 4600  1 anon2.setSuperClass(sd);
 4601  1 anon2.setOuterData(_sd1);
 4602  1 _sd1.addInnerClass(anon2);
 4603   
 4604  1 VariableData vd1 = new VariableData("field1", _publicMav, SymbolData.DOUBLE_TYPE, true, sd);
 4605  1 VariableData vd2 = new VariableData("field2", _publicMav, SymbolData.DOUBLE_TYPE, true, sd);
 4606  1 sd.addVar(vd1);
 4607  1 sd.addVar(vd2);
 4608   
 4609  1 MethodData md =
 4610    new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[] {
 4611    new VariableData("j", _finalMav, SymbolData.INT_TYPE, true, null)}, new String[0], sd, cmd1);
 4612  1 md.getParams()[0].setEnclosingData(md);
 4613  1 MethodData cd =
 4614    new MethodData("name", _publicMav, new TypeParameter[0], sd, new VariableData[0], new String[0], sd, cmd1);
 4615  1 anon2.addMethod(md);
 4616  1 sd.addMethod(cd);
 4617    // check that this complex expression returns correct type, overwriting fields and method in super class
 4618  1 assertEquals("Should return anon2. ", anon2.getInstanceData(), complicated.visit(_etc));
 4619  1 assertEquals("There should be no errors", 0, errors.size());
 4620   
 4621  1 _etc._data.addVar(new VariableData("myAnon", _publicMav, sd, false, _etc._data));
 4622   
 4623   
 4624    // Test that I can assign the anonymous inner class to a variable of the right type.
 4625  1 _sd1.setAnonymousInnerClassNum(1);
 4626  1 symbolTable.put("int", SymbolData.INT_TYPE);
 4627  1 VariableDeclaration vd =
 4628    new VariableDeclaration(SourceInfo.NONE, _publicMav, new VariableDeclarator[] {
 4629    new InitializedVariableDeclarator(SourceInfo.NONE,
 4630    new ClassOrInterfaceType(SourceInfo.NONE, "name", new Type[0]),
 4631    new Word(SourceInfo.NONE, "myAnon"), complicated)});
 4632  1 vd.visit(_etc);
 4633  1 assertEquals("There should still be no errors", 0, errors.size());
 4634   
 4635    //Test that a method invoked from an anonymous inner class does its thing correctly
 4636  1 _sd1.setAnonymousInnerClassNum(1);
 4637  1 MethodInvocation mie =
 4638    new ComplexMethodInvocation(SourceInfo.NONE,
 4639    complicated,
 4640    new Word(SourceInfo.NONE, "myMethod"),
 4641    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[] {
 4642    new IntegerLiteral(SourceInfo.NONE, 5)}));
 4643  1 assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), mie.visit(_etc));
 4644  1 assertEquals("There should still be no errors", 0, errors.size());
 4645   
 4646    // Test that we can get a field from an anonymous inner class
 4647  1 _sd1.setAnonymousInnerClassNum(1);
 4648   
 4649  1 Expression nr = new ComplexNameReference(SourceInfo.NONE, complicated, new Word(SourceInfo.NONE, "field1"));
 4650  1 assertEquals("Should return double", SymbolData.DOUBLE_TYPE.getInstanceData(), nr.visit(_etc));
 4651  1 assertEquals("There should be no errors...still!", 0, errors.size());
 4652   
 4653    // Let sd be abstract with an abstract method that our instantiation doesn't override. Should throw an error.
 4654  1 _sd1.setAnonymousInnerClassNum(1);
 4655  1 sd.setMav(_publicAbstractMav);
 4656  1 sd.addMethod(new MethodData("yeah", _abstractMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE,
 4657    new VariableData[0], new String[0], sd, cmd1));
 4658   
 4659  1 assertEquals("Should return anon2 instance", anon2.getInstanceData(), complicated.visit(_etc));
 4660  1 assertEquals("There should be one error", 1, errors.size());
 4661  1 assertEquals("The error message should be correct",
 4662    "This anonymous inner class must override the abstract method: yeah() in name",
 4663    errors.get(0).getFirst());
 4664   
 4665    //cannot use syntax new A.B() if B is not static. Make sure appropriate error is thrown.
 4666  1 SimpleAnonymousClassInstantiation nestedNonStatic =
 4667    new SimpleAnonymousClassInstantiation(SourceInfo.NONE,
 4668    new ClassOrInterfaceType(SourceInfo.NONE, "A.B", new Type[0]),
 4669    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]),
 4670    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 4671   
 4672  1 SymbolData a = new SymbolData("A");
 4673  1 a.setIsContinuation(false);
 4674  1 SymbolData b = new SymbolData("A$B");
 4675  1 b.setIsContinuation(false);
 4676  1 b.setOuterData(a);
 4677  1 a.addInnerClass(b);
 4678  1 MethodData consb = new MethodData("B", _publicMav, new TypeParameter[0], b,
 4679    new VariableData[0],
 4680    new String[0],
 4681    b,
 4682    null);
 4683  1 b.addMethod(consb);
 4684  1 symbolTable.put("A", a);
 4685  1 a.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 4686  1 b.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 4687   
 4688  1 SymbolData anon3 = new SymbolData("i.like.monkey$3");
 4689  1 anon3.setIsContinuation(false);
 4690  1 anon3.setMav(_publicMav);
 4691  1 _sd1.addInnerClass(anon3);
 4692  1 anon3.setOuterData(_sd1);
 4693   
 4694    //if inner part is not static, give error
 4695  1 assertEquals("Should return anon3", anon3.getInstanceData(), nestedNonStatic.visit(_etc));
 4696  1 assertEquals("Should be 2 errors", 2, errors.size());
 4697   
 4698  1 assertEquals("Error message should be correct",
 4699    "A.B is not a static inner class, and thus cannot be instantiated from this context. "
 4700    + "Perhaps you meant to use an instantiation of the form new A().new B()",
 4701    errors.getLast().getFirst());
 4702   
 4703  1 _sd1.setAnonymousInnerClassNum(2);
 4704    //if inner part is static, no problem
 4705  1 b.addModifier("static");
 4706  1 assertEquals("Should return anon3", anon3.getInstanceData(), nestedNonStatic.visit(_etc));
 4707  1 assertEquals("Should still be just 2 errors", 2, errors.size());
 4708   
 4709    }
 4710   
 4711  1 public void testForComplexAnonymousClassInstantiation() {
 4712  1 ClassOrInterfaceType objType = new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]);
 4713   
 4714  1 AnonymousClassInstantiation basic =
 4715    new ComplexAnonymousClassInstantiation(SourceInfo.NONE,
 4716    new SimpleNameReference(SourceInfo.NONE,
 4717    new Word(SourceInfo.NONE, "bob")),
 4718    objType,
 4719    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]),
 4720    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 4721   
 4722    // Create a variable 'bob' of type _sd2 within _sd1
 4723  1 VariableData bob = new VariableData("bob", _publicMav, _sd2, true, _sd1);
 4724  1 _etc._vars.add(bob); // _data for _etc is _sd1
 4725   
 4726  1 SymbolData object = LanguageLevelConverter.symbolTable.get("java.lang.Object");
 4727  1 _sd1.setAnonymousInnerClassNum(0);
 4728  1 SymbolData anon1 = new SymbolData("i.like.monkey$1");
 4729  1 anon1.setIsContinuation(false);
 4730  1 anon1.setPackage("i.like");
 4731  1 anon1.setMav(_publicMav);
 4732  1 anon1.setOuterData(_sd1);
 4733  1 assert object != null;
 4734  1 anon1.setSuperClass(object);
 4735  1 _sd1.addInnerClass(anon1);
 4736  1 assertEquals("Should return anon1 instance", anon1.getInstanceData(), basic.visit(_etc));
 4737   
 4738  1 assertEquals("Should be no errors", 0, errors.size());
 4739   
 4740   
 4741  1 VariableDeclaration vdecl = new VariableDeclaration(SourceInfo.NONE,
 4742    _packageMav,
 4743    new VariableDeclarator[] {
 4744    new UninitializedVariableDeclarator(SourceInfo.NONE,
 4745    new PrimitiveType(SourceInfo.NONE, "double"),
 4746    new Word (SourceInfo.NONE, "field1")),
 4747    new UninitializedVariableDeclarator(SourceInfo.NONE,
 4748    new PrimitiveType(SourceInfo.NONE, "boolean"),
 4749    new Word (SourceInfo.NONE, "field2"))});
 4750   
 4751  1 PrimitiveType intt = new PrimitiveType(SourceInfo.NONE, "int");
 4752  1 UninitializedVariableDeclarator uvd =
 4753    new UninitializedVariableDeclarator(SourceInfo.NONE, intt, new Word(SourceInfo.NONE, "i"));
 4754  1 FormalParameter param =
 4755    new FormalParameter(SourceInfo.NONE,
 4756    new UninitializedVariableDeclarator(SourceInfo.NONE, intt,
 4757    new Word(SourceInfo.NONE, "j")), false);
 4758  1 BracedBody bb =
 4759    new BracedBody(SourceInfo.NONE, new BodyItemI[] {
 4760    new VariableDeclaration(SourceInfo.NONE, _packageMav, new UninitializedVariableDeclarator[]{uvd}),
 4761    new ValueReturnStatement(SourceInfo.NONE, new IntegerLiteral(SourceInfo.NONE, 5))});
 4762   
 4763  1 ConcreteMethodDef cmd1 =
 4764    new ConcreteMethodDef(SourceInfo.NONE, _publicMav, new TypeParameter[0],
 4765    intt, new Word(SourceInfo.NONE, "myMethod"), new FormalParameter[] {param},
 4766    new ReferenceType[0], bb);
 4767  1 BracedBody classBb = new BracedBody(SourceInfo.NONE, new BodyItemI[] { vdecl, cmd1 });
 4768   
 4769  1 ComplexAnonymousClassInstantiation complicated =
 4770    new ComplexAnonymousClassInstantiation(SourceInfo.NONE,
 4771    new SimpleNameReference(SourceInfo.NONE,
 4772    new Word(SourceInfo.NONE, "bob")),
 4773    new ClassOrInterfaceType(SourceInfo.NONE, "name", new Type[0]),
 4774    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]),
 4775    classBb);
 4776   
 4777    // This test is not well-documented. In refactoring, I tried to preserve it as best as possible.
 4778  1 SymbolData sd = new SymbolData("name");
 4779  1 sd.setIsContinuation(false);
 4780  1 sd.setMav(_publicMav);
 4781  1 sd.setSuperClass(object);
 4782  1 symbolTable.put("name", sd);
 4783  1 SymbolData anon2 = new SymbolData("i.like.monkey$2");
 4784  1 anon2.setIsContinuation(false);
 4785  1 anon2.setPackage("i.like");
 4786  1 anon2.setSuperClass(sd);
 4787  1 anon2.setOuterData(_sd1);
 4788  1 _sd1.addInnerClass(anon2);
 4789   
 4790  1 VariableData vd1 = new VariableData("field1", _publicMav, SymbolData.DOUBLE_TYPE, true, sd);
 4791  1 VariableData vd2 = new VariableData("field2", _publicMav, SymbolData.DOUBLE_TYPE, true, sd);
 4792  1 sd.addVar(vd1);
 4793  1 sd.addVar(vd2);
 4794   
 4795  1 MethodData md =
 4796    new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[] {
 4797    new VariableData("j", _finalMav, SymbolData.INT_TYPE, true, null)}, new String[0], sd, cmd1);
 4798  1 md.getParams()[0].setEnclosingData(md);
 4799  1 MethodData cd =
 4800    new MethodData("name", _publicMav, new TypeParameter[0], sd, new VariableData[0], new String[0], sd, cmd1);
 4801  1 anon2.addMethod(md);
 4802  1 sd.addMethod(cd);
 4803    // check that this complex expression returns correct type, overwriting fields in super class and method in
 4804    // super class
 4805  1 assertEquals("Should return anon2. ", anon2.getInstanceData(), complicated.visit(_etc));
 4806  1 assertEquals("There should be no errors", 0, errors.size());
 4807   
 4808  1 _etc._data.addVar(new VariableData("myAnon", _publicMav, sd, false, _etc._data));
 4809   
 4810   
 4811    // Test that I can assign the anonymous inner class to a variable of the right type.
 4812  1 _sd1.setAnonymousInnerClassNum(1);
 4813  1 symbolTable.put("int", SymbolData.INT_TYPE);
 4814  1 VariableDeclaration vd =
 4815    new VariableDeclaration(SourceInfo.NONE, _publicMav, new VariableDeclarator[] {
 4816    new InitializedVariableDeclarator(SourceInfo.NONE,
 4817    new ClassOrInterfaceType(SourceInfo.NONE, "name", new Type[0]),
 4818    new Word(SourceInfo.NONE, "myAnon"),
 4819    complicated)});
 4820  1 vd.visit(_etc);
 4821  1 assertEquals("There should still be no errors", 0, errors.size());
 4822   
 4823    //Test that a method invoked from an anonymous inner class does its thing correctly
 4824  1 _sd1.setAnonymousInnerClassNum(1);
 4825  1 MethodInvocation mie =
 4826    new ComplexMethodInvocation(SourceInfo.NONE, complicated,
 4827    new Word(SourceInfo.NONE, "myMethod"),
 4828    new ParenthesizedExpressionList(SourceInfo.NONE,
 4829    new Expression[] {
 4830    new IntegerLiteral(SourceInfo.NONE, 5)}));
 4831  1 assertEquals("Should return int", SymbolData.INT_TYPE.getInstanceData(), mie.visit(_etc));
 4832  1 assertEquals("There should still be no errors", 0, errors.size());
 4833   
 4834    // //Test that we can get a field from an anonymous inner class
 4835  1 _sd1.setAnonymousInnerClassNum(1);
 4836   
 4837  1 Expression nr = new ComplexNameReference(SourceInfo.NONE, complicated, new Word(SourceInfo.NONE, "field1"));
 4838  1 assertEquals("Should return double", SymbolData.DOUBLE_TYPE.getInstanceData(), nr.visit(_etc));
 4839  1 assertEquals("There should be no errors...still!", 0, errors.size());
 4840   
 4841    // If the implemented sd is abstract and it isn't overriden, type-checking should throw an error.
 4842  1 _sd1.setAnonymousInnerClassNum(1);
 4843  1 sd.setMav(_publicAbstractMav);
 4844  1 sd.addMethod(new MethodData("yeah", _abstractMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE,
 4845    new VariableData[0], new String[0], sd, cmd1));
 4846   
 4847  1 assertEquals("Should return anon2 instance", anon2.getInstanceData(), complicated.visit(_etc));
 4848  1 assertEquals("There should be one error", 1, errors.size());
 4849  1 assertEquals("The error message should be correct",
 4850    "This anonymous inner class must override the abstract method: yeah() in name",
 4851    errors.get(0).getFirst());
 4852   
 4853    // //cannot use syntax a.new B() if B is static. Make sure appropriate error is thrown.
 4854  1 ComplexAnonymousClassInstantiation nestedNonStatic =
 4855    new ComplexAnonymousClassInstantiation(SourceInfo.NONE,
 4856    new SimpleNameReference(SourceInfo.NONE,
 4857    new Word(SourceInfo.NONE, "a")),
 4858    new ClassOrInterfaceType(SourceInfo.NONE, "B", new Type[0]),
 4859    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]),
 4860    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 4861   
 4862  1 SymbolData a = new SymbolData("A");
 4863  1 a.setIsContinuation(false);
 4864  1 SymbolData b = new SymbolData("A$B");
 4865  1 b.setIsContinuation(false);
 4866  1 b.setOuterData(a);
 4867  1 a.addInnerClass(b);
 4868  1 MethodData consb =
 4869    new MethodData("B", _publicMav, new TypeParameter[0], b, new VariableData[0], new String[0], b, null);
 4870  1 b.addMethod(consb);
 4871  1 symbolTable.put("A", a);
 4872  1 a.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 4873  1 b.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"}));
 4874   
 4875  1 SymbolData anon3 = new SymbolData("i.like.monkey$3");
 4876  1 anon3.setIsContinuation(false);
 4877  1 anon3.setMav(_publicMav);
 4878  1 _sd1.addInnerClass(anon3);
 4879  1 anon3.setOuterData(_sd1);
 4880  1 VariableData aVar = new VariableData("a", _publicMav, a, true, _sd1);
 4881  1 _etc._vars.add(aVar);
 4882   
 4883    //if inner part is not static, no problem
 4884  1 assertEquals("Should return anon3", anon3.getInstanceData(), nestedNonStatic.visit(_etc));
 4885  1 assertEquals("Should still be just 1 error", 1, errors.size());
 4886   
 4887    //if outer part is private, should break
 4888  1 _sd1.setAnonymousInnerClassNum(2);
 4889  1 a.setMav(_privateMav);
 4890  1 assertEquals("Should return anon3", anon3.getInstanceData(), nestedNonStatic.visit(_etc));
 4891  1 assertEquals("Should be 2 errors", 2, errors.size());
 4892  1 assertEquals("Error message should be correct",
 4893    "The class or interface A in A is private and cannot be accessed from i.like.monkey",
 4894    errors.getLast().getFirst());
 4895  1 a.setMav(_publicMav);
 4896   
 4897    //if inner part is static, give error
 4898  1 _sd1.setAnonymousInnerClassNum(2);
 4899  1 b.setMav(_publicStaticMav);
 4900  1 assertEquals("Should return anon3", anon3.getInstanceData(), nestedNonStatic.visit(_etc));
 4901  1 assertEquals("Should be 3 errors", 3, errors.size());
 4902  1 assertEquals("Error message should be correct",
 4903    "You cannot instantiate a static inner class or interface with this syntax. Instead, try new A.B()",
 4904    errors.getLast().getFirst());
 4905   
 4906    // if inner part is not static, but outer part is type name, give error
 4907  1 ComplexAnonymousClassInstantiation nested =
 4908    new ComplexAnonymousClassInstantiation(SourceInfo.NONE,
 4909    new SimpleNameReference(SourceInfo.NONE,
 4910    new Word(SourceInfo.NONE, "A")),
 4911    new ClassOrInterfaceType(SourceInfo.NONE, "B", new Type[0]),
 4912    new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]),
 4913    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 4914  1 _sd1.setAnonymousInnerClassNum(2);
 4915  1 b.setMav(_publicMav);
 4916  1 assertEquals("Should return anon3", anon3.getInstanceData(), nested.visit(_etc));
 4917  1 assertEquals("Should be 4 errors", 4, errors.size());
 4918  1 assertEquals("Error message should be correct",
 4919    "The constructor of a non-static inner class can only be called on an instance of its "
 4920    + "containing class (e.g. new A().new B())",
 4921    errors.getLast().getFirst());
 4922   
 4923    }
 4924    }
 4925    }