Clover coverage report - Java Language Levels Test Coverage (javalanglevels-20120305-r5436)
Coverage timestamp: Sun Mar 4 2012 22:02:46 CST
file stats: LOC: 2,672   Methods: 83
NCLOC: 1,826   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
TypeChecker.java 84.5% 95% 80.7% 92%
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.Log;
 42    import edu.rice.cs.javalanglevels.util.UnexpectedException;
 43    import edu.rice.cs.javalanglevels.util.Utilities;
 44    import java.util.*;
 45    import java.io.File;
 46    import edu.rice.cs.plt.reflect.JavaVersion;
 47    import edu.rice.cs.plt.iter.*;
 48   
 49    import junit.framework.TestCase;
 50   
 51    /** Does Type Checking that is not dependent on the enclosing body. Also does top level type checking. Common
 52    * to all langauge levels. */
 53    public class TypeChecker extends JExpressionIFDepthFirstVisitor<TypeData> implements JExpressionIFVisitor<TypeData> {
 54   
 55    public static final SourceInfo NONE = SourceInfo.NONE;
 56    public static final NullLiteral NULL_LITERAL = new NullLiteral(NONE);
 57   
 58    public static final ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(NONE, new String[0]);
 59    public static final ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(NONE, new String[] {"public"});
 60    public static final ModifiersAndVisibility _protectedMav =
 61    new ModifiersAndVisibility(NONE, new String[] {"protected"});
 62    public static final ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(NONE, new String[] {"private"});
 63   
 64    public static final ModifiersAndVisibility _abstractMav = new ModifiersAndVisibility(NONE, new String[] {"abstract"});
 65    public static final ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(NONE, new String[] {"final"});
 66    public static final ModifiersAndVisibility _finalPublicMav =
 67    new ModifiersAndVisibility(NONE, new String[] {"final", "public"});
 68    public static final ModifiersAndVisibility _publicAbstractMav =
 69    new ModifiersAndVisibility(NONE, new String[] {"public", "abstract"});
 70    public static final ModifiersAndVisibility _publicStaticMav =
 71    new ModifiersAndVisibility(NONE, new String[] {"public", "static"});
 72   
 73    protected static final Log _log = new Log("LLConverter.txt", false);
 74   
 75    /** Holds any errors that are encountered during TypeChecking */
 76    static LinkedList<Pair<String, JExpressionIF>> errors;
 77   
 78    /** Holds the information about any classes/interfaces that have been resolved */
 79    static final Symboltable symbolTable = LanguageLevelConverter.symbolTable;
 80   
 81    /**True if we have an error we can't recover from*/
 82    static boolean _errorAdded;
 83   
 84    /** The source file we are type checking */
 85    File _file;
 86   
 87    /** The package of the source file. */
 88    String _package;
 89   
 90    /** Holds the names of the specifically imported classes. */
 91    LinkedList<String> _importedFiles;
 92   
 93    /**Holds the names of packages that are imported in the source file*/
 94    LinkedList<String> _importedPackages;
 95   
 96    /** The normal constructor. Called to begin type checking
 97    * @param file The source file being type checked
 98    * @param packageName The name of the package of the source file
 99    * @param errors The list of errors that are encountered during type checking
 100    * @param importedFiles The specific classes imported in the source file
 101    * @param importedPackages The list of package names that are imported
 102    */
 103  75 public TypeChecker(File file, String packageName, LinkedList<Pair<String, JExpressionIF>> errors,
 104    Symboltable symbolTable, LinkedList<String> importedFiles,
 105    LinkedList<String> importedPackages) {
 106  75 _file = file;
 107  75 _package = packageName;
 108  75 this.errors = errors;
 109    // this.symbolTable = symbolTable;
 110  75 this._importedFiles = importedFiles;
 111  75 this._importedPackages = importedPackages;
 112    }
 113   
 114    /** Called by the subclasses.
 115    * @param file The Source File being checked
 116    * @param packageName The package the source file is in
 117    * @param importedFiles The specific classes imported in the source file
 118    * @param importedPackages The list of package names that are imported
 119    */
 120  1299 public TypeChecker(File file, String packageName, LinkedList<String> importedFiles,
 121    LinkedList<String> importedPackages) {
 122  1299 _file = file;
 123  1299 _package = packageName;
 124  1299 _importedFiles = importedFiles;
 125  1299 _importedPackages = importedPackages;
 126    }
 127   
 128    /**The top level type checker does not have a data */
 129  1 protected Data _getData() {
 130  1 throw new RuntimeException("Internal Program Error: _getData() shouldn't get called from TypeChecker. " +
 131    "Please report this bug.");
 132    }
 133   
 134    /** Adds an appropriate definition of junit.framework.TestCase to symbolTable. */
 135  2 protected static SymbolData defineTestCaseClass() {
 136  2 SymbolData testCase = new SymbolData("junit.framework.TestCase");
 137  2 testCase.setIsContinuation(false);
 138  2 testCase.setMav(_publicMav);
 139  2 testCase.setPackage("junit.framework");
 140  2 LanguageLevelConverter.symbolTable.put("junit.framework.TestCase", testCase);
 141  2 return testCase;
 142    }
 143   
 144    /** Returns the SymbolData corresponding to the name className. Checks 1) unqualified or partially-qualified inner
 145    * classes visible in this scope, 2) fully-qualified inner classes, 3) primitives, 4) array types, 5) fully
 146    * qualified top-level classes, 6) imported classes, 7) a top-level class within this package, 8) imported packages,
 147    * and 9) java.lang classes. Assumes that an error should be generated if the class is not found, and that
 148    * classes are not allowed to extend java.lang.Runnable.
 149    * Will always check accessiblity since giveException is assumed to be true.
 150    * @param className The class name to look up which may or may not be fully qualified.
 151    * @param enclosingData The enclosing data -- either a MethodData or a ClassData for this reference
 152    * @param jexpr The AST of the phrase containing the reference.
 153    * */
 154  475 public SymbolData getSymbolData(String className, Data enclosingData, JExpression jexpr) {
 155  475 return getSymbolData(className, enclosingData, jexpr, true);
 156    }
 157   
 158    /** Call the next version of GetSymbolData, but pass it giveException as the flag for whether or not to
 159    * give ambigException.
 160    */
 161  761 public SymbolData getSymbolData(String className, Data enclosingData, JExpression jexpr, boolean giveException) {
 162  761 return getSymbolData(giveException, className, enclosingData, jexpr, giveException);
 163    }
 164   
 165    /** Returns the SymbolData corresponding to the name className. Checks 1) unqualified or partially-qualified inner
 166    * classes visible in this scope, 2) fully-qualified inner classes, 3) primitives, 4) array types, 5) fully
 167    * qualified top-level classes, 6) imported classes, 7) a top-level class within this package, 8) imported packages,
 168    * and 9) java.lang classes. Assumes that classes are not allowed to extend java.lang.Runnable.
 169    * Will only check accessibility if giveException is true.
 170    * */
 171  859 public SymbolData getSymbolData(boolean giveAmbigException, String className, Data enclosingData, JExpression jexpr,
 172    boolean giveException) {
 173  859 Data d = enclosingData;
 174  859 SymbolData result = null;
 175  859 while (d != null && result == null) {
 176  1409 result = enclosingData.getInnerClassOrInterface(className);
 177  1409 d = d.getOuterData();
 178    }
 179   
 180  821 if (result == null) result = getSymbolData(className, jexpr, giveException, true);
 181   
 182  38 else if (result == SymbolData.AMBIGUOUS_REFERENCE) {
 183  6 if (giveAmbigException) {
 184  6 _addError("Ambiguous reference to class or interface " + className, jexpr);
 185  6 return SymbolData.AMBIGUOUS_REFERENCE;
 186    }
 187  0 return null; // return null to indicate we were unable to resolve this.
 188    }
 189  383 if (result == null || ! giveException) return result;
 190  470 if (checkAccess(jexpr, result.getMav(), className, result, enclosingData.getSymbolData(), "class or interface")) {
 191  464 return result;
 192    }
 193  6 else return result;
 194   
 195    }
 196   
 197    /** Returns the SymbolData corresponding to the name className, assuming that className
 198    * does not refer to an unqualified or partially-qualified inner class.
 199    * */
 200  1400 public SymbolData getSymbolData(String className, JExpression jexpr, boolean giveException, boolean runnableNotOkay) {
 201    // Check qualified class name (which is no different at elementary level)
 202  1400 SourceInfo si = jexpr.getSourceInfo();
 203   
 204    // Create a dummy LLV; this seems awkward. TODO: refactor
 205  1400 LanguageLevelVisitor llv =
 206    new LanguageLevelVisitor(_file,
 207    _package,
 208    null, // enclosing class for top level traversal
 209    _importedFiles,
 210    _importedPackages,
 211    new HashSet<String>(),
 212    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 213    new LinkedList<Command>(),
 214    new HashMap<String, SymbolData>());
 215   
 216  1400 LanguageLevelConverter._newSDs.clear();
 217  1400 assert LanguageLevelConverter.symbolTable.containsKey("java.lang.Object");
 218  1400 SymbolData sd = llv.getSymbolData(className, si, false, true); // TODO: Is this right?
 219    // if (sd == null) {
 220    // System.err.println("***ALARM*** The following symbol was not found in symbolTable: " + className);
 221    // }
 222    // else if (sd.getName().equals("java.lang.Throwable"))
 223    // System.err.println("*** Package for retrieved java.lang.Throwable is " + sd.getPackage());
 224  1400 if (sd == null || sd.isContinuation()) {
 225  6 if (giveException) { _addError("Class or variable " + className + " not found.", jexpr); }
 226  90 return null;
 227    }
 228    else {
 229    //Check to see that sd is really in the package it should be in.
 230  1310 if (notRightPackage(sd)) {
 231  24 _addError("The class " + sd.getName() + " is not in the right package. Perhaps you meant to package it?",
 232    jexpr);
 233    }
 234   
 235  1310 if (runnableNotOkay) {
 236  910 if (sd.implementsRunnable()) {
 237  1 _addError(sd.getName() + " implements the Runnable interface, which is not allowed at any language level",
 238    jexpr);
 239  1 return null;
 240    }
 241    }
 242  1309 return sd;
 243    }
 244    }
 245   
 246    /** Return false if the symbolData is in the wrong package.
 247    * @param sd The SymbolData to check.
 248    */
 249  1320 protected boolean notRightPackage(SymbolData sd) {
 250  1320 if (sd.getOuterData() != null) { // if this is an inner class, check its outer data.
 251  10 return notRightPackage(sd.getOuterData().getSymbolData());
 252    }
 253  1310 return (sd.getPackage().equals("") && sd.getName().lastIndexOf('.') != -1) ||
 254    ! sd.getName().startsWith(sd.getPackage());
 255    }
 256   
 257    /** Create a clone of the linked list of Variable Data. */
 258  393 public LinkedList<VariableData> cloneVariableDataList(LinkedList<VariableData> vars) {
 259  393 LinkedList<VariableData> nv = new LinkedList<VariableData>();
 260  393 for (int i = 0; i<vars.size(); i++) {
 261  730 VariableData old = vars.get(i);
 262  730 nv.addLast(old);
 263    }
 264  393 return nv;
 265    }
 266   
 267    /** The Qualified Class Name is the package, followed by a dot, followed by the rest of the class name.
 268    * If the provided className is already qualified, just return it. If the package is not empty,
 269    * and the className does not start with the package, append the package name onto the className, and return it.
 270    * @param className The className to qualify.
 271    */
 272  128 protected String getQualifiedClassName(String className) {
 273  3 if (! _package.equals("") && ! className.startsWith(_package)) { return _package + '.' + className;}
 274  125 else return className;
 275    }
 276   
 277    /** Check to see if the two symbol datas are in the same package.*/
 278  161 private static boolean _areInSamePackage(SymbolData enclosingSD, SymbolData thisSD) {
 279  161 String enclosingSDName = enclosingSD.getName();
 280  161 int lastIndexOfDot = enclosingSDName.lastIndexOf('.');
 281  161 if (lastIndexOfDot != -1) {
 282   
 283    // Check for inner class names:
 284  43 if (enclosingSD.getOuterData() != null) {
 285  11 return _areInSamePackage(enclosingSD.getOuterData().getSymbolData(), thisSD);
 286    }
 287   
 288  32 enclosingSDName = enclosingSDName.substring(0, lastIndexOfDot);
 289    }
 290  118 else { enclosingSDName = ""; }
 291  150 String thisSDName = thisSD.getName();
 292  150 lastIndexOfDot = thisSDName.lastIndexOf('.');
 293  150 if (lastIndexOfDot != -1) {
 294   
 295    //check for inner class names:
 296  34 if (thisSD.getOuterData() != null) {
 297  3 return _areInSamePackage(enclosingSD, thisSD.getOuterData().getSymbolData());
 298    }
 299   
 300  31 thisSDName = thisSDName.substring(0, lastIndexOfDot);
 301    }
 302  116 else { thisSDName = ""; }
 303  147 return enclosingSDName.equals(thisSDName);
 304    }
 305   
 306   
 307    /** Pass a default value*/
 308  205 protected MethodData _lookupMethodHelper(String methodName, SymbolData enclosingSD, InstanceData[] arguments,
 309    JExpression jexpr, boolean isConstructor, SymbolData thisSD) {
 310  205 return _lookupMethodHelper(methodName, enclosingSD, arguments, jexpr, isConstructor, thisSD,
 311    new LinkedList<MethodData>());
 312    }
 313   
 314    /** Finds and returns all matching methods. Assumes that the correct SymbolData is passed in.
 315    * @param methodName The name of the method.
 316    * @param enclosingSD The SymbolData we're currently searching for the method.
 317    * @param arguments The types of the arguments to the method.
 318    * @param jexpr The JExpression for the method invocation used in the error message.
 319    * @param isConstructor True if this method is a constructor. If so, we know it must be in the initial SymbolData.
 320    * @param thisSD The SymbolData whence the method is invoked.
 321    * @return The pair of matching MethodData lists: without autoboxing and with autoboxing.
 322    * An error is added if it is not found.
 323    */
 324  363 protected Pair<LinkedList<MethodData>, LinkedList<MethodData>>
 325    _getMatchingMethods(String methodName, SymbolData enclosingSD, InstanceData[] arguments, JExpression jexpr,
 326    boolean isConstructor, SymbolData thisSD) {
 327  363 LinkedList<MethodData> mds = enclosingSD.getMethods();
 328  363 Iterator<MethodData> iter = mds.iterator();
 329  363 LinkedList<MethodData> matching = new LinkedList<MethodData>();
 330  363 LinkedList<MethodData> matchingWithAutoBoxing = new LinkedList<MethodData>();
 331    // if (enclosingSD.getName().equals("NonEmpty"))
 332    // System.err.println("Starting search for method " + methodName + " in " + enclosingSD);
 333  363 while (iter.hasNext()) {
 334  2634 MethodData md = iter.next();
 335    // System.err.println("Testing method " + md.getName());
 336    // if (md.getName().equals("NonEmpty")) {
 337    // System.err.println("*** for NonEmpty(), params length = " + md.getParams().length + "; args length = "
 338    // + arguments.length);
 339    // }
 340    // Check that the names match.
 341  2634 if (md.getName().equals(methodName) && md.getParams().length == arguments.length) {
 342  281 VariableData[] vds = md.getParams();
 343  281 int i;
 344  281 boolean matches = true;
 345   
 346    // First check to see if any methods exist that match the invocation without using autoboxing
 347  281 for (i = 0; i < vds.length && i < arguments.length; i++) {
 348  234 matches = matches &&
 349    _isAssignableFromWithoutAutoboxing(vds[i].getType().getSymbolData(), arguments[i].getSymbolData());
 350  85 if (matches == false) break;
 351    }
 352   
 353    // if all arguments checked out, check the access stuff.
 354  281 if (matches && checkAccess(jexpr, md.getMav(), md.getName(), enclosingSD, thisSD, "method")) {
 355  196 matching.addLast(md);
 356    }
 357   
 358  281 if (matches == false) { // Didn't match the method directly; try to match it with autoboxing
 359    // if (enclosingSD.getName().equals("NonEmpty")) {
 360    // System.err.println("*** Looking for autoboxing match for NonEmpty");
 361    // System.err.println("vds = " + Arrays.toString(vds) + " arguments = " + Arrays.toString(arguments));
 362    // }
 363  85 matches = true;
 364    // Now check to see if any methods exist that match the invocation while using autoboxing.
 365  85 for (i = 0; i < vds.length && i < arguments.length; i++) {
 366  123 if (enclosingSD.getName().equals("NonEmpty")) {
 367  2 SymbolData parmSD = vds[i].getType().getSymbolData();
 368    // System.err.println("vds[" + i + "].getType().getSymbolData() = " + parmSD);
 369  2 SymbolData argSD = arguments[i].getSymbolData();
 370    // System.err.println("arguments[" + i + "].getSymbolData() = " + argSD);
 371  2 if (argSD.equals(SymbolData.INT_TYPE) && parmSD.equals(symbolTable.get("java.lang.Object")))
 372  1 assert _isAssignableFrom(parmSD, argSD);
 373    }
 374  123 matches = matches && _isAssignableFrom(vds[i].getType().getSymbolData(), arguments[i].getSymbolData());
 375  123 if (matches == false) {
 376  93 if (enclosingSD.getName().equals("NonEmpty"))
 377    // System.err.println("No match found for NonEmpty using autoboxing");
 378  0 break;
 379    }
 380    }
 381   
 382    // if all arguments checked out, check the access stuff.
 383  85 if (matches && checkAccess(jexpr, md.getMav(), md.getName(), enclosingSD, thisSD, "method")) {
 384  11 matchingWithAutoBoxing.addLast(md);
 385    }
 386    }
 387    }
 388    }
 389   
 390  363 if (! isConstructor) {
 391  228 for (SymbolData sup : enclosingSD.getInterfaces()) {
 392  43 Pair<LinkedList<MethodData>, LinkedList<MethodData>> p =
 393    _getMatchingMethods(methodName, sup, arguments, jexpr, isConstructor, thisSD);
 394  43 matching.addAll(p.getFirst());
 395  43 matchingWithAutoBoxing.addAll(p.getSecond());
 396    }
 397  228 if (enclosingSD.getSuperClass() != null) {
 398  115 Pair<LinkedList<MethodData>, LinkedList<MethodData>> p =
 399    _getMatchingMethods(methodName, enclosingSD.getSuperClass(), arguments, jexpr, isConstructor, thisSD);
 400  115 matching.addAll(p.getFirst());
 401  115 matchingWithAutoBoxing.addAll(p.getSecond());
 402    }
 403    }
 404    // if (methodName.equals("NonEmpty")) {
 405    // System.err.println("***** enclosingSD = " + enclosingSD + "; thisSD = " + thisSD + "; matching methods: "
 406    // + matching);
 407    // System.err.println("***** matching methods with autoboxing: " + matchingWithAutoBoxing);
 408    // }
 409   
 410  363 return new Pair<LinkedList<MethodData>, LinkedList<MethodData>> (matching, matchingWithAutoBoxing);
 411    }
 412   
 413    /** Finds which SymbolData this method is in, beginning at this SymbolData and recursively visiting super classes.
 414    * @param methodName The name of the method.
 415    * @param enclosingSD The SymbolData we're currently searching for the method.
 416    * @param arguments The types of the arguments to the method.
 417    * @param jexpr The JExpression for the method invocation used in the error message.
 418    * @param isConstructor Tells us if this method is a constructor. If so, we know it must be in the initial SymbolData.
 419    * We assume that the correct SymbolData was passed in.
 420    * @param thisSD The SymbolData whence the method is invoked.
 421    * @return The SymbolData where we find the method of null if it was not found. An error is added if it is not found.
 422    */
 423  205 protected MethodData _lookupMethodHelper(String methodName, SymbolData enclosingSD, InstanceData[] arguments,
 424    JExpression jexpr, boolean isConstructor, SymbolData thisSD,
 425    LinkedList<MethodData> matchingMethods) {
 426  205 Pair<LinkedList<MethodData>, LinkedList<MethodData>> p = _getMatchingMethods(methodName, enclosingSD, arguments,
 427    jexpr, isConstructor, thisSD);
 428  205 LinkedList<MethodData> matching = p.getFirst();
 429  205 LinkedList<MethodData> matchingWithAutoBoxing = p.getSecond();
 430   
 431    // if this is not a constructor, matching and matchingWithAutoBoxing are both empty, and there is a outer data,
 432    // then look at outer data
 433  205 SymbolData currData = enclosingSD;
 434  205 while (!isConstructor && matching.isEmpty() && matchingWithAutoBoxing.isEmpty() &&
 435    currData.getOuterData() != null) {
 436  0 currData = currData.getOuterData().getSymbolData();
 437  0 p = _getMatchingMethods(methodName, currData, arguments, jexpr, isConstructor, thisSD);
 438  0 matching = p.getFirst();
 439  0 matchingWithAutoBoxing = p.getSecond();
 440    }
 441   
 442  169 if (matching.size() == 1) return matching.getFirst();
 443  12 if (matching.size() > 1) return selectMostSpecificMethod(matching, arguments, jexpr);
 444  5 if (matchingWithAutoBoxing.size() == 1) return matchingWithAutoBoxing.getFirst();
 445  2 if (matchingWithAutoBoxing.size() > 1) return selectMostSpecificMethod(matchingWithAutoBoxing, arguments, jexpr);
 446   
 447    //if nothing matched at all, return null
 448  17 return null;
 449    }
 450   
 451    /** Finds which SymbolData this method is in, beginning at this SymbolData and recursively visiting super classes.
 452    * Adds an error if the method is not found.
 453    * @param methodName The name of the method.
 454    * @param enclosingSD The SymbolData we're currently searching for the method.
 455    * @param arguments The instance types of the arguments to the method.
 456    * @param jexpr The JExpression for the method invocation used in the error message.
 457    * @param errorMsg The error to be displayed if the method cannot be found.
 458    * @param isConstructor True if this method is a constructor. If so, we know it must be in the initial SymbolData.
 459    * We assume that the correct SymbolData was passed in.
 460    * @param thisSD The SymbolData of the initial SymbolData.
 461    * @return The SymbolData containging the method of null if it was not found. An error is added if it is not found.
 462    */
 463  200 protected MethodData _lookupMethod(String methodName, SymbolData enclosingSD, InstanceData[] arguments,
 464    JExpression jexpr, String errorMsg, boolean isConstructor, SymbolData thisSD) {
 465    // if (enclosingSD.isContinuation() && jexpr != null) {
 466    // SymbolData newSD = getSymbolData(enclosingSD.getName(), enclosingSD, jexpr);
 467    // if (newSD != null) {
 468    // System.err.println("Replacing " + enclosingSD + " by " + newSD);
 469    // if (methodName == "getName()" || methodName == "getName") {
 470    // System.err.println("The methods of " + enclosingSD + " are: \n" + enclosingSD.getMethods());
 471    // throw new UnexpectedException("Computation aborted");
 472    //// System.err.println("The methods of " + newSD + " are: \n" + newSD.getMethods());
 473    // }
 474    // enclosingSD = newSD;
 475    // }
 476    // }
 477  200 if (! isConstructor && methodName.equals(LanguageLevelVisitor.getUnqualifiedClassName(enclosingSD.getName()))) {
 478  0 _addError("The keyword 'new' is required to invoke a constructor", jexpr);
 479    }
 480   
 481  200 MethodData md = _lookupMethodHelper(methodName, enclosingSD, arguments, jexpr, isConstructor, thisSD);
 482  200 if (md != null) {
 483  185 return md;
 484    }
 485    // None of the methods matched the signature.
 486  15 StringBuffer message = new StringBuffer(errorMsg + methodName);
 487  15 message.append("(");
 488  15 if (arguments.length > 0) {
 489  5 message.append(arguments[0].getName());
 490  5 for (int i = 1; i < arguments.length; i++) {
 491  1 message.append(", " + arguments[i].getName());
 492    }
 493    }
 494  15 message.append(").");
 495  15 _addError(message.toString(), jexpr);
 496    // If not found, return null and have the caller check for it.
 497  15 return null;
 498    }
 499   
 500    /** Assumes that all methods in list have the same name and the same number of arguments. Selects the method with
 501    * the most specific signature. Assumes that each method does not require the application of any 1.5+ specific
 502    * features.
 503    * @param list The list of methods used
 504    * @return The most specific method among the methods in the given list
 505    */
 506  14 private static MethodData selectMostSpecificMethod(List<MethodData> list, InstanceData[] arguments,
 507    JExpression jexpr) {
 508  0 if (list.isEmpty()) return null;
 509  14 Iterator<MethodData> it = list.iterator();
 510  14 MethodData best = it.next();
 511  14 MethodData ambiguous = null; // there is no ambiguous other method at first
 512  14 while (it.hasNext()) {
 513  17 MethodData curr = it.next();
 514  17 SymbolData[] bestParams = new SymbolData[best.getParams().length];
 515  17 SymbolData[] currParams = new SymbolData[curr.getParams().length];
 516   
 517  17 boolean better1 = false; // whether 'best' is better than 'curr'
 518  17 boolean better2 = false; // whether 'curr' is better than 'best'
 519  17 for (int i = 0; i < bestParams.length; i++) {
 520  23 SymbolData bp = best.getParams()[i].getType().getSymbolData();
 521  23 SymbolData cp = curr.getParams()[i].getType().getSymbolData();
 522  23 boolean fromCurrToBest = cp.isAssignableTo(bp, LanguageLevelConverter.OPT.javaVersion());
 523  23 boolean fromBestToCurr = bp.isAssignableTo(cp, LanguageLevelConverter.OPT.javaVersion());
 524  23 bestParams[i] = bp;
 525  23 currParams[i] = cp;
 526   
 527  23 if (fromBestToCurr && ! fromCurrToBest) { // best's parameter[i] is more specific than curr's
 528  6 better1 = true; // so best is better than curr
 529    }
 530  23 if (fromCurrToBest && ! fromBestToCurr) { // curr's parameter[i] is more specific than best's
 531  6 better2 = true; // so curr is better than best
 532    }
 533    }
 534   
 535    // decide which is more specific or whether they are ambiguous
 536  17 if (better1 == better2) { // neither is better than the other
 537    // Handle overridden methods
 538  7 if (Arrays.equals(bestParams, currParams)) {
 539  5 SymbolData c1 = best.getSymbolData();
 540  5 SymbolData c2 = curr.getSymbolData();
 541  5 boolean c1IsSuperOrSame = c2.isAssignableTo(c1, LanguageLevelConverter.OPT.javaVersion());
 542  5 boolean c2IsSuperOrSame = c1.isAssignableTo(c2, LanguageLevelConverter.OPT.javaVersion());
 543  5 if (c1IsSuperOrSame && !c2IsSuperOrSame) { // c2 is more specific
 544  0 best = curr;
 545  0 continue;
 546    }
 547  5 else if (c2IsSuperOrSame && !c1IsSuperOrSame) { // c1 is more specific
 548  5 continue;
 549    }
 550    }
 551  2 ambiguous = curr;
 552    }
 553  10 else if (better2) {
 554  4 best = curr;
 555  4 ambiguous = null; // no more ambiguity
 556    }
 557    }
 558  14 if (ambiguous != null) {
 559  2 StringBuffer invokeArgs = new StringBuffer("(");
 560  2 StringBuffer ambigArgs = new StringBuffer("(");
 561  2 StringBuffer bestArgs = new StringBuffer("(");
 562  2 for (int i = 0; i<arguments.length; i++) {
 563  4 if (i>0) {
 564  2 invokeArgs.append(", ");
 565  2 ambigArgs.append(", ");
 566  2 bestArgs.append(", ");
 567    }
 568  4 invokeArgs.append(arguments[i].getSymbolData().getName());
 569  4 ambigArgs.append(ambiguous.getParams()[i].getType().getSymbolData().getName());
 570  4 bestArgs.append(best.getParams()[i].getType().getSymbolData().getName());
 571    }
 572  2 invokeArgs.append(")");
 573  2 ambigArgs.append(")");
 574  2 bestArgs.append(")");
 575  2 _addError(best.getName() + invokeArgs.toString() + " is an ambiguous invocation. It matches both "
 576    + best.getName() + bestArgs.toString() + " and " + ambiguous.getName() + ambigArgs.toString(),
 577    jexpr);
 578    }
 579  14 return best;
 580    }
 581   
 582   
 583    /**
 584    * Checks that the method is accessible given the SymbolData it's in and the current SymbolData.
 585    * We have already checked the modifiers for validity.
 586    * This will also work when checking the accessibility of static inner classes by passing in the
 587    * static inner class for enclosingSD.
 588    * @param mav The modifiers and visibility of the thing we're checking
 589    * @param name The name of the thing we're checking
 590    * @param enclosingSD The SymbolData which encloses name
 591    * @param thisSD The SymbolData that is being type checked (from which we're referencing name)
 592    * @param dataType The String that tells us whether name is a field, method, or class.
 593    */
 594  1308 public static boolean checkAccess(JExpression piece, ModifiersAndVisibility mav, String name,
 595    SymbolData enclosingSD, SymbolData thisSD, String dataType) {
 596  1308 return checkAccess(piece, mav, name, enclosingSD, thisSD, dataType, true);
 597    }
 598   
 599   
 600    /** Call this version when you don't want to add an error--only take in what is necessary to do the check, give default
 601    * values for anything that will not be used.
 602    */
 603  124 public static boolean checkAccess(ModifiersAndVisibility mav, SymbolData enclosingSD, SymbolData thisSD) {
 604  124 return checkAccess(NULL_LITERAL, mav, "", enclosingSD, thisSD, "", false);
 605    }
 606   
 607    /** Determines if thisSD can reference specified name defined in enclosingSD. Empty symbol is OK. See preceding
 608    * method body.
 609    * @param mav ??
 610    */
 611  1844 public static boolean checkAccess(JExpression piece, ModifiersAndVisibility mav, String name,
 612    SymbolData enclosingSD, SymbolData thisSD, String dataType, boolean addError) {
 613    // if (piece instanceof VariableReference) System.err.println("**** Checking access of " + piece + "\nin " + enclosingSD);
 614  1844 if (thisSD.isOuterData(enclosingSD) || enclosingSD.isOuterData(thisSD) || thisSD.equals(enclosingSD)) {
 615  726 return true;
 616    }
 617   
 618    // Check for the public modifier.
 619  1118 if (Utilities.isPublic(mav)) {
 620  953 Data enclosingOuter = enclosingSD.getOuterData();
 621  889 if (enclosingOuter == null) return true;
 622  64 if (enclosingOuter instanceof SymbolData) {
 623  64 return checkAccess(piece, mav, name, enclosingSD.getOuterData().getSymbolData(), thisSD, dataType, addError);
 624    }
 625  0 throw new RuntimeException("Internal Program Error: Trying to reference " + name +
 626    "which is a member of something other than a class from outside of that thing. " +
 627    "Please report this bug.");
 628    }
 629   
 630    // Check for the private modifier.
 631  165 if (Utilities.isPrivate(mav)) {
 632    /* As long as one of the symbol datas is the outer data of the other one (at some point down the data chain),
 633    * private classes/methods/fields can be seen. Since we would have already returned, just throw the error and
 634    * return false. */
 635    // Utilities.show(thisSD + " cannot access symbol '" + name + "' within " + enclosingSD + " from '" + thisSD
 636    // + "' in file " + piece.getSourceInfo().getFile());
 637    // if (name.equals("evalVisitor")) throw new UnexpectedException("evalVisitor BUG");
 638  23 String nameWithDots = Data.dollarSignsToDots(name);
 639  23 String enclosingWithDots = Data.dollarSignsToDots(enclosingSD.getName());
 640   
 641    // The following is a kludge to eliminate SOME spurious results.
 642  0 if (nameWithDots.equals(enclosingWithDots) && enclosingSD.isPrimitiveType()) return true;
 643   
 644  23 String siteName = Data.dollarSignsToDots(thisSD.getName());
 645  23 if (addError) {
 646  16 _addError("The " + dataType + " " + nameWithDots + " in " + enclosingWithDots +
 647    " is private and cannot be accessed from " + siteName,
 648    piece);
 649    // throw new UnexpectedException("Generate Debugging Trace for access failure to " + nameWithDots + " in "
 650    // + enclosingWithDots + " from " + siteName); // DEBUG
 651    }
 652    // Utilities.show("enclosingSD = " + enclosingSD + " thisSD = " + thisSD);
 653  23 return false;
 654    }
 655   
 656    // Check for the protected modifier.
 657  142 if (Utilities.isProtected(mav)) {
 658    // Compare the package names. Remember that inner classes have '$' in their names. NO! TODO: Fix this !!!
 659  4 if (_areInSamePackage(enclosingSD, thisSD)) {
 660  2 return true;
 661    }
 662    // Check if thisSD is a subclass of enclosingSD.
 663    // If they are in the same file, they are in the same package, so this does not need to check outer classes,
 664    // only super classes and interfaces.
 665  2 if (thisSD.isSubClassOf(enclosingSD)) {
 666  0 return true;
 667    }
 668    else {
 669  2 if (addError) _addError("The " + dataType + " " + Data.dollarSignsToDots(name) +
 670    " is protected and cannot be accessed from " + Data.dollarSignsToDots(thisSD.getName()),
 671    piece);
 672  2 return false;
 673    }
 674    }
 675   
 676    // Check the default "package modifier"
 677  118 if (_areInSamePackage(enclosingSD, thisSD)) return true;
 678    else {
 679  10 if (addError) _addError("The " + dataType + " " + Data.dollarSignsToDots(name) +
 680    " is package protected because there is no access specifier and cannot be accessed from "
 681    + Data.dollarSignsToDots(thisSD.getName()),
 682    piece);
 683  20 return false;
 684    }
 685    }
 686   
 687    /** Return the field or variable with the name text inside of data. (Referenced from thisSD) */
 688  179 public static VariableData getFieldOrVariable(String text, Data data, SymbolData thisSD, JExpression piece) {
 689  0 if (data == null) return null;
 690  179 return getFieldOrVariable(text, data, thisSD, piece, data.getVars(), true, true);
 691    }
 692   
 693  1 public static VariableData getFieldOrVariable(String text, Data data, SymbolData thisSD, JExpression piece,
 694    LinkedList<VariableData> vars) {
 695  1 return getFieldOrVariable(text, data, thisSD, piece, vars, false, true);
 696    }
 697   
 698   
 699  0 public static VariableData getFieldOrVariable(String text, Data data, SymbolData thisSD, JExpression piece,
 700    LinkedList<VariableData> vars, boolean shouldRecur) {
 701  0 return getFieldOrVariable(text, data, thisSD, piece, vars, shouldRecur, true);
 702    }
 703   
 704    /** This method checks if the identifier called text is a field or variable visible from the context of the param
 705    * "data" and is accessible from the context of thisSD. This will search through all of "data"'s enclosing classes
 706    * (outer class, superclass, interfaces) recursively. This could mean a lot of recursion...
 707    * Returns null if the field or variable is not found.
 708    */
 709  794 public static VariableData getFieldOrVariable(String text, Data data, SymbolData thisSD, JExpression piece,
 710    LinkedList<VariableData> vars, boolean shouldRecur, boolean addError) {
 711  794 VariableData vd = null;
 712  0 if (data == null) return null;
 713   
 714  794 Iterator<VariableData> iter = vars.iterator();
 715  794 while (iter.hasNext()) {
 716  847 vd = iter.next();
 717  847 if (vd != null) {
 718  847 if (vd.getName().equals(text)) {
 719  468 if (vd.getEnclosingData() instanceof MethodData && addError) { // was BodyData
 720    /* If vd is defined in a method and thisSD is a local class or anonymous inner class defined in data, then
 721    * vd must be final to be used. Note: the enclosingData of formal parameters is the enclosing class not
 722    * the corresponding method.
 723    */
 724  95 if (thisSD.isOuterData(vd.getEnclosingData())) {
 725  0 if (! vd.isFinal() && addError) {
 726  0 _addError("Local variable " + vd.getName()
 727    + " is accessed from within an inner class; must be declared final", piece);
 728    }
 729    }
 730    }
 731  468 if (addError) {
 732  461 checkAccess(piece, vd.getMav(), vd.getName(), vd.getEnclosingData().getSymbolData(), thisSD,
 733    "field or variable");
 734    }
 735  468 return vd;
 736    }
 737    }
 738    }
 739   
 740  326 if (shouldRecur) {
 741    /* The enclosingData should contain the super class, then the interfaces, and then the
 742    * outer class. */
 743   
 744  325 Iterator<Data> enclosingData = data.getEnclosingData().iterator();
 745  325 while (enclosingData.hasNext()) {
 746  219 Data outerData = enclosingData.next();
 747  4 if (outerData == null) return null;
 748  215 vd = getFieldOrVariable(text, outerData, thisSD, piece, outerData.getVars(), true, addError);
 749  32 if (vd != null) return vd;
 750    }
 751    }
 752  290 return null;
 753    }
 754   
 755    /** Return true iff type is an instance type. If not, add an error. */
 756  597 public boolean assertInstanceType(TypeData type, String errorMsg, JExpression expression) {
 757  597 if (! type.isInstanceType()) {
 758  38 _addError(errorMsg + ". Perhaps you meant to create a new instance of " + type.getName(), expression);
 759  38 return false;
 760    }
 761  559 return true;
 762    }
 763   
 764    /** If type is a PackageData, then it could not be resolved. Give an error*/
 765  1100 public boolean assertFound(TypeData type, JExpressionIF expression) {
 766  1100 if (type instanceof PackageData) {
 767  19 _addError("Could not resolve symbol " + type.getName(), expression);
 768  19 return false;
 769    }
 770  1081 return true;
 771    }
 772   
 773    /** Adds an error pair consisting of the specified String message and JExpression. Sets _errorAdded to true.
 774    * @param message Error message
 775    * @param that The JExpression corresponding to where the error is.
 776    */
 777  347 protected static void _addError(String message, JExpressionIF that) {
 778  347 _errorAdded = true;
 779  347 Pair<String, JExpressionIF> p = new Pair<String, JExpressionIF>(message, that);
 780  311 if (! errors.contains(p)) errors.addLast(p);
 781    }
 782   
 783    /** Return a TypeData array of the specified size. */
 784  1475 protected TypeData[] makeArrayOfRetType(int len) { return new TypeData[len]; }
 785   
 786    /** This method is called by default from cases that do not
 787    * override forCASEOnly.
 788    **/
 789  1675 protected TypeData defaultCase(JExpressionIF that) { return null; }
 790   
 791  104 public TypeData forClassDefOnly(ClassDef that, TypeData mavRes, TypeData nameRes, TypeData[] typeParametersRes,
 792    TypeData superRes, TypeData[] interfacesRes, TypeData bodyRes) {
 793  104 return forJExpressionOnly(that);//forTypeDefBaseOnly(that, mavRes, nameRes, typeParametersRes);
 794    }
 795   
 796  0 public TypeData forInnerClassDefOnly(InnerClassDef that, TypeData mavRes, TypeData nameRes, TypeData[] typeParamRes,
 797    TypeData superClassRes, TypeData[] interfacesRes, TypeData bodyRes) {
 798  0 return forJExpressionOnly(that);
 799    // replaces forClassDefOnly(that, mavRes, nameRes, typeParamRes, superClassRes, interfacesRes,
 800    // bodyRes);
 801    }
 802   
 803  15 public TypeData forInterfaceDefOnly(InterfaceDef that, TypeData mavRes, TypeData nameRes,
 804    TypeData[] typeParamRes, TypeData[] superinterfacesRes, TypeData bodyRes) {
 805  15 return forJExpressionOnly(that); //forTypeDefBaseOnly(that, mavRes, nameRes, typeParamRes);
 806    }
 807   
 808  0 public TypeData forInnerInterfaceDefOnly(InnerInterfaceDef that, TypeData mavRes, TypeData nameRes,
 809    TypeData[] typeParamRes, TypeData[] superinterfacesRes, TypeData bodyRes) {
 810  0 return forJExpressionOnly(that);
 811    // replaces forInterfaceDefOnly(that, mavRes, nameRes, typeParamRes, superinterfacesRes, bodyRes);
 812    }
 813   
 814  0 public TypeData forInstanceInitializerOnly(InstanceInitializer that, TypeData codeRes) {
 815  0 return forJExpressionOnly(that);//forInitializerOnly(that, codeRes);
 816    }
 817   
 818  0 public TypeData forStaticInitializerOnly(StaticInitializer that, TypeData codeRes) {
 819  0 return forJExpressionOnly(that);//InitializerOnly(that, codeRes);
 820    }
 821   
 822  0 public TypeData forLabeledStatementOnly(LabeledStatement that, TypeData statementRes) {
 823  0 return forJExpressionOnly(that);//StatementOnly(that);
 824    }
 825   
 826  0 public TypeData forBlockOnly(Block that, TypeData[] statementsRes) {
 827  0 return forJExpressionOnly(that);//StatementOnly(that);
 828    }
 829   
 830  0 public TypeData forExpressionStatementOnly(ExpressionStatement that, TypeData exprRes) {
 831  0 return forJExpressionOnly(that);//StatementOnly(that);
 832    }
 833   
 834  0 public TypeData forSwitchStatementOnly(SwitchStatement that, TypeData testRes, TypeData[] casesRes) {
 835  0 return forJExpressionOnly(that);//tatementOnly(that);
 836    }
 837   
 838  18 public TypeData forBreakStatementOnly(BreakStatement that) {
 839    // returns a sentinel value that tells us that this is a break or continue statement.
 840  18 return SymbolData.NOT_FOUND;
 841    }
 842   
 843  0 public TypeData forContinueStatementOnly(ContinueStatement that) {
 844    // returns a sentinel value that tells us that this is a break or continue statement.
 845  0 return SymbolData.NOT_FOUND;
 846    }
 847   
 848  0 public TypeData forReturnStatementOnly(ReturnStatement that) {
 849  0 return forJExpressionOnly(that);//StatementOnly(that);
 850    }
 851   
 852  0 public TypeData forTryCatchStatementOnly(TryCatchStatement that, TypeData tryBlockRes,
 853    TypeData[] catchBlocksRes) {
 854  0 return forJExpressionOnly(that);//StatementOnly(that);
 855    }
 856   
 857  0 public TypeData forMethodDefOnly(MethodDef that, TypeData mavRes, TypeData[] typeParamsRes,
 858    TypeData resRes, TypeData nameRes, TypeData paramsRes,
 859    TypeData[] throwsRes) {
 860  0 return resRes; //forJExpressionOnly(that);
 861    }
 862  0 public TypeData forConcreteMethodDefOnly(ConcreteMethodDef that, TypeData mavRes, TypeData[] typeParamsRes,
 863    TypeData resRes, TypeData nameRes, TypeData paramsRes,
 864    TypeData[] throwsRes, TypeData bodyRes) {
 865  0 return forMethodDefOnly(that, mavRes, typeParamsRes, resRes, nameRes, paramsRes,
 866    throwsRes);
 867    }
 868   
 869    /** Returns the common super type of the two types provided.*/
 870  15 protected SymbolData getCommonSuperTypeBaseCase(SymbolData sdLeft, SymbolData sdRight) {
 871  0 if (sdLeft == SymbolData.EXCEPTION) { return sdRight; }
 872  0 if (sdRight == SymbolData.EXCEPTION) { return sdLeft; }
 873  8 if (_isAssignableFrom(sdLeft, sdRight)) {return sdLeft;}
 874  1 if (_isAssignableFrom(sdRight, sdLeft)) {return sdRight;}
 875  6 return null;
 876    }
 877   
 878    /** Return whether the value on the right can be assigned to the value on the left.
 879    * Uses autoboxing if the user has java 1.5.
 880    */
 881  425 protected static boolean _isAssignableFrom(SymbolData sdLeft, SymbolData sdRight) {
 882  0 if (sdRight == null) return false;
 883    // System.err.println("Java Version = " + LanguageLevelConverter.OPT.javaVersion());
 884  425 assert LanguageLevelConverter.versionSupportsAutoboxing(LanguageLevelConverter.OPT.javaVersion());
 885  425 return sdRight.isAssignableTo(sdLeft, LanguageLevelConverter.OPT.javaVersion());
 886    }
 887   
 888    /** Return whether the value on the right can be assigned to the value on the left. Does not use autoboxing. */
 889  246 protected boolean _isAssignableFromWithoutAutoboxing(SymbolData sdLeft, SymbolData sdRight) {
 890   
 891  0 if (sdRight == null) { return false; }
 892  246 return sdRight.isAssignableTo(sdLeft, JavaVersion.JAVA_1_4); // Version 1.4 used to turn off autoboxing
 893    }
 894   
 895    /**
 896    * The method will add an error for each abstract method in the current SymbolData's inheritance hierarchy
 897    * that does not have a concrete implementation.
 898    * @param sd The SymbolData for the current class definition
 899    * @param classDef The current ClassDef
 900    */
 901  124 protected void _checkAbstractMethods(SymbolData sd, JExpression classDef) {
 902  124 if (sd.hasModifier("abstract") || sd.isInterface()) {
 903    // Our work here is done because an abstract class has no constraints to implement.
 904  4 return;
 905    }
 906  120 LinkedList<MethodData> mds = sd.getMethods();
 907   
 908    //add all concrete methods from our super classes--this is to fix the case where you and your super class extend
 909    //the same interface, and your super class concretely implements the methods--you do not have to also implement them.
 910    //there are other generalizations of this case.
 911    //TODO: Consider optimizing this--it may be slow.
 912  120 LinkedList<MethodData> cmds = _cloneMethodDataList(mds);
 913  120 SymbolData superD = sd.getSuperClass();
 914  120 while (superD != null && !superD.getName().equals("java.lang.Object")) {
 915  52 LinkedList<MethodData> smds = superD.getMethods();
 916  52 for (MethodData md: smds) {
 917  413 if (!md.hasModifier("abstract")) {// && SymbolData.repeatedSignature(cmds, md, false) == null) {
 918  409 cmds.addLast(md);
 919    }
 920    }
 921  52 superD = superD.getSuperClass();
 922    }
 923   
 924    // TODO: Check all enclosingDatas (interfaces too).
 925  120 _checkAbstractMethodsHelper(sd, sd.getSuperClass(), cmds, classDef);
 926    //check interfaces as well:
 927  120 for (SymbolData iSD: sd.getInterfaces()) {
 928  10 _checkAbstractMethodsHelper(sd, iSD, cmds, classDef);
 929    }
 930    }
 931   
 932    /**
 933    * This checks a superclass of the original SymbolData. If this class is not abstract, then we are
 934    * done because this concrete class must have implemented all the abstract methods above it.
 935    * @param origSd The SymbolData for the current class definition
 936    * @param sd The SymbolData for the class in origSd's superclass hierarchy that we're currently examining
 937    * @param concreteMds The list of MethodDatas of concrete methods that we've seen so far
 938    * @param classDef The original ClassDef
 939    */
 940  171 private void _checkAbstractMethodsHelper(SymbolData origSd, SymbolData sd, LinkedList<MethodData> concreteMds,
 941    JExpression classDef) {
 942  171 if (sd == null || (!sd.hasModifier("abstract") && !sd.isInterface())) {
 943  139 return;
 944    }
 945    // Gets its abstract methods and make sure they're in concreteMds.
 946  32 LinkedList<MethodData> mds = sd.getMethods();
 947  32 Iterator<MethodData> iter = mds.iterator();
 948  32 while (iter.hasNext()) {
 949  122 MethodData md = iter.next();
 950  122 if (md.hasModifier("abstract")) {
 951    // Check if this md is overridden by one of the MethodDatas in the list of concreteMds.
 952  42 MethodData matchingMd = SymbolData.repeatedSignature(concreteMds, md);
 953  42 if (matchingMd == null) {
 954  4 StringBuffer message;
 955  4 if (classDef instanceof AnonymousClassInstantiation) {
 956  2 message = new StringBuffer("This anonymous inner class must override the abstract method: " + md.getName());
 957    }
 958    else {
 959  2 message = new StringBuffer(origSd.getName()
 960    + " must be declared abstract or must override the abstract method: "
 961    + md.getName());
 962    }
 963  4 VariableData[] params = md.getParams();
 964  4 InstanceData[] arguments = new InstanceData[params.length];
 965  4 for (int i = 0; i < params.length; i++) {
 966  4 arguments[i] = params[i].getType().getInstanceData();
 967    }
 968  4 message.append("(");
 969  4 if (arguments.length > 0) {
 970  2 message.append(arguments[0].getName());
 971  2 for (int i = 1; i < arguments.length; i++) {
 972  2 message.append(", " + arguments[i].getName());
 973    }
 974    }
 975  4 message.append(") in " + sd.getName());
 976  4 _addError(message.toString(), classDef);
 977    }
 978    }
 979    else {
 980    // Update the list of concrete methods.
 981  80 concreteMds.addLast(md);
 982    }
 983    }
 984    //check the super class
 985  32 _checkAbstractMethodsHelper(origSd, sd.getSuperClass(), _cloneMethodDataList(concreteMds), classDef);
 986   
 987    //check the interfaces
 988  32 for (SymbolData iSD: sd.getInterfaces()) {
 989  6 _checkAbstractMethodsHelper(origSd, iSD, _cloneMethodDataList(concreteMds), classDef);
 990    }
 991    }
 992   
 993    /**Create a new LinkedList that holds the method datas in mds*/
 994  158 private LinkedList<MethodData> _cloneMethodDataList(LinkedList<MethodData> mds) {
 995  158 LinkedList<MethodData> toReturn = new LinkedList<MethodData>();
 996  158 for (int i = 0; i<mds.size(); i++) {
 997  1574 toReturn.addLast(mds.get(i));
 998    }
 999  158 return toReturn;
 1000    }
 1001   
 1002    /**
 1003    * Make a copy of the provided symbol data list, and return that copy.
 1004    * @param l The LinkedList of SymbolDatas to copy.
 1005    * @return A copy of l.
 1006    */
 1007  180 private LinkedList<SymbolData> cloneSDList(LinkedList<SymbolData> l) {
 1008  180 LinkedList<SymbolData> l2 = new LinkedList<SymbolData>();
 1009  180 for (int i = 0; i< l.size(); i++) {
 1010  259 l2.addLast(l.get(i));
 1011    }
 1012  180 return l2;
 1013    }
 1014   
 1015    /**
 1016    * Checks for cyclic inheritance by traversing sd's list of superclasses and interfaces and checking if we've
 1017    * seen them before. We accumulate the list of classes and interfaces we've seen before in hierarchy.
 1018    * @param sd The SymbolData we're currently checking
 1019    * @param hierarchy The list of classes and interfaces we've seen before.
 1020    * @return Whether there is cyclic inheritance
 1021    */
 1022  342 protected boolean checkForCyclicInheritance(SymbolData sd, LinkedList<SymbolData> hierarchy, TypeDefBase tdb) {
 1023  342 if (sd==null || LanguageLevelVisitor.isJavaLibraryClass(sd.getName())) {
 1024    // We can stop checking because these can't have cyclic inheritance
 1025  158 return false;
 1026    }
 1027   
 1028   
 1029  184 if (hierarchy.contains(sd)) {
 1030  4 _addError("Cyclic inheritance involving " + sd.getName(), tdb);
 1031  4 return true;
 1032    }
 1033   
 1034    //add current symbol data to the hierarchy
 1035  180 hierarchy.addLast(sd);
 1036   
 1037    //Also add inner classes
 1038  180 LinkedList<SymbolData> innerClasses = sd.getInnerClasses();
 1039  180 for (int i = 0; i < innerClasses.size(); i++) {
 1040  8 hierarchy.addLast(innerClasses.get(i));
 1041    }
 1042   
 1043  180 LinkedList<SymbolData> clonedHierarchy = cloneSDList(hierarchy);
 1044  180 boolean doReturn = checkForCyclicInheritance(sd.getSuperClass(), clonedHierarchy, tdb);
 1045   
 1046    //check the interfaces
 1047  180 for (SymbolData iSD: sd.getInterfaces()) {
 1048  33 doReturn |= checkForCyclicInheritance(iSD, clonedHierarchy, tdb);
 1049    }
 1050   
 1051  180 return doReturn;
 1052    }
 1053   
 1054    /**Do what is necessary to handle a class def */
 1055  107 public TypeData forClassDef(ClassDef that) {
 1056   
 1057  107 SymbolData objectSD = getSymbolData("java.lang.Object", that, true, false);
 1058  107 assert SymbolData.INT_TYPE.isAssignableTo(objectSD, LanguageLevelConverter.OPT.javaVersion());
 1059   
 1060  107 String className = getQualifiedClassName(that.getName().getText());
 1061  107 SymbolData sd = getSymbolData(className, that, true, false);
 1062  107 if (sd == null) {
 1063    // System.err.println("****DISASTER**** sd is null for ClassDef " + className);
 1064  0 _addError("The class " + className + " was never defined", that);
 1065  0 _log.log("*********DISASTER**** sd is null for ClassDef " + className);
 1066  0 return null;
 1067    }
 1068    // Check for cyclic inheritance
 1069  107 if (checkForCyclicInheritance(sd, new LinkedList<SymbolData>(), that)) {
 1070  1 return null;
 1071    }
 1072   
 1073    // See if sd is public. If so, the filename must match sd's name.
 1074  106 if (sd.hasModifier("public")) {
 1075  15 String fileName = className.replace('.', System.getProperty("file.separator").charAt(0));
 1076  15 if (!_file.getAbsolutePath().endsWith(fileName + ".dj") &&
 1077    !_file.getAbsolutePath().endsWith(fileName + ".dj0") &&
 1078    !_file.getAbsolutePath().endsWith(fileName + ".dj1") &&
 1079    !_file.getAbsolutePath().endsWith(fileName + ".dj2")) {
 1080  1 _addError(className + " is public thus must be defined in a file with the same name.", that.getName());
 1081    }
 1082    }
 1083   
 1084    // Reset sd's anonymous inner class count so we can count again during this second pass.
 1085  106 sd.setAnonymousInnerClassNum(0);
 1086   
 1087    // Make sure this class does not implement the Runnable interface
 1088  106 if (sd.hasInterface(getSymbolData("java.lang.Runnable", that, false, false))) {
 1089  1 _addError(sd.getName() + " implements the Runnable interface, which is not allowed at any language level", that);
 1090    }
 1091   
 1092  106 SymbolData superClass = sd.getSuperClass();
 1093    // make sure this class can see its super class
 1094  106 if (superClass != null) {
 1095  104 checkAccess(that.getSuperclass(), superClass.getMav(), superClass.getName(), superClass, sd, "class");
 1096    //Also make sure that the superClass is not an interface!
 1097  104 if (superClass.isInterface()) {
 1098  1 _addError(superClass.getName() + " is an interface and thus cannot appear after the keyword 'extends' here. "
 1099    + "Perhaps you meant to say 'implements'?", that);
 1100    }
 1101    }
 1102   
 1103    //make sure that the class def does not extend a final class.
 1104  106 if (superClass != null && superClass.hasModifier("final")) {
 1105  1 _addError("Class " + sd.getName() + " cannot extend the final class " + superClass.getName(), that);
 1106  1 return sd;
 1107    }
 1108   
 1109  105 final TypeData mavRes = that.getMav().visit(this);
 1110  105 final TypeData nameRes = that.getName().visit(this);
 1111  105 final TypeData[] typeParamRes = makeArrayOfRetType(that.getTypeParameters().length);
 1112  105 for (int i = 0; i < that.getTypeParameters().length; i++) {
 1113  0 typeParamRes[i] = that.getTypeParameters()[i].visit(this);
 1114    }
 1115  105 final TypeData superClassRes = that.getSuperclass().visit(this);
 1116  105 final SymbolData[] interfacesRes = new SymbolData[that.getInterfaces().length];
 1117  105 for (int i = 0; i < that.getInterfaces().length; i++) {
 1118  15 interfacesRes[i] = getSymbolData(that.getInterfaces()[i].getName(), that.getInterfaces()[i], true, true);
 1119  15 if (interfacesRes[i] != null) {
 1120    //make sure this class can see the interfaces it implements
 1121  15 checkAccess(that.getInterfaces()[i], interfacesRes[i].getMav(), interfacesRes[i].getName(), interfacesRes[i], sd,
 1122    "interface");
 1123    //Make sure that all of these are actually interfaces.
 1124  15 if (!interfacesRes[i].isInterface()) {
 1125  1 _addError(interfacesRes[i].getName() +
 1126    " is not an interface and thus cannot appear after the keyword 'implements' here. " +
 1127    "Perhaps you meant to say 'extends'?", that);
 1128    }
 1129   
 1130    }
 1131    else {
 1132  0 throw new RuntimeException("Internal Program Error: getSymbolData( " + that.getInterfaces()[i].getName() +
 1133    ") returned null. Please report this bug.");
 1134    }
 1135    }
 1136   
 1137    //See if sd is a test class. If so, it must be public.
 1138  105 SymbolData testSd = getSymbolData("junit.framework.TestCase", NULL_LITERAL, false, true);
 1139  105 if (testSd != null && sd.isSubClassOf(testSd)) {
 1140  7 if (! sd.hasModifier("public")) {
 1141  1 _addError(sd.getName() + " extends TestCase and thus must be explicitly declared public", that);
 1142    }
 1143  7 boolean foundOne = false;
 1144  7 for (int i = 0; i < sd.getMethods().size(); i++) {
 1145  6 MethodData myMd = sd.getMethods().get(i);
 1146  6 if (myMd.getName().startsWith("test") && (myMd.getReturnType() == SymbolData.VOID_TYPE) &&
 1147    myMd.hasModifier("public")) {
 1148  5 foundOne = true;
 1149  5 break;
 1150    }
 1151    }
 1152  7 if (! foundOne) {
 1153  2 _addError("Class " + sd.getName() + " does not have any valid test methods. " +
 1154    "Test methods must be declared public, must return void, and must start with the word \"test\"",
 1155    that);
 1156    }
 1157    }
 1158   
 1159  105 ClassBodyTypeChecker cbtc =
 1160    new ClassBodyTypeChecker(sd, _file, _package, _importedFiles, _importedPackages, new LinkedList<VariableData>(),
 1161    new LinkedList<Pair<SymbolData, JExpression>>());
 1162   
 1163   
 1164  105 final TypeData bodyRes = that.getBody().visit(cbtc);
 1165   
 1166    // Make sure that sd's methods override all of its hierarchy's abstract methods.
 1167  105 _checkAbstractMethods(sd, that);
 1168   
 1169   
 1170    //only do this if there were no constructors: make sure that all final fields were given a value.
 1171  105 if (! cbtc.hasConstructor) {
 1172  89 LinkedList<VariableData> sdVars = sd.getVars();
 1173  89 for (int i = 0; i<sdVars.size(); i++) {
 1174  57 if (!sdVars.get(i).hasValue()) {
 1175  1 _addError("The final field " + sdVars.get(i).getName() + " has not been initialized", that);
 1176  1 return null;
 1177    }
 1178    }
 1179    }
 1180   
 1181    // Unassign anything that got assigned in the scope of the class def.
 1182  104 unassignVariableDatas(cbtc.thingsThatHaveBeenAssigned);
 1183   
 1184  104 return forClassDefOnly(that, mavRes, nameRes, typeParamRes, superClassRes, interfacesRes, bodyRes);
 1185    }
 1186   
 1187    /**Do everything necessary to handle an interface*/
 1188  16 public TypeData forInterfaceDef(InterfaceDef that) {
 1189  16 String interfaceName = getQualifiedClassName(that.getName().getText());
 1190  16 SymbolData sd = getSymbolData(interfaceName, that, true, false);
 1191   
 1192    // //See if sd is public. If so, the filename must match sd's name.
 1193  16 if (sd.hasModifier("public")) {
 1194  3 String fileName = interfaceName.replace('.', System.getProperty("file.separator").charAt(0));
 1195  3 if (!_file.getAbsolutePath().endsWith(fileName + ".dj") &&
 1196    !_file.getAbsolutePath().endsWith(fileName + ".dj0") &&
 1197    !_file.getAbsolutePath().endsWith(fileName + ".dj1") &&
 1198    !_file.getAbsolutePath().endsWith(fileName + ".dj2")) {
 1199  1 _addError(interfaceName + " is public thus must be defined in a file with the same name.", that.getName());
 1200    }
 1201    }
 1202   
 1203    // Check for cyclic inheritance
 1204  16 if (checkForCyclicInheritance(sd, new LinkedList<SymbolData>(), that)) {
 1205  1 return null;
 1206    }
 1207   
 1208    // // Make sure that this does not extend the runnable interface
 1209    // if (sd.hasInterface(getSymbolData("java.lang.Runnable", that, false, false))) {
 1210    // _addError(sd.getName() + " extends the Runnable interface, which is not allowed at any language level", that);
 1211    // }
 1212   
 1213  15 final TypeData mavRes = that.getMav().visit(this);
 1214  15 final TypeData nameRes = that.getName().visit(this);
 1215  15 final TypeData[] typeParamRes = makeArrayOfRetType(that.getTypeParameters().length);
 1216  15 for (int i = 0; i < that.getTypeParameters().length; i++) {
 1217  0 typeParamRes[i] = that.getTypeParameters()[i].visit(this);
 1218    }
 1219  15 final SymbolData[] interfacesRes = new SymbolData[that.getInterfaces().length];
 1220  15 for (int i = 0; i < that.getInterfaces().length; i++) {
 1221    //superinterfacesRes[i] = that.getInterfaces()[i].visit(this);
 1222  8 interfacesRes[i]=getSymbolData(that.getInterfaces()[i].getName(), that.getInterfaces()[i], true, true);
 1223  8 if (interfacesRes[i] != null) {
 1224    //make sure this class can see the interfaces it implements
 1225  8 checkAccess(that.getInterfaces()[i], interfacesRes[i].getMav(), interfacesRes[i].getName(), interfacesRes[i], sd,
 1226    "interface");
 1227  8 if (!interfacesRes[i].isInterface()) {
 1228  1 _addError(interfacesRes[i].getName() +
 1229    " is not an interface and thus cannot appear after the keyword 'extends' here",
 1230    that);
 1231    }
 1232    }
 1233    else {
 1234  0 throw new RuntimeException("Internal Program Error: getSymbolData( " + that.getInterfaces()[i].getName() +
 1235    ") returned null. Please report this bug.");
 1236    }
 1237   
 1238    }
 1239  15 InterfaceBodyTypeChecker ibtc =
 1240    new InterfaceBodyTypeChecker(sd, _file, _package, _importedFiles, _importedPackages,
 1241    new LinkedList<VariableData>(), new LinkedList<Pair<SymbolData, JExpression>>());
 1242  15 final TypeData bodyRes = that.getBody().visit(ibtc);
 1243  15 return forInterfaceDefOnly(that, mavRes, nameRes, typeParamRes, interfacesRes, bodyRes);
 1244    }
 1245   
 1246    /** Retrieve the class being imported from the Symbol table, and make sure it is public. */
 1247  5 public TypeData forClassImportStatement(ClassImportStatement that) {
 1248  5 CompoundWord cWord = that.getCWord();
 1249  5 Word[] words = cWord.getWords();
 1250   
 1251  5 StringBuffer name = new StringBuffer(words[0].getText());
 1252  8 for (int i = 1; i < words.length; i++) {name.append('.' + words[i].getText());}
 1253    //This makes sure the class can be imported and is in the right package.
 1254  5 final TypeData cWordRes = getSymbolData(name.toString(), that, true, true);
 1255  5 if (cWordRes != null) {
 1256  5 if (! cWordRes.hasModifier("public")) {
 1257  0 _addError(cWordRes.getName() + " is not public, and thus cannot be seen here", that);
 1258    }
 1259    }
 1260  5 return forClassImportStatementOnly(that, cWordRes);
 1261    }
 1262   
 1263    /**
 1264    * Make sure that the package being imported does not conflict with another class in the symbol table, since
 1265    * we will not allow a package to be imported if it has the same name as a class.
 1266    */
 1267  3 public TypeData forPackageStatement(PackageStatement that) {
 1268    //final SymbolData cWordRes = that.getCWord().visit(this);
 1269  3 CompoundWord cWord = that.getCWord();
 1270  3 Word[] words = cWord.getWords();
 1271   
 1272  3 StringBuffer nameBuff = new StringBuffer(words[0].getText());
 1273  3 for (int i = 1; i < words.length; i++) nameBuff.append('.' + words[i].getText());
 1274  3 String name = nameBuff.toString();
 1275   
 1276    /* It is sufficient to just use "get" directly from the symbolTable, becuase the first pass has resolved all
 1277    * package names as symbols (??), so if we were successful, they will already be in symbol table. It is not
 1278    * necessary to check accessibility, because somewhere along the line, the package must have conflicted with
 1279    * a visible class--all top level classes must be public or package protected. */
 1280  3 if (symbolTable.get(name) != null) {
 1281  1 _addError(name + " is not a allowable package name, because it conflicts with a class you have already defined",
 1282    that);
 1283    }
 1284  3 return null;
 1285    }
 1286   
 1287    /** @return the appropriate type for a primitive type.*/
 1288  4 public TypeData forPrimitiveType(PrimitiveType that) {
 1289  4 String text = that.getName();
 1290  4 if (text.equals("boolean")) {
 1291  0 return SymbolData.BOOLEAN_TYPE;
 1292    }
 1293  4 else if (text.equals("char")) {
 1294  0 return SymbolData.CHAR_TYPE;
 1295    }
 1296  4 else if (text.equals("byte")) {
 1297  0 return SymbolData.BYTE_TYPE;
 1298    }
 1299  4 else if (text.equals("short")) {
 1300  0 return SymbolData.SHORT_TYPE;
 1301    }
 1302  4 else if (text.equals("int")) {
 1303  1 return SymbolData.INT_TYPE;
 1304    }
 1305  3 else if (text.equals("long")) {
 1306  0 return SymbolData.LONG_TYPE;
 1307    }
 1308  3 else if (text.equals("float")) {
 1309  0 return SymbolData.FLOAT_TYPE;
 1310    }
 1311  3 else if (text.equals("double")) {
 1312  2 return SymbolData.DOUBLE_TYPE;
 1313    }
 1314    else {
 1315  1 throw new RuntimeException("Internal Program Error: Not a legal primitive type: " + text
 1316    + ". Please report this bug");
 1317    }
 1318    }
 1319   
 1320    /**Visit the type of the cast expression as well as the value being cast*/
 1321  0 public TypeData forCastExpression(CastExpression that) {
 1322  0 final TypeData typeRes = that.getType().visit(this);
 1323  0 final TypeData valueRes = that.getValue().visit(this);
 1324  0 if (valueRes == null) {
 1325    // An error occurred type-checking the value; return the expected type to
 1326    // allow type-checking to continue.
 1327  0 return typeRes;
 1328    }
 1329  0 return forCastExpressionOnly(that, typeRes, valueRes);
 1330    }
 1331   
 1332    /**
 1333    * Walk the provided list of VariableDatas, and set each one back to unassigned.
 1334    * This is used to correct the changes to VariableDatas made when we change scope.
 1335    * VariableDatas will only be in this list if they are assigned for the first time
 1336    * in a context that we are now leaving.
 1337    * @param toUnassign A LinkedList of VariableDatas to set back to unassigned.
 1338    */
 1339  252 void unassignVariableDatas(LinkedList<VariableData> toUnassign) {
 1340  252 for (int i = 0; i<toUnassign.size(); i++) {
 1341  25 toUnassign.get(i).lostValue();
 1342    }
 1343    }
 1344   
 1345    /** Test the methods defined in the above class. */
 1346    public static class TypeCheckerTest extends TestCase {
 1347   
 1348    private TypeChecker _btc;
 1349   
 1350    private SymbolData _sd1;
 1351    private SymbolData _sd2;
 1352    private SymbolData _sd3;
 1353    private SymbolData _sd4;
 1354    private SymbolData _sd5;
 1355    private SymbolData _sd6;
 1356    private SymbolData _object;
 1357   
 1358  0 public TypeCheckerTest() { this(""); }
 1359  20 public TypeCheckerTest(String name) { super(name); }
 1360   
 1361  20 public void setUp() {
 1362  20 errors = new LinkedList<Pair<String, JExpressionIF>>();
 1363  20 LanguageLevelConverter.symbolTable.clear();
 1364  20 LanguageLevelConverter.loadSymbolTable();
 1365   
 1366  20 _btc = new TypeChecker(new File(""), "", new LinkedList<String>(), new LinkedList<String>());
 1367  20 LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, EmptyIterable.<File>make());
 1368  20 _btc._importedPackages.addFirst("java.lang");
 1369  20 _errorAdded = false;
 1370  20 _sd1 = new SymbolData("i.like.monkey");
 1371  20 _sd2 = new SymbolData("i.like.giraffe");
 1372  20 _sd3 = new SymbolData("zebra");
 1373  20 _sd4 = new SymbolData("u.like.emu");
 1374  20 _sd5 = new SymbolData("");
 1375  20 _sd6 = new SymbolData("cebu");
 1376   
 1377  20 _object = symbolTable.get("java.lang.Object");
 1378  20 assert _object != null;
 1379    // o.setIsContinuation(false);
 1380    // o.setMav(_publicMav);
 1381    // symbolTable.put("java.lang.Object", o);
 1382   
 1383  20 assert symbolTable.get("java.lang.Double") != null;
 1384    // Double.setIsContinuation(false);
 1385    // Double.setMav(_publicMav);
 1386    // Double.setSuperClass(o); // a white lie for this test
 1387    // symbolTable.put("java.lang.Double", Double);
 1388   
 1389  20 assert symbolTable.get("java.lang.Float") != null;
 1390    // Float.setIsContinuation(false);
 1391    // Float.setMav(_publicMav);
 1392    // Float.setSuperClass(o); // a white lie for this test
 1393    // symbolTable.put("java.lang.Float", Float);
 1394   
 1395  20 assert symbolTable.get("java.lang.Long") != null;
 1396    // Long.setIsContinuation(false);
 1397    // Long.setMav(_publicMav);
 1398    // Long.setSuperClass(o); // a white lie for this test
 1399    // symbolTable.put("java.lang.Long", Long);
 1400   
 1401  20 assert symbolTable.get("java.lang.Integer") != null;
 1402    // Integer.setIsContinuation(false);
 1403    // Integer.setMav(_publicMav);
 1404    // Integer.setSuperClass(o); // a white lie for this test
 1405    // symbolTable.put("java.lang.Integer", Integer);
 1406   
 1407  20 assert symbolTable.get("java.lang.Short") != null;
 1408    // Short.setIsContinuation(false);
 1409    // Short.setMav(_publicMav);
 1410    // Short.setSuperClass(o); // a white lie for this test
 1411    // symbolTable.put("java.lang.Short", Short);
 1412   
 1413  20 assert symbolTable.get("java.lang.Character") != null;
 1414    // Character.setIsContinuation(false);
 1415    // Character.setMav(_publicMav);
 1416    // Character.setSuperClass(o); // a white lie for this test
 1417    // symbolTable.put("java.lang.Character", Character);
 1418   
 1419  20 assert symbolTable.get("java.lang.Byte") != null;
 1420    // Byte.setIsContinuation(false);
 1421    // Byte.setMav(_publicMav);
 1422    // Byte.setSuperClass(o); // a white lie for this test
 1423    // symbolTable.put("java.lang.Byte", Byte);
 1424   
 1425  20 assert symbolTable.get("java.lang.Boolean") != null;
 1426    // Boolean.setIsContinuation(false);
 1427    // Boolean.setMav(_publicMav);
 1428    // Boolean.setSuperClass(o); // a white lie for this test
 1429    // symbolTable.put("java.lang.Boolean", Boolean);
 1430   
 1431  20 assert symbolTable.get("java.lang.String") != null;
 1432    // SymbolData string = new SymbolData("java.lang.String");
 1433    // string.setIsContinuation(false);
 1434    // string.setMav(_publicMav);
 1435    // string.setSuperClass(_object); // a white lie for this test
 1436    // symbolTable.put("java.lang.String", string);
 1437    }
 1438   
 1439  1 public void test_getData() {
 1440  1 try {
 1441  1 _btc._getData();
 1442  0 fail("Should have thrown a RuntimeException");
 1443    }
 1444    catch (RuntimeException re) {
 1445    }
 1446    }
 1447   
 1448  1 public void testGetSymbolData() {
 1449  1 symbolTable.put("zebra", _sd3);
 1450  1 _sd3.setIsContinuation(false);
 1451  1 SymbolData sd = symbolTable.get("java.lang.Object");
 1452  1 sd.setPackage("java.lang");
 1453  1 assertEquals("Should get _sd3 from the Symboltable.", _sd3,
 1454    _btc.getSymbolData("zebra", NULL_LITERAL, true, true));
 1455  1 assertEquals("Should get sd from the Symboltable.", sd,
 1456    _btc.getSymbolData("java.lang.Object", NULL_LITERAL, true, true));
 1457  1 _btc.getSymbolData("koala", NULL_LITERAL, true, true);
 1458   
 1459  1 assertEquals("Should be one error", 1, errors.size());
 1460  1 assertEquals("ERror message should be correct ", "Class or variable koala not found.", errors.get(0).getFirst());
 1461   
 1462  1 errors = new LinkedList<Pair<String, JExpressionIF>>();
 1463   
 1464  1 sd.setPackage("notRightPackage");
 1465  1 _btc.getSymbolData("java.lang.Object", NULL_LITERAL, true, true);
 1466  1 assertEquals("Should be 1 error", 1, errors.size());
 1467  1 assertEquals("Error message should be correct",
 1468    "The class java.lang.Object is not in the right package. Perhaps you meant to package it?",
 1469    errors.get(0).getFirst());
 1470   
 1471    //looking up a class that implements runnable will give an error:
 1472  1 SymbolData sdThread = new SymbolData("java.lang.Thread");
 1473  1 sdThread.setIsContinuation(false);
 1474  1 sdThread.setPackage("java.lang");
 1475  1 symbolTable.put("java.lang.Thread", sdThread);
 1476  1 assertEquals("Should return null", null, _btc.getSymbolData("Thread", NULL_LITERAL, true,
 1477    true));
 1478   
 1479  1 assertEquals("Should now be 2 errors", 2, errors.size());
 1480  1 assertEquals("Error message should be correct", "java.lang.Thread implements the Runnable interface, " +
 1481    "which is not allowed at any language level", errors.get(1).getFirst());
 1482   
 1483    // a class that implements Runnable, but was not user defined and is not one of our specific classes known to
 1484    // extend Runnable will not give an error
 1485  1 SymbolData sdOther = new SymbolData("myClass");
 1486  1 sdOther.setIsContinuation(false);
 1487  1 SymbolData run = new SymbolData("java.lang.Runnable");
 1488  1 run.setIsContinuation(false);
 1489  1 run.setInterface(true);
 1490  1 run.setPackage("java.lang");
 1491  1 sdOther.addInterface(run);
 1492   
 1493  1 symbolTable.put("myClass", sdOther);
 1494  1 symbolTable.put("java.lang.Runnable", run);
 1495   
 1496  1 assertEquals("Should return sdOther", sdOther, _btc.getSymbolData("myClass", NULL_LITERAL,
 1497    true, true));
 1498  1 assertEquals("Should still just be 2 errors", 2, errors.size());
 1499   
 1500    //Test an inner class from the context of the outer class
 1501  1 SymbolData sdInner = new SymbolData("outer.inner");
 1502  1 sdInner.setIsContinuation(false);
 1503  1 SymbolData sdOuter = new SymbolData("outer");
 1504  1 sd.setIsContinuation(false);
 1505  1 sdOuter.addInnerClass(sdInner);
 1506  1 sdInner.setOuterData(sdOuter);
 1507  1 assertEquals("Should return sdInner", sdInner, _btc.getSymbolData("inner", sdOuter,
 1508    NULL_LITERAL));
 1509   
 1510    //Test an inner interface from the context of the outer class
 1511  1 sdInner.setInterface(true);
 1512  1 sdOuter = new SymbolData("outer");
 1513  1 sd.setIsContinuation(false);
 1514  1 sdOuter.addInnerInterface(sdInner);
 1515  1 assertEquals("Should return sdInner", sdInner, _btc.getSymbolData("inner", sdOuter,
 1516    NULL_LITERAL));
 1517   
 1518   
 1519    //Test that the correct inner class is returned
 1520    //
 1521    // C {
 1522    // A {
 1523    //
 1524    // D{}
 1525    // }
 1526    // B{
 1527    // D{}
 1528    // }
 1529    // }
 1530   
 1531  1 SymbolData sd1 = new SymbolData("C.A");
 1532  1 SymbolData sd2 = new SymbolData("C.B");
 1533  1 SymbolData sd3 = new SymbolData("C");
 1534  1 SymbolData sd4 = new SymbolData("C.A.D");
 1535  1 SymbolData sd5 = new SymbolData("C.B.D");
 1536  1 sd1.setIsContinuation(false);
 1537  1 sd2.setIsContinuation(false);
 1538  1 sd3.setIsContinuation(false);
 1539  1 sd4.setIsContinuation(false);
 1540  1 sd5.setIsContinuation(false);
 1541   
 1542  1 sd1.addInnerClass(sd4);
 1543  1 sd4.setOuterData(sd1);
 1544  1 sd2.addInnerClass(sd5);
 1545  1 sd5.setOuterData(sd2);
 1546  1 sd3.addInnerClass(sd1);
 1547  1 sd1.setOuterData(sd3);
 1548  1 sd3.addInnerClass(sd2);
 1549  1 sd2.setOuterData(sd3);
 1550   
 1551  1 assertEquals("Should return A.D", sd4, _btc.getSymbolData("A.D", sd3, NULL_LITERAL));
 1552  1 assertEquals("Should return B.D", sd5, _btc.getSymbolData("B.D", sd3, NULL_LITERAL));
 1553  1 assertEquals("Should return null", null, _btc.getSymbolData("D", sd3, NULL_LITERAL));
 1554  1 assertEquals("Should return B", sd2, _btc.getSymbolData("B", sd1, NULL_LITERAL));
 1555  1 assertEquals("Should return C.A", sd1, _btc.getSymbolData("A", sd5, NULL_LITERAL));
 1556    //Test a class defined in the context of a method
 1557  1 MethodData md = new MethodData("myMethod", _publicMav, new TypeParameter[0],
 1558    SymbolData.INT_TYPE, new VariableData[0], new String[0], sdOuter,
 1559    NULL_LITERAL);
 1560  1 md.addInnerClass(sd3);
 1561  1 assertEquals("Should return sd3", sd3, _btc.getSymbolData("C", md, NULL_LITERAL));
 1562    }
 1563   
 1564  1 public void testGetQualifiedClassName() {
 1565    //first test when the package is empty:
 1566  1 _btc._package = "";
 1567  1 assertEquals("Should not change qualified name.", "simpson.Bart", _btc.getQualifiedClassName("simpson.Bart"));
 1568  1 assertEquals("Should not change unqualified name.", "Lisa", _btc.getQualifiedClassName("Lisa"));
 1569   
 1570    //now test when package is not empty.
 1571  1 _btc._package="myPackage";
 1572  1 assertEquals("Should not change properly packaged qualified name.", "myPackage.Snowball",
 1573    _btc.getQualifiedClassName("myPackage.Snowball"));
 1574  1 assertEquals("Should append package to front of not fully packaged name", "myPackage.simpson.Snowball",
 1575    _btc.getQualifiedClassName("simpson.Snowball"));
 1576  1 assertEquals("Should append package to front of unqualified class name.", "myPackage.Grandpa",
 1577    _btc.getQualifiedClassName("Grandpa"));
 1578    }
 1579   
 1580  1 public void test_lookupMethodHelper() {
 1581  1 VariableData[] vds =
 1582    new VariableData[] { new VariableData("field1", _finalMav, SymbolData.DOUBLE_TYPE, true, null),
 1583    new VariableData("field2", _finalMav, SymbolData.INT_TYPE, true, null) };
 1584  1 VariableData[] vds2 =
 1585    new VariableData[] { new VariableData("field3", _finalMav, SymbolData.DOUBLE_TYPE, true, null) };
 1586  1 VariableData[] vds3 =
 1587    new VariableData[] { new VariableData("field1", _finalMav, SymbolData.CHAR_TYPE, true, null) };
 1588  1 InstanceData[] sds =
 1589    new InstanceData[] { SymbolData.DOUBLE_TYPE.getInstanceData(), SymbolData.INT_TYPE.getInstanceData()};
 1590  1 InstanceData[] sds2 = new InstanceData[] { SymbolData.DOUBLE_TYPE.getInstanceData() };
 1591  1 InstanceData[] sds3 = new InstanceData[] { SymbolData.CHAR_TYPE.getInstanceData()};
 1592  1 MethodData md =
 1593    new MethodData("Bart", _publicMav, new TypeParameter[0], _sd1, vds, new String[0], _sd1, null);
 1594  1 vds[0].setEnclosingData(md);
 1595  1 vds[1].setEnclosingData(md);
 1596  1 _sd1.addMethod(md);
 1597  1 MethodData md2 =
 1598    new MethodData("Homer", _publicMav, new TypeParameter[0], _sd2, vds2, new String[0], _sd2, null);
 1599  1 vds2[0].setEnclosingData(md2);
 1600  1 _sd2.addMethod(md2);
 1601  1 _sd1.setSuperClass(_sd2);
 1602  1 MethodData constructor =
 1603    new MethodData("monkey", _publicMav, new TypeParameter[0], _sd1, vds3, new String[0], _sd1, null);
 1604  1 vds3[0].setEnclosingData(constructor);
 1605  1 _sd1.addMethod(constructor);
 1606  1 assertEquals("Should return md.", md, _btc._lookupMethodHelper("Bart", _sd1, sds, null, false, _sd3));
 1607  1 assertEquals("Should return md2.", md2, _btc._lookupMethodHelper("Homer", _sd1, sds2, null, false, _sd3));
 1608  1 assertEquals("Should return constructor.", constructor, _btc._lookupMethodHelper("monkey", _sd1, sds3, null, true,
 1609    _sd3));
 1610  1 assertEquals("Should return null.", null, _btc._lookupMethodHelper("Homer", _sd1, sds2, null, true, _sd3));
 1611  1 assertEquals("Should return null.", null, _btc._lookupMethodHelper("Lenny", _sd1, sds, null, false, _sd3));
 1612    }
 1613   
 1614  1 public void testLookupMethod() {
 1615  1 VariableData[] vds =
 1616    new VariableData[] { new VariableData("field1", _finalMav, SymbolData.DOUBLE_TYPE, true, null),
 1617    new VariableData("field2", _finalMav, SymbolData.INT_TYPE, true, null) };
 1618  1 InstanceData[] sds =
 1619    new InstanceData[] { SymbolData.DOUBLE_TYPE.getInstanceData(), SymbolData.INT_TYPE.getInstanceData() };
 1620  1 MethodData md = new MethodData("Bart", _publicMav, new TypeParameter[0], _sd1, vds, new String[0], _sd1, null);
 1621  1 vds[0].setEnclosingData(md);
 1622  1 vds[1].setEnclosingData(md);
 1623  1 _sd1.addMethod(md);
 1624   
 1625  1 assertEquals("Should return md.", md, _btc._lookupMethod("Bart", _sd1, sds, null, "Error message:", true, _sd3));
 1626  1 assertEquals("Should be no errors.", 0, errors.size());
 1627  1 assertEquals("Should return null.", null, _btc._lookupMethod("Lenny", _sd1, sds, null, "Lenny Error message: ",
 1628    true, _sd3));
 1629  1 assertEquals("Should be one error.", 1, errors.size());
 1630  1 assertEquals("Newest error should have correct message", "Lenny Error message: Lenny(double, int).",
 1631    errors.getLast().getFirst());
 1632    }
 1633   
 1634  1 public void testAreInSamePackage() {
 1635  1 assertTrue("areInSamePackage with same qualified names", _btc._areInSamePackage(_sd1, _sd2));
 1636  1 assertFalse("areInSamePackage with unqualified and qualified names", _btc._areInSamePackage(_sd1, _sd3));
 1637  1 assertFalse("areInSamePackage with different qualified names", _btc._areInSamePackage(_sd1, _sd4));
 1638  1 assertFalse("areInSamePackage with qualified and empty names", _btc._areInSamePackage(_sd4, _sd5));
 1639  1 assertTrue("areInSamePackage with different unqualified names", _btc._areInSamePackage(_sd3, _sd6));
 1640    }
 1641   
 1642  1 public void testCheckAccessibility() {
 1643  1 _sd6.setSuperClass(_sd3);
 1644  1 _sd6.setOuterData(_sd2);
 1645  1 _sd2.addInnerClass(_sd6);
 1646  1 String sd3Name = _sd3.getName();
 1647  1 String sd6Name = _sd6.getName();
 1648   
 1649    // public
 1650  1 assertTrue("checkAccess with public mav and same package",
 1651    _btc.checkAccess(NULL_LITERAL, _publicMav, "fieldOfDreams", _sd1, _sd2, "field"));
 1652  1 assertTrue("checkAccess with public mav and different packages",
 1653    _btc.checkAccess(NULL_LITERAL, _publicMav, "fieldOfDreams", _sd1, _sd4, "field"));
 1654  1 assertTrue("checkAccess with public mav and is outer class",
 1655    _btc.checkAccess(NULL_LITERAL, _publicMav, "fieldOfDreams", _sd3, _sd6, "field"));
 1656  1 assertTrue("checkAccess for a class and its outer class",
 1657    _btc.checkAccess(NULL_LITERAL, _publicMav, sd6Name, _sd2, _sd6, "class"));
 1658  1 assertTrue("checkAccess for a class and a class it is not related to",
 1659    _btc.checkAccess(NULL_LITERAL, _publicMav, sd6Name, _sd2, _sd4, "class"));
 1660   
 1661    // protected
 1662  1 assertTrue("checkAccess with protected mav and same package",
 1663    _btc.checkAccess(NULL_LITERAL, _protectedMav, "fieldOfDreams", _sd1, _sd2, "field"));
 1664  1 assertFalse("checkAccess with protected mav and different package",
 1665    _btc.checkAccess(NULL_LITERAL, _protectedMav, "fieldOfDreams", _sd1, _sd4, "field"));
 1666  1 assertTrue("checkAccess with protected mav and is outer class",
 1667    _btc.checkAccess(NULL_LITERAL, _protectedMav, "fieldOfDreams", _sd2, _sd6, "field"));
 1668  1 assertTrue("checkAccess with protected mav and is super class",
 1669    _btc.checkAccess(NULL_LITERAL, _protectedMav, "fieldOfDreams", _sd3, _sd6, "field"));
 1670  1 assertTrue("checkAccess for a class and its outer class",
 1671    _btc.checkAccess(NULL_LITERAL, _protectedMav, sd6Name, _sd2, _sd6, "class"));
 1672  1 assertFalse("checkAccess for a class and a class it is not related to",
 1673    _btc.checkAccess(NULL_LITERAL, _protectedMav, sd6Name, _sd2, _sd4, "class"));
 1674   
 1675    // private
 1676  1 assertFalse("checkAccess with private mav and same package",
 1677    _btc.checkAccess(NULL_LITERAL, _privateMav, "fieldOfDreams", _sd1, _sd2, "field"));
 1678  1 assertFalse("checkAccess with private mav and different package",
 1679    _btc.checkAccess(NULL_LITERAL, _privateMav, "fieldOfDreams", _sd1, _sd4, "field"));
 1680  1 assertTrue("checkAccess with private mav and is outer class",
 1681    _btc.checkAccess(NULL_LITERAL, _privateMav, "fieldOfDreams", _sd2, _sd6, "field"));
 1682  1 assertFalse("checkAccess with private mav and is super class",
 1683    _btc.checkAccess(NULL_LITERAL, _privateMav, "fieldOfDreams", _sd3, _sd6, "field"));
 1684  1 assertEquals("There should be 5 errors", 5, errors.size());
 1685  1 assertEquals("The last error message should be correct",
 1686    "The field fieldOfDreams in " + sd3Name + " is private and cannot be accessed from " + sd6Name,
 1687    errors.getLast().getFirst());
 1688  1 assertTrue("checkAccess with private mav and same file",
 1689    _btc.checkAccess(NULL_LITERAL, _privateMav, "fieldOfDreams", _sd3, _sd3, "field"));
 1690  1 assertTrue("checkAccess for a class and its outer class",
 1691    _btc.checkAccess(NULL_LITERAL, _privateMav, sd6Name, _sd2, _sd6, "class"));
 1692  1 assertFalse("checkAccess for a class and a class it is not related to",
 1693    _btc.checkAccess(NULL_LITERAL, _privateMav, sd6Name, _sd2, _sd4, "class"));
 1694   
 1695    // package
 1696  1 assertTrue("checkAccess with package mav and same package",
 1697    _btc.checkAccess(NULL_LITERAL, _packageMav, "fieldOfDreams", _sd1, _sd2, "field"));
 1698  1 assertFalse("checkAccess with package mav and different package",
 1699    _btc.checkAccess(NULL_LITERAL, _packageMav, "fieldOfDreams", _sd1, _sd4, "field"));
 1700  1 assertTrue("checkAccess with package mav and is outer class",
 1701    _btc.checkAccess(NULL_LITERAL, _packageMav, "fieldOfDreams", _sd2, _sd6, "field"));
 1702  1 assertTrue("checkAccess with package mav and is super class",
 1703    _btc.checkAccess(NULL_LITERAL, _packageMav, "fieldOfDreams", _sd3, _sd6, "field"));
 1704  1 assertTrue("checkAccess for a class and its outer class",
 1705    _btc.checkAccess(NULL_LITERAL, _packageMav, sd6Name, _sd2, _sd6, "class"));
 1706  1 assertFalse("checkAccess for a class and a class it is not related to",
 1707    _btc.checkAccess(NULL_LITERAL, _packageMav, sd6Name, _sd2, _sd4, "class"));
 1708   
 1709    }
 1710   
 1711  1 public void testGetFieldOrVariable() {
 1712  1 _sd6.setSuperClass(_sd3);
 1713  1 _sd6.setOuterData(_sd2);
 1714  1 VariableData vd0 = new VariableData("field0", _privateMav, _sd1, true, _sd6);
 1715  1 VariableData vd1 = new VariableData("field1", _publicMav, _sd1, true, _sd3);
 1716  1 VariableData vd2 = new VariableData("field2", _privateMav, _sd2, true, _sd2);
 1717  1 VariableData vd3 =
 1718    new VariableData("variable1", new ModifiersAndVisibility(NONE, new String[0]), _sd3, true, _sd3);
 1719  1 MethodData md = new MethodData("method1", _protectedMav, null, null, null, null, _sd3, null);
 1720  1 md.addVar(vd3);
 1721  1 _sd6.addVar(vd0);
 1722  1 _sd3.addVar(vd1);
 1723  1 _sd2.addVar(vd2);
 1724  1 _sd3.addMethod(md);
 1725  1 assertEquals("Should find field0", vd0, _btc.getFieldOrVariable("field0", _sd6, _sd6, NULL_LITERAL));
 1726  1 assertEquals("Should find field1", vd1, _btc.getFieldOrVariable("field1", _sd6, _sd6, NULL_LITERAL));
 1727  1 assertEquals("Should find field2", vd2, _btc.getFieldOrVariable("field2", _sd6, _sd6, NULL_LITERAL));
 1728  1 assertEquals("Should not find field7", null, _btc.getFieldOrVariable("field7", _sd6, _sd6, NULL_LITERAL));
 1729  1 assertEquals("Should find variable1", vd3, _btc.getFieldOrVariable("variable1", md, _sd3, NULL_LITERAL));
 1730   
 1731    // test that passing in a list of variables to use will not recur (if called from the type checker)
 1732  1 assertEquals("Should not find field1", null,
 1733    _btc.getFieldOrVariable("field1", _sd6, _sd6, NULL_LITERAL, new LinkedList<VariableData>()));
 1734  1 assertEquals("There should be no errors", 0, errors.size());
 1735    }
 1736   
 1737  1 public void test_addError() {
 1738  1 LinkedList<Pair<String, JExpressionIF>> e = new LinkedList<Pair<String, JExpressionIF>>();
 1739   
 1740  1 NullLiteral nl = NULL_LITERAL;
 1741  1 NullLiteral nl2 = NULL_LITERAL;
 1742   
 1743  1 e.addLast(new Pair<String,JExpressionIF>("Boy, is this an error!", nl));
 1744  1 _addError("Boy, is this an error!", nl);
 1745   
 1746  1 assertTrue("An error should have been added.", _errorAdded);
 1747  1 assertEquals("The errors list should be correct.", e, errors);
 1748   
 1749  1 e.addLast(new Pair<String,JExpressionIF>("Error again!", nl2));
 1750  1 _addError("Error again!", nl2);
 1751   
 1752  1 assertTrue("Another error should have been aded.", _errorAdded);
 1753  1 assertEquals("The new errors list should be correct.", e, errors);
 1754    }
 1755   
 1756   
 1757  1 public void testCheckAbstractMethodsHelper() {
 1758    /*
 1759    * This should work.
 1760    * _sd1 will be abstract.
 1761    * _sd2 will be concrete and extend _sd1.
 1762    * _sd3 will be abstract and extend _sd2.
 1763    * _sd4 will be abstract and extend _sd3.
 1764    * _sd5 will be concrete and extend _sd4.
 1765    */
 1766   
 1767  1 VariableData[] vds = new VariableData[] { new VariableData("field1", _finalMav, SymbolData.DOUBLE_TYPE, true, null),
 1768    new VariableData("field2", _finalMav, SymbolData.INT_TYPE, true, null) };
 1769  1 MethodData md1 = new MethodData("Abe", _abstractMav, new TypeParameter[0], _sd1,
 1770    vds,
 1771    new String[0],
 1772    _sd1,
 1773    null);
 1774  1 vds[0].setEnclosingData(md1);
 1775  1 vds[1].setEnclosingData(md1);
 1776  1 _sd1.addMethod(md1);
 1777  1 _sd1.setMav(_abstractMav);
 1778  1 _sd1.setSuperClass(_sd6);
 1779  1 _sd2.setSuperClass(_sd1);
 1780  1 MethodData md2 = new MethodData("Homer", _abstractMav, new TypeParameter[0], _sd1,
 1781    vds,
 1782    new String[0],
 1783    _sd3,
 1784    null);
 1785  1 MethodData md3 = new MethodData("Marge", _publicMav, new TypeParameter[0], _sd1,
 1786    vds,
 1787    new String[0],
 1788    _sd3,
 1789    null);
 1790  1 MethodData md123 = new MethodData("Apu", _abstractMav, new TypeParameter[0], _sd1,
 1791    vds,
 1792    new String[0],
 1793    _sd3,
 1794    null);
 1795  1 _sd3.addMethod(md2);
 1796  1 _sd3.addMethod(md3);
 1797  1 _sd3.addMethod(md123);
 1798  1 _sd3.setMav(_abstractMav);
 1799  1 _sd3.setSuperClass(_sd2);
 1800  1 MethodData md4 = new MethodData("Bart", _abstractMav, new TypeParameter[0], _sd1,
 1801    vds,
 1802    new String[0],
 1803    _sd4,
 1804    null);
 1805  1 MethodData md5 = new MethodData("Lisa", _abstractMav, new TypeParameter[0], _sd1,
 1806    vds,
 1807    new String[0],
 1808    _sd4,
 1809    null);
 1810  1 MethodData md1234 = new MethodData("Apu", _publicMav, new TypeParameter[0], _sd1,
 1811    vds, new String[0],
 1812    _sd4,
 1813    null);
 1814  1 _sd4.addMethod(md4);
 1815  1 _sd4.addMethod(md5);
 1816  1 _sd4.addMethod(md1234);
 1817  1 _sd4.setMav(_abstractMav);
 1818  1 _sd4.setSuperClass(_sd3);
 1819  1 MethodData md6 = new MethodData("Bart", _abstractMav, new TypeParameter[0], _sd1,
 1820    vds,
 1821    new String[0],
 1822    _sd5,
 1823    null);
 1824  1 MethodData md7 = new MethodData("Homer", _abstractMav, new TypeParameter[0], _sd1,
 1825    vds,
 1826    new String[0],
 1827    _sd5,
 1828    null);
 1829  1 MethodData md8 = new MethodData("Lisa", _abstractMav, new TypeParameter[0], _sd1,
 1830    vds,
 1831    new String[0],
 1832    _sd5,
 1833    null);
 1834  1 _sd5.addMethod(md6);
 1835  1 _sd5.addMethod(md7);
 1836  1 _sd5.addMethod(md8);
 1837  1 _sd5.setSuperClass(_sd4);
 1838  1 LinkedList<MethodData> mds = _sd5.getMethods();
 1839    // TODO: Check all enclosingDatas (interfaces too)
 1840  1 _btc._checkAbstractMethodsHelper(_sd5, _sd5.getSuperClass(), mds, null);
 1841  1 assertEquals("There should be no errors.", 0, errors.size());
 1842    // must be declared abstract or must override the abstract method: " + md.getName()
 1843    // Test one that doesn't work.
 1844  1 mds = _sd2.getMethods();
 1845  1 _btc._checkAbstractMethodsHelper(_sd2, _sd2.getSuperClass(), mds, null);
 1846  1 assertEquals("There should be one error.", 1, errors.size());
 1847  1 assertEquals("The error message should be correct.",
 1848    "i.like.giraffe must be declared abstract or must override the abstract method: Abe(double, int) in "
 1849    + _sd2.getSuperClass().getName(),
 1850    errors.get(0).getFirst());
 1851   
 1852    //check that an interface's abstract methods are recognized.
 1853  1 _sd3.setInterface(true);
 1854  1 _sd3.setMethods(new LinkedList<MethodData>());
 1855  1 _sd3.addMethod(md7);
 1856  1 _sd2.addEnclosingData(_sd3);
 1857  1 SymbolData sd = symbolTable.get("java.lang.Object");
 1858    // sd.setIsContinuation(false);
 1859  1 _sd2.setSuperClass(sd);
 1860  1 _btc._checkAbstractMethodsHelper(_sd2, _sd3, mds, null);
 1861  1 assertEquals("There should be two errors.", 2, errors.size());
 1862  1 assertEquals("The error message should be correct.",
 1863    "i.like.giraffe must be declared abstract or must override the abstract method: Homer(double, int) in "
 1864    + _sd3.getName(), errors.get(1).getFirst());
 1865    }
 1866   
 1867  1 public void testForPrimitiveType() {
 1868  1 assertEquals("Should return SymbolData.INT_TYPE.",
 1869    SymbolData.INT_TYPE,
 1870    _btc.forPrimitiveType(new PrimitiveType(NONE, "int")));
 1871  1 try {
 1872  1 _btc.forPrimitiveType(new PrimitiveType(NONE, "Maggie"));
 1873  0 fail("Should have thrown an exception.");
 1874    }
 1875    catch(RuntimeException re) {
 1876    }
 1877    }
 1878   
 1879  1 public void test_isAssignableFrom() {
 1880  1 assertTrue("Should be assignable.",
 1881    _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, symbolTable.get("java.lang.Double")));
 1882  1 assertFalse("Should not be assignable.",
 1883    _btc._isAssignableFrom(symbolTable.get("java.lang.Double"), SymbolData.FLOAT_TYPE));
 1884  1 assertTrue("Should be assignable.",
 1885    _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, symbolTable.get("java.lang.Long")));
 1886  1 assertFalse("Should not be assignable.",
 1887    _btc._isAssignableFrom(symbolTable.get("java.lang.Double"), SymbolData.INT_TYPE));
 1888  1 assertTrue("Should be assignable.",
 1889    _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, symbolTable.get("java.lang.Short")));
 1890  1 assertFalse("Should not be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Double"), symbolTable.get("java.lang.Character")));
 1891  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, SymbolData.BYTE_TYPE));
 1892  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Integer"), symbolTable.get("java.lang.Integer")));
 1893  1 assertFalse("Should not be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Integer"), symbolTable.get("java.lang.Character")));
 1894  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Character"), SymbolData.CHAR_TYPE));
 1895  1 assertFalse("Should not be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Boolean"), SymbolData.INT_TYPE));
 1896   
 1897  1 assertTrue("Should be assignable", _btc._isAssignableFrom(symbolTable.get("java.lang.Object"), SymbolData.INT_TYPE));
 1898   
 1899  1 _sd2.setSuperClass(_sd1);
 1900  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(_sd1, _sd1));
 1901  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(_sd1, _sd2));
 1902   
 1903    //test 1.5/1.4 auto-boxing and unboxing
 1904  1 assertFalse("Should not be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Double"), SymbolData.INT_TYPE));
 1905  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, symbolTable.get("java.lang.Short")));
 1906  1 assertFalse("Should not be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Double"), symbolTable.get("java.lang.Character")));
 1907  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, SymbolData.BYTE_TYPE));
 1908  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Integer"), symbolTable.get("java.lang.Integer")));
 1909  1 assertFalse("Should not be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Integer"), symbolTable.get("java.lang.Character")));
 1910  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(symbolTable.get("java.lang.Object"), SymbolData.INT_TYPE));
 1911   
 1912  1 LanguageLevelVisitor llv =
 1913    new LanguageLevelVisitor(_btc._file,
 1914    _btc._package,
 1915    null, // enclosingClassName for top level traversal
 1916    _btc._importedFiles,
 1917    _btc._importedPackages,
 1918    new HashSet<String>(),
 1919    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>(),
 1920    new LinkedList<Command>());
 1921   
 1922    // LanguageLevelConverter.symbolTable = llv.symbolTable = _btc.symbolTable;
 1923  1 LanguageLevelConverter._newSDs.clear();
 1924   
 1925  1 SourceInfo si = NONE;
 1926   
 1927  1 ArrayData intArray = new ArrayData(SymbolData.INT_TYPE, llv, si);
 1928  1 assertTrue("Should be able to assign an array to Object",
 1929    _btc._isAssignableFrom(symbolTable.get("java.lang.Object"), intArray));
 1930   
 1931  1 ArrayData doubleArray = new ArrayData(SymbolData.DOUBLE_TYPE, llv, si);
 1932  1 assertFalse("Should not be able to assign an int[] to a double[]",
 1933    _btc._isAssignableFrom(doubleArray, intArray));
 1934   
 1935  1 ArrayData integerArray = new ArrayData(symbolTable.get("java.lang.Integer"), llv, si);
 1936  1 assertFalse("Should not be able to assign an array of ints to an array of Integers",
 1937    _btc._isAssignableFrom(integerArray, intArray));
 1938  1 assertFalse("Should not be able to assign an array of Integers to an array of ints",
 1939    _btc._isAssignableFrom(intArray, integerArray));
 1940   
 1941  1 assertTrue("Should be able to assign an array to an interface of java.io.Serializable",
 1942    _btc._isAssignableFrom(symbolTable.get("java.io.Serializable"), integerArray));
 1943   
 1944  1 LanguageLevelConverter.OPT = new Options(JavaVersion.JAVA_5, EmptyIterable.<File>make());
 1945  1 assertFalse("Should not be assignable.",
 1946    _btc._isAssignableFrom(symbolTable.get("java.lang.Double"), SymbolData.INT_TYPE));
 1947  1 assertFalse("Should not be assignable.",
 1948    _btc._isAssignableFrom(symbolTable.get("java.lang.Double"), symbolTable.get("java.lang.Character")));
 1949  1 assertTrue("Should be assignable.", _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, SymbolData.BYTE_TYPE));
 1950  1 assertTrue("Should be assignable.",
 1951    _btc._isAssignableFrom(SymbolData.DOUBLE_TYPE, symbolTable.get("java.lang.Short")));
 1952  1 assertTrue("Should be assignable.",
 1953    _btc._isAssignableFrom(symbolTable.get("java.lang.Integer"), symbolTable.get("java.lang.Integer")));
 1954  1 assertFalse("Should not be assignable.",
 1955    _btc._isAssignableFrom(symbolTable.get("java.lang.Integer"), symbolTable.get("java.lang.Character")));
 1956  1 assertTrue("Should not assignable.",
 1957    _btc._isAssignableFrom(SymbolData.INT_TYPE, symbolTable.get("java.lang.Character")));
 1958  1 assertTrue("Should be assignable.",
 1959    _btc._isAssignableFrom(symbolTable.get("java.lang.Object"), SymbolData.INT_TYPE));
 1960  1 assertTrue("Should be able to assign an array to Object",
 1961    _btc._isAssignableFrom(symbolTable.get("java.lang.Object"), intArray));
 1962   
 1963   
 1964    //check that classes are know to be subclasses of their interfaces.
 1965  1 SymbolData myData = new SymbolData("yes");
 1966  1 SymbolData yourData = new SymbolData("interface");
 1967  1 yourData.setInterface(true);
 1968  1 myData.setIsContinuation(false);
 1969  1 myData.addInterface(yourData);
 1970  1 yourData.setIsContinuation(false);
 1971  1 assertTrue("Should be assignable", _btc._isAssignableFrom(yourData, myData));
 1972    }
 1973   
 1974   
 1975  1 public void test_isAssignableFromWithoutAutoboxing() {
 1976  1 assertTrue("Should be assignable.",
 1977    _btc._isAssignableFromWithoutAutoboxing(SymbolData.DOUBLE_TYPE, SymbolData.DOUBLE_TYPE));
 1978  1 assertTrue("Should be assignable.",
 1979    _btc._isAssignableFromWithoutAutoboxing(SymbolData.DOUBLE_TYPE, SymbolData.FLOAT_TYPE));
 1980  1 assertTrue("Should be assignable.",
 1981    _btc._isAssignableFromWithoutAutoboxing(SymbolData.DOUBLE_TYPE, SymbolData.LONG_TYPE));
 1982  1 assertTrue("Should be assignable.",
 1983    _btc._isAssignableFromWithoutAutoboxing(SymbolData.DOUBLE_TYPE, SymbolData.INT_TYPE));
 1984  1 assertTrue("Should be assignable.",
 1985    _btc._isAssignableFromWithoutAutoboxing(SymbolData.DOUBLE_TYPE, SymbolData.SHORT_TYPE));
 1986  1 assertTrue("Should be assignable.",
 1987    _btc._isAssignableFromWithoutAutoboxing(SymbolData.DOUBLE_TYPE, SymbolData.CHAR_TYPE));
 1988  1 assertTrue("Should be assignable.",
 1989    _btc._isAssignableFromWithoutAutoboxing(SymbolData.DOUBLE_TYPE, SymbolData.BYTE_TYPE));
 1990  1 assertTrue("Should be assignable.",
 1991    _btc._isAssignableFromWithoutAutoboxing(SymbolData.INT_TYPE, SymbolData.INT_TYPE));
 1992  1 assertTrue("Should be assignable.",
 1993    _btc._isAssignableFromWithoutAutoboxing(SymbolData.INT_TYPE, SymbolData.CHAR_TYPE));
 1994  1 assertTrue("Should be assignable.",
 1995    _btc._isAssignableFromWithoutAutoboxing(SymbolData.CHAR_TYPE, SymbolData.CHAR_TYPE));
 1996   
 1997  1 _sd2.setSuperClass(_sd1);
 1998  1 assertTrue("Should be assignable.", _btc._isAssignableFromWithoutAutoboxing(_sd1, _sd1));
 1999  1 assertTrue("Should be assignable.", _btc._isAssignableFromWithoutAutoboxing(_sd1, _sd2));
 2000    }
 2001   
 2002  1 public void testCheckForCyclicInheritance() {
 2003  1 _sd1.setSuperClass(_sd2);
 2004  1 _sd2.addInterface(_sd3);
 2005  1 _sd2.setSuperClass(new SymbolData("java.lang.String"));
 2006  1 _sd3.addInterface(symbolTable.get("java.lang.Object"));
 2007  1 _sd1.addInnerClass(_sd4);
 2008   
 2009    //no cyclic inheritance
 2010  1 InterfaceDef nl =
 2011    new InterfaceDef(NONE, _publicMav, new Word(NONE, "name"), new TypeParameter[0], new ReferenceType[0],
 2012    new BracedBody(NONE, new BodyItemI[0]));
 2013  1 assertFalse("Should not be cyclic inheritance",
 2014    _btc.checkForCyclicInheritance(_sd1, new LinkedList<SymbolData>(), nl));
 2015   
 2016    //if you and your super interface implement the same interface, it's okay
 2017  1 _sd4.addInterface(_sd5);
 2018  1 _sd4.addInterface(_sd6);
 2019  1 _sd5.addInterface(_sd6);
 2020  1 assertFalse("Should not be cyclic inheritance",
 2021    _btc.checkForCyclicInheritance(_sd4, new LinkedList<SymbolData>(), nl));
 2022   
 2023  1 _sd3.addInterface(_sd2);
 2024    //cyclic inheritance
 2025  1 assertTrue("Should be cyclic inheritance",
 2026    _btc.checkForCyclicInheritance(_sd1, new LinkedList<SymbolData>(), nl));
 2027  1 assertEquals("There should be one error", 1, errors.size());
 2028  1 assertEquals("The error message should be correct", "Cyclic inheritance involving " + _sd2.getName(),
 2029    errors.get(0).getFirst());
 2030   
 2031    //if your super class implements your inner class, there is cyclic inheritance
 2032  1 ArrayList<SymbolData> temp = _sd3.getInterfaces();
 2033  1 _sd3.getInterfaces().remove(_sd2);
 2034  1 _sd3.setInterfaces(temp);
 2035  1 _sd2.setSuperClass(_sd6);
 2036  1 _sd6.setSuperClass(_sd4);
 2037  1 _sd4.setSuperClass(symbolTable.get("java.lang.Object"));
 2038  1 assertTrue("Should be cyclic inheritance", _btc.checkForCyclicInheritance(_sd1, new LinkedList<SymbolData>(), nl));
 2039  1 assertEquals("Should now be 2 errors", 2, errors.size());
 2040  1 assertEquals("The error message should be correct", "Cyclic inheritance involving " + _sd4.getName(),
 2041    errors.get(1).getFirst());
 2042    }
 2043   
 2044  1 public void testForClassDef() {
 2045   
 2046  1 ClassDef cd =
 2047    new ClassDef(NONE, _publicMav, new Word(NONE, "Lisa"),
 2048    new TypeParameter[0],
 2049    new ClassOrInterfaceType(NONE, "java.lang.Object", new Type[0]), new ReferenceType[0],
 2050    new BracedBody(NONE, new BodyItemI[0]));
 2051   
 2052    //Test that no cyclic inheritance goes okay
 2053  1 SymbolData Lisa = new SymbolData("Lisa");
 2054  1 Lisa.setSuperClass(symbolTable.get("java.lang.Object"));
 2055   
 2056  1 Lisa.setIsContinuation(false);
 2057  1 Lisa.setMav(_publicMav);
 2058  1 _btc._file=new File("Lisa.dj1");
 2059  1 _btc.symbolTable.put("Lisa", Lisa);
 2060  1 TypeData result = cd.visit(_btc);
 2061   
 2062   
 2063  1 assertEquals("There should be no errors", 0, errors.size());
 2064   
 2065    //Test that cyclic inheritance throws an error
 2066  1 Lisa.setSuperClass(Lisa);
 2067  1 result = cd.visit(_btc);
 2068   
 2069  1 assertEquals("There should be one error", 1, errors.size());
 2070  1 assertEquals("Error message should be correct", "Cyclic inheritance involving Lisa", errors.get(0).getFirst());
 2071   
 2072    //Test that if you extend a final class, an error is thrown
 2073  1 ClassDef cd2 =
 2074    new ClassDef(NONE, _publicMav, new Word(NONE, "Me"),
 2075    new TypeParameter[0], new ClassOrInterfaceType(NONE, "Parent", new Type[0]), new ReferenceType[0],
 2076    new BracedBody(NONE, new BodyItemI[0]));
 2077  1 SymbolData parent = new SymbolData("Parent");
 2078  1 parent.setMav(_finalMav);
 2079  1 parent.setSuperClass(symbolTable.get("java.lang.Object"));
 2080  1 _btc.symbolTable.put("Parent", parent);
 2081   
 2082  1 SymbolData me = new SymbolData("Me");
 2083   
 2084  1 me.setSuperClass(parent);
 2085  1 me.setIsContinuation(false);
 2086  1 _btc.symbolTable.put("Me", me);
 2087   
 2088  1 result = cd2.visit(_btc);
 2089   
 2090   
 2091  1 assertEquals("There should be 2 errors", 2, errors.size());
 2092  1 assertEquals("2nd Error message should be correct", "Class Me cannot extend the final class Parent",
 2093    errors.get(1).getFirst());
 2094   
 2095   
 2096    //Test that if you extend a class you cannot see, an error is thrown
 2097  1 ClassDef cd3 =
 2098    new ClassDef(NONE, _publicMav, new Word(NONE, "somewhereElse.Lisa"),
 2099    new TypeParameter[0], new ClassOrInterfaceType(NONE, "java.lang.Object", new Type[0]),
 2100    new ReferenceType[0],
 2101    new BracedBody(NONE, new BodyItemI[0]));
 2102   
 2103  1 Lisa = new SymbolData("somewhereElse.Lisa");
 2104  1 Lisa.setSuperClass(new SymbolData("hungry"));
 2105  1 Lisa.setPackage("somewhereElse");
 2106  1 Lisa.setIsContinuation(false);
 2107  1 Lisa.getSuperClass().setIsContinuation(false);
 2108   
 2109  1 _btc.symbolTable.put("somewhereElse.Lisa", Lisa);
 2110  1 result = cd3.visit(_btc);
 2111   
 2112  1 assertEquals("There should be three errors", 3, errors.size());
 2113  1 assertEquals("3rd error message should be correct",
 2114    "The class hungry is package protected because there is no access specifier and cannot be "
 2115    + "accessed from somewhereElse.Lisa",
 2116    errors.get(2).getFirst());
 2117   
 2118    //Test that if you implement an interface you cannot see, an error is thrown
 2119  1 SymbolData superI = new SymbolData("superI");
 2120  1 superI.setInterface(true);
 2121  1 superI.setIsContinuation(false);
 2122  1 Lisa.setSuperClass(new SymbolData("super", _publicMav, new TypeParameter[0], null, new ArrayList<SymbolData>(), null));
 2123   
 2124  1 Lisa.addInterface(superI);
 2125  1 _btc.symbolTable.put("superI", superI);
 2126   
 2127  1 ClassDef cd4 =
 2128    new ClassDef(NONE, _publicMav, new Word(NONE, "somewhereElse.Lisa"),
 2129    new TypeParameter[0], new TypeVariable(NONE, "super"),
 2130    new ReferenceType[] {new ClassOrInterfaceType(NONE, "superI", new Type[0])},
 2131    new BracedBody(NONE, new BodyItemI[0]));
 2132   
 2133   
 2134   
 2135  1 cd4.visit(_btc);
 2136  1 assertEquals("There should be four errors", 4, errors.size());
 2137  1 assertEquals("The 4th error message should be correct",
 2138    "The interface superI is package protected because there is no access specifier and cannot be "
 2139    + "accessed from somewhereElse.Lisa",
 2140    errors.get(3).getFirst());
 2141   
 2142    // Test that if a class has a final field and a constructor that sets the value, it won't throw an error
 2143  1 VariableDeclarator vdec =
 2144    new UninitializedVariableDeclarator(NONE, new PrimitiveType(NONE, "int"), new Word(NONE, "i"));
 2145  1 VariableDeclaration vd = new VariableDeclaration(NONE, _finalMav, new VariableDeclarator[] {vdec});
 2146  1 ExpressionStatement se =
 2147    new ExpressionStatement(NONE,
 2148    new SimpleAssignmentExpression(NONE, new SimpleNameReference(NONE, new Word(NONE, "i")),
 2149    new IntegerLiteral(NONE, 1)));
 2150  1 BracedBody cbb = new BracedBody(NONE, new BodyItemI[] {se});
 2151  1 ConstructorDef consD =
 2152    new ConstructorDef(NONE, new Word(NONE, "Jimes"), _publicMav, new FormalParameter[0], new ReferenceType[0], cbb);
 2153  1 BracedBody b = new BracedBody(NONE, new BodyItemI[] {vd, consD});
 2154  1 ClassDef cd5 =
 2155    new ClassDef(NONE, _publicMav, new Word(NONE, "Jimes"),
 2156    new TypeParameter[0], new ClassOrInterfaceType(NONE, "java.lang.Object", new Type[0]),
 2157    new ReferenceType[0], new BracedBody(NONE, new BodyItemI[] {vd, consD}));
 2158   
 2159  1 SymbolData sd = new SymbolData("Jimes");
 2160  1 VariableData vData = new VariableData("i", _finalMav, SymbolData.INT_TYPE, false, sd);
 2161  1 sd.setIsContinuation(false);
 2162  1 sd.addVar(vData);
 2163  1 SymbolData sd2 = symbolTable.get("java.lang.Object");
 2164    // sd2.setIsContinuation(false);
 2165    // sd2.setMav(_publicMav);
 2166    // sd2.setPackage("java.lang");
 2167  1 MethodData objMd =
 2168    new MethodData("java.lang.Object", _publicMav, new TypeParameter[0], sd2, new VariableData[0], new String[0],
 2169    sd2, cd);
 2170  1 sd2.addMethod(objMd);
 2171   
 2172  1 sd.setSuperClass(sd2);
 2173  1 symbolTable.put("Jimes", sd);
 2174  1 MethodData md = new MethodData("Jimes", _publicMav, new TypeParameter[0], sd, new VariableData[0], new String[0],
 2175    sd, cd);
 2176  1 sd.addMethod(md);
 2177   
 2178  1 cd5.visit(_btc);
 2179  1 assertEquals("There should still be four errors", 4, errors.size());
 2180   
 2181    // Test that if a class has a final field, that if there are no constructors, an error is thrown since the value
 2182    // of the field cannot be set.
 2183  1 vData.lostValue();
 2184  1 b = new BracedBody(NONE, new BodyItemI[] {vd});
 2185  1 cd5 = new ClassDef(NONE, _publicMav, new Word(NONE, "Jimes"), new TypeParameter[0],
 2186    new ClassOrInterfaceType(NONE, "java.lang.Object", new Type[0]),
 2187    new ReferenceType[0], b);
 2188   
 2189  1 cd5.visit(_btc);
 2190  1 assertEquals("There should be 5 errors now", 5, errors.size());
 2191  1 assertEquals("The error message should be correct", "The final field i has not been initialized",
 2192    errors.get(4).getFirst());
 2193   
 2194    //Test that if the class implements java.lang.Runnable, then an error is thrown.
 2195  1 ClassDef cd6 =
 2196    new ClassDef(NONE, _publicMav, new Word(NONE, "JimesH"),
 2197    new TypeParameter[0],
 2198    new ClassOrInterfaceType(NONE, "java.lang.Object", new Type[0]),
 2199    new ReferenceType[] {new ClassOrInterfaceType(NONE, "java.lang.Runnable", new Type[0])},
 2200    new BracedBody(NONE, new BodyItemI[0]));
 2201  1 sd = new SymbolData("JimesH");
 2202  1 sd.setIsContinuation(false);
 2203   
 2204  1 symbolTable.clear();
 2205  1 SymbolData runnableSd = new SymbolData("java.lang.Runnable");
 2206  1 runnableSd.setMav(_publicMav);
 2207  1 runnableSd.setIsContinuation(false);
 2208  1 runnableSd.setPackage("java.lang");
 2209  1 runnableSd.setInterface(true);
 2210  1 sd.addInterface(runnableSd);
 2211  1 symbolTable.put("JimesH", sd);
 2212  1 symbolTable.remove("java.lang.Runnable");
 2213  1 symbolTable.put("java.lang.Runnable", runnableSd);
 2214   
 2215  1 cd6.visit(_btc);
 2216  1 assertEquals("There should be 6 errors now", 6, errors.size());
 2217  1 assertEquals("The error message should be correct",
 2218    "JimesH implements the Runnable interface, which is not allowed at any language level",
 2219    errors.get(5).getFirst());
 2220   
 2221    //Test that if a class implements another class, an error is thrown
 2222  1 ClassDef cd7 =
 2223    new ClassDef(NONE, _publicMav, new Word(NONE, "Hspia"),
 2224    new TypeParameter[0], new ClassOrInterfaceType(NONE, "superSD", new Type[0]),
 2225    new ReferenceType[] {new ClassOrInterfaceType(NONE, "java.lang.String", new Type[0])},
 2226    new BracedBody(NONE, new BodyItemI[0]));
 2227  1 sd = new SymbolData("Hspia");
 2228  1 sd.setIsContinuation(false);
 2229   
 2230  1 symbolTable.clear();
 2231  1 SymbolData stringSd = new SymbolData("java.lang.String");
 2232  1 stringSd.setMav(_publicMav);
 2233  1 stringSd.setIsContinuation(false);
 2234  1 stringSd.setPackage("java.lang");
 2235  1 stringSd.setInterface(false);
 2236  1 sd.addInterface(stringSd);
 2237  1 symbolTable.put("Hspia", sd);
 2238  1 symbolTable.put("java.lang.String", stringSd);
 2239   
 2240  1 cd7.visit(_btc);
 2241  1 assertEquals("There should be 7 errors now", 7, errors.size());
 2242  1 assertEquals("The error message should be correct",
 2243    "java.lang.String is not an interface and thus cannot appear after the keyword 'implements' here."
 2244    + " Perhaps you meant to say 'extends'?" ,
 2245    errors.get(6).getFirst());
 2246   
 2247   
 2248    //Test that if a class extends an interface, an error is thrown
 2249   
 2250  1 stringSd.setInterface(true);
 2251  1 SymbolData superSD = new SymbolData("SuperSD");
 2252  1 superSD.setInterface(true);
 2253  1 sd.setSuperClass(superSD);
 2254  1 sd.setInterfaces(new ArrayList<SymbolData>());
 2255  1 symbolTable.put("superSD", superSD);
 2256  1 cd7.visit(_btc);
 2257  1 assertEquals("There should be 8 errors now", 8, errors.size());
 2258  1 assertEquals("The error message should be correct",
 2259    "SuperSD is an interface and thus cannot appear after the keyword 'extends' here." +
 2260    " Perhaps you meant to say 'implements'?", errors.get(7).getFirst());
 2261   
 2262    //Test that if a public class is not in a file of the same name, an error is thrown
 2263  1 superSD.setInterface(false);
 2264  1 sd.addModifier("public");
 2265  1 cd7.visit(_btc);
 2266  1 assertEquals("There should now be 9 errors", 9, errors.size());
 2267  1 assertEquals("The error message should be correct",
 2268    "Hspia is public thus must be defined in a file with the same name.", errors.get(8).getFirst());
 2269   
 2270    //Test that if a public class is in a file of the same name, no error is thrown.
 2271  1 _btc._file = new File("Hspia.dj1");
 2272  1 cd7.visit(_btc);
 2273  1 assertEquals("There should still be just 9 errors", 9, errors.size());
 2274   
 2275    //Test that if a class that is not public extends test case, an error is thrown.
 2276    //Also check that if a test class doesn't have any test methods, an error is thrown.
 2277  1 sd.setMav(_privateMav);
 2278  1 symbolTable.remove("Hspia");
 2279  1 symbolTable.put("Hspia", sd);
 2280   
 2281  1 SymbolData testCase = defineTestCaseClass();
 2282  1 sd.setSuperClass(testCase);
 2283   
 2284  1 cd7.visit(_btc);
 2285   
 2286  1 assertEquals("There should now be 11 errors", 11, errors.size());
 2287  1 assertEquals("The tenth error message should be correct",
 2288    "Hspia extends TestCase and thus must be explicitly declared public" ,
 2289    errors.get(9).getFirst());
 2290  1 assertEquals("The eleventh error message should be correct",
 2291    "Class Hspia does not have any valid test methods. Test methods must be declared public, " +
 2292    "must return void, and must start with the word \"test\"" ,
 2293    errors.get(10).getFirst());
 2294   
 2295    //Test that if a class that is not public extends test case, an error is thrown.
 2296    //Also check that if a test class doesn't have any test methods, an error is thrown.
 2297  1 _btc._file = new File("Hspia.dj0");
 2298  1 sd.setMav(_publicMav);
 2299  1 symbolTable.remove("Hspia");
 2300  1 symbolTable.put("Hspia", sd);
 2301   
 2302    // SymbolData testCase = defineTestCase();
 2303    // symbolTable.put("junit.framework.TestCase", testCase);
 2304    // sd.setSuperClass(testCase);
 2305   
 2306  1 cd7.visit(_btc);
 2307   
 2308  1 assertEquals("There should still be 11 errors", 11, errors.size()); // Generated duplicate error message
 2309  1 assertEquals("The 12th error message should be correct",
 2310    "Class Hspia does not have any valid test methods. Test methods must be declared public, " +
 2311    "must return void, and must start with the word \"test\"" ,
 2312    errors.get(10).getFirst());
 2313   
 2314    }
 2315   
 2316  1 public void testForInterfaceDef() {
 2317  1 InterfaceDef id = new InterfaceDef(NONE, _publicMav, new Word(NONE, "Lisa"),
 2318    new TypeParameter[0],
 2319    new ReferenceType[] {new ClassOrInterfaceType(NONE, "superI", new Type[0])},
 2320    new BracedBody(NONE, new BodyItemI[0]));
 2321   
 2322    //Test that no cyclic inheritance goes okay
 2323  1 SymbolData Lisa = new SymbolData("Lisa");
 2324  1 Lisa.setInterface(true);
 2325  1 SymbolData superI = new SymbolData("superI");
 2326  1 superI.setInterface(true);
 2327  1 Lisa.addInterface(superI);
 2328  1 Lisa.setIsContinuation(false);
 2329  1 superI.setIsContinuation(false);
 2330  1 _btc.symbolTable.put("Lisa", Lisa);
 2331  1 _btc.symbolTable.put("superI", superI);
 2332   
 2333  1 TypeData result = id.visit(_btc);
 2334   
 2335   
 2336  1 assertEquals("There should be no errors", 0, errors.size());
 2337   
 2338    //Test that cyclic inheritance throws an error
 2339  1 Lisa.addInterface(Lisa);
 2340  1 result = id.visit(_btc);
 2341   
 2342  1 assertEquals("There should be one error", 1, errors.size());
 2343  1 assertEquals("Error message should be correct", "Cyclic inheritance involving Lisa", errors.get(0).getFirst());
 2344   
 2345    //Test that if you implement an interface you cannot see, an error is thrown:
 2346  1 InterfaceDef id2 = new InterfaceDef(NONE, _publicMav, new Word(NONE, "somewhereElse.Lisa"),
 2347    new TypeParameter[0],
 2348    new ReferenceType[] {new ClassOrInterfaceType(NONE, "superI", new Type[0])},
 2349    new BracedBody(NONE, new BodyItemI[0]));
 2350  1 Lisa = new SymbolData("somewhereElse.Lisa");
 2351  1 Lisa.setIsContinuation(false);
 2352  1 Lisa.addInterface(superI);
 2353  1 Lisa.setPackage("somewhereElse");
 2354  1 Lisa.setInterface(true);
 2355  1 _btc.symbolTable.put("somewhereElse.Lisa", Lisa);
 2356  1 superI.setMav(_privateMav);
 2357   
 2358  1 id2.visit(_btc);
 2359   
 2360  1 assertEquals("There should be 2 errors", 2, errors.size());
 2361  1 assertEquals("The error message should be correct",
 2362    "The interface superI in superI is private and cannot be accessed from somewhereElse.Lisa",
 2363    errors.get(1).getFirst());
 2364   
 2365    /* The Runnable restriction has been dropped. */
 2366    // //Test that if the interface extends java.lang.Runnable, then an error is thrown.
 2367    // InterfaceDef id3 =
 2368    // new InterfaceDef(NONE, _publicMav, new Word(NONE, "JimesH"),
 2369    // new TypeParameter[0],
 2370    // new ReferenceType[] {new ClassOrInterfaceType(NONE, "java.lang.Runnable", new Type[0])},
 2371    // new BracedBody(NONE, new BodyItemI[0]));
 2372    // SymbolData sd = new SymbolData("JimesH");
 2373    // sd.setIsContinuation(false);
 2374    // sd.setInterface(true);
 2375    //
 2376    // symbolTable.clear();
 2377    // SymbolData runnableSd = new SymbolData("java.lang.Runnable");
 2378    // runnableSd.setMav(_publicMav);
 2379    // runnableSd.setIsContinuation(false);
 2380    // runnableSd.setPackage("java.lang");
 2381    // runnableSd.setInterface(true);
 2382    // sd.addInterface(runnableSd);
 2383    // symbolTable.put("JimesH", sd);
 2384    // symbolTable.remove("java.lang.Runnable");
 2385    // symbolTable.put("java.lang.Runnable", runnableSd);
 2386    //
 2387    // id3.visit(_btc);
 2388    // assertEquals("There should be 3 errors now", 3, errors.size());
 2389    // assertEquals("The error message should be correct",
 2390    // "JimesH extends the Runnable interface, which is not allowed at any language level",
 2391    // errors.get(2).getFirst());
 2392   
 2393    // Test that an error is thrown if you implement a class
 2394   
 2395  1 InterfaceDef id4 =
 2396    new InterfaceDef(NONE, _publicMav, new Word(NONE, "Bart"),
 2397    new TypeParameter[0],
 2398    new ReferenceType[] {new ClassOrInterfaceType(NONE, "superC", new Type[0])},
 2399    new BracedBody(NONE, new BodyItemI[0]));
 2400    // Test that no cyclic inheritance goes okay
 2401  1 SymbolData me = new SymbolData("Bart");
 2402  1 me.setInterface(true);
 2403  1 SymbolData superC = new SymbolData("superC");
 2404  1 superC.setInterface(false);
 2405    //Lisa.setSuperClass(superI);
 2406  1 me.addInterface(superC);
 2407  1 me.setIsContinuation(false);
 2408  1 superC.setIsContinuation(false);
 2409  1 _btc.symbolTable.put("Bart", me);
 2410  1 _btc.symbolTable.put("superC", superC);
 2411   
 2412  1 result = id4.visit(_btc);
 2413   
 2414   
 2415  1 assertEquals("There should be 3 errors now ", 3, errors.size());
 2416  1 assertEquals("The error message should be correct",
 2417    "superC is not an interface and thus cannot appear after the keyword 'extends' here",
 2418    errors.getLast().getFirst());
 2419   
 2420    // Test that no error is thrown if you implement an interface
 2421  1 superC.setInterface(true);
 2422  1 result = id4.visit(_btc);
 2423  1 assertEquals("There should still just be 3 errors", 3, errors.size());
 2424   
 2425    // Test that if a public interface is in a file of the wrong name, an error is thrown.
 2426  1 me.addModifier("public");
 2427  1 result = id4.visit(_btc);
 2428  1 assertEquals("There should be 4 errorrs", 4, errors.size());
 2429  1 assertEquals("The error message should be correct",
 2430    "Bart is public thus must be defined in a file with the same name.",
 2431    errors.getLast().getFirst());
 2432   
 2433    // Test that if a public interface is in a file of the right name, no error is thrown.
 2434  1 _btc._file = new File("Bart.dj1");
 2435  1 result = id4.visit(_btc);
 2436  1 assertEquals("There should still just be 4 errors", 4, errors.size());
 2437    }
 2438   
 2439  1 public void testForClassImportStatement() {
 2440  1 Word[] words = new Word[] {
 2441    new Word(NONE, "alpha"),
 2442    new Word(NONE, "beta")};
 2443  1 CompoundWord cw = new CompoundWord(NONE, words);
 2444  1 ClassImportStatement cis = new ClassImportStatement(NONE, cw);
 2445  1 SymbolData sd = new SymbolData("alpha.beta");
 2446    //Test one that will work
 2447  1 sd.setPackage("alpha");
 2448  1 sd.setIsContinuation(false);
 2449  1 sd.setMav(_publicMav);
 2450  1 symbolTable.put("alpha.beta", sd);
 2451   
 2452  1 cis.visit(_btc);
 2453  1 assertEquals("There should be no errors", 0, errors.size());
 2454   
 2455    //Test one that does not work (file is not in the right package)
 2456  1 sd.setPackage("");
 2457  1 cis.visit(_btc);
 2458   
 2459  1 assertEquals("There should be 1 error", 1, errors.size());
 2460  1 assertEquals("The error message should be correct",
 2461    "The class alpha.beta is not in the right package. Perhaps you meant to package it?",
 2462    errors.get(0).getFirst());
 2463    }
 2464   
 2465  1 public void testForPackageStatement() {
 2466  1 Word[] badWords = new Word[] {
 2467    new Word(NONE, "java"),
 2468    new Word(NONE, "lang"),
 2469    new Word(NONE, "Object")};
 2470  1 Word[] okWords = new Word[] { new Word(NONE, "java"), new Word(NONE, "lang")};
 2471   
 2472  1 PackageStatement badPackage =
 2473    new PackageStatement(NONE, new CompoundWord(NONE, badWords));
 2474  1 PackageStatement okPackage =
 2475    new PackageStatement(NONE, new CompoundWord(NONE, okWords));
 2476   
 2477    // SymbolData object = new SymbolData("java.lang.Object");
 2478    // object.setPackage("java.lang");
 2479    // object.setIsContinuation(false);
 2480    // symbolTable.put("java.lang.Object", object);
 2481   
 2482  1 okPackage.visit(_btc);
 2483  1 assertEquals("Should be 0 errors", 0, errors.size());
 2484   
 2485  1 badPackage.visit(_btc);
 2486  1 assertEquals("Should be 1 error", 1, errors.size());
 2487  1 assertEquals("Error message should be correct",
 2488    "java.lang.Object is not a allowable package name, because it conflicts with a class you have"
 2489    + " already defined",
 2490    errors.getLast().getFirst());
 2491    }
 2492   
 2493  1 public void testAutoBoxingAndUnboxing() {
 2494    //Test that autoboxing works for a method invocation going from java.lang.Integer to int
 2495  1 Expression e = new SimpleMethodInvocation(NONE,
 2496    new Word(NONE, "myMethod"),
 2497    new ParenthesizedExpressionList(NONE, new Expression[]{
 2498    new SimpleNameReference(NONE, new Word(NONE, "i"))}));
 2499  1 BodyItemI[] bii = new BodyItemI[] {new ExpressionStatement(NONE, e)};
 2500  1 BracedBody b = new BracedBody(NONE, bii);
 2501   
 2502  1 VariableData vd1 = new VariableData("i", _publicMav, symbolTable.get("java.lang.Integer"), true, _sd1);
 2503  1 VariableData vd2 = new VariableData("i", _publicMav, SymbolData.INT_TYPE, true, null);
 2504  1 _sd1.addVar(vd1);
 2505  1 MethodData md =
 2506    new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[] {vd2},
 2507    new String[0], null, NULL_LITERAL);
 2508  1 vd2.setEnclosingData(md);
 2509  1 _sd1.addMethod(md);
 2510   
 2511  1 b.visit(new ClassBodyTypeChecker(_sd1, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2512    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2513   
 2514  1 assertEquals("There should be no errors", 0, errors.size());
 2515   
 2516    //Test that autoboxing works for a method invocation going from double java.lang.Double
 2517  1 bii = new BodyItemI[] {new ExpressionStatement(NONE, e)};
 2518  1 b = new BracedBody(NONE, bii);
 2519   
 2520   
 2521  1 vd1 = new VariableData("i", _publicMav, symbolTable.get("java.lang.Double"), true, null);
 2522  1 vd2 = new VariableData("i", _publicMav, SymbolData.DOUBLE_TYPE, true, _sd1);
 2523  1 _sd1.setVars(new LinkedList<VariableData>());
 2524  1 _sd1.addVar(vd2);
 2525  1 _sd1.setMethods(new LinkedList<MethodData>());
 2526  1 md = new MethodData("myMethod", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[] {vd1},
 2527    new String[0], null, NULL_LITERAL);
 2528  1 vd1.setEnclosingData(md);
 2529  1 _sd1.addMethod(md);
 2530   
 2531  1 b.visit(new ClassBodyTypeChecker(_sd1, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2532    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2533   
 2534   
 2535  1 assertEquals("There should be no errors", 0, errors.size());
 2536   
 2537   
 2538    //Test that autoboxing can find the correct method def.
 2539  1 _sd1.setVars(new LinkedList<VariableData>());
 2540  1 _sd1.addVar(vd2);
 2541  1 _sd1.addVar(new VariableData("t", _publicMav, SymbolData.BOOLEAN_TYPE, false, _sd1));
 2542  1 _sd1.addMethod(new MethodData("myMethod", _publicMav, new TypeParameter[0],
 2543    SymbolData.BOOLEAN_TYPE, new VariableData[] {vd2}, new String[0], null,
 2544    NULL_LITERAL));
 2545   
 2546  1 Expression e2 = new SimpleAssignmentExpression(NONE,
 2547    new SimpleNameReference(NONE, new Word(NONE, "t")),
 2548    e);
 2549   
 2550  1 BodyItemI[] bii2 = new BodyItemI[] {new ExpressionStatement(NONE, e2)};
 2551  1 BracedBody b2 = new BracedBody(NONE, bii2);
 2552   
 2553  1 b2.visit(new ClassBodyTypeChecker(_sd1, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2554    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2555   
 2556  1 assertEquals("There should be no errors", 0, errors.size());
 2557   
 2558    //Test that autoboxing works for a constructor invocation
 2559  1 _sd1.setIsContinuation(false);
 2560  1 symbolTable.put("i.like.monkey", _sd1);
 2561  1 _sd1.setPackage("i.like");
 2562  1 Expression[] expr1 = new Expression[] {new SimpleNameReference(NONE, new Word(NONE, "i"))};
 2563  1 e = new SimpleNamedClassInstantiation(NONE,
 2564    new ClassOrInterfaceType(NONE, "i.like.monkey", new Type[0]),
 2565    new ParenthesizedExpressionList(NONE, expr1));
 2566   
 2567  1 bii = new BodyItemI[] {new ExpressionStatement(NONE, e)};
 2568  1 b = new BracedBody(NONE, bii);
 2569   
 2570  1 _sd1.setVars(new LinkedList<VariableData>());
 2571   
 2572  1 vd1 = new VariableData("i", _publicMav, symbolTable.get("java.lang.Integer"), true, _sd1);
 2573  1 vd2 = new VariableData("j", _publicMav, SymbolData.INT_TYPE, true, null);
 2574   
 2575  1 _sd1.addVar(vd1);
 2576  1 _sd1.setMethods(new LinkedList<MethodData>());
 2577  1 md = new MethodData("monkey", _publicMav, new TypeParameter[0], _sd1, new VariableData[]{vd2}, new String[0],
 2578    _sd1, NULL_LITERAL);
 2579  1 vd2.setEnclosingData(md);
 2580  1 _sd1.addMethod(md);
 2581   
 2582  1 b.visit(new ClassBodyTypeChecker(_sd1, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2583    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2584   
 2585  1 assertEquals("There should be no errors", 0, errors.size());
 2586   
 2587   
 2588    //Test that autoboxing works for an assignment from int to Integer
 2589  1 ExpressionStatement se = new ExpressionStatement(NONE,
 2590    new PlusAssignmentExpression(NONE,
 2591    new SimpleNameReference(NONE, new Word(NONE, "i")),
 2592    new SimpleNameReference(NONE, new Word(NONE, "j"))));
 2593   
 2594   
 2595  1 _sd1.addVar(vd2);
 2596  1 se.visit(new ClassBodyTypeChecker(_sd1, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2597    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2598    // System.err.println("*******The errant error message is: \n" + errors.get(0).getFirst());
 2599  1 assertEquals("There should be no errors", 0, errors.size());
 2600   
 2601    //Test that an error is thrown when there is an ambiguous method.
 2602  1 VariableData vd1Obj = new VariableData("i", _publicMav, symbolTable.get("java.lang.Integer"), true, null);
 2603  1 VariableData vd1Prim = new VariableData("i", _publicMav, SymbolData.INT_TYPE, true, null);
 2604  1 VariableData vd2Obj = new VariableData("j", _publicMav, symbolTable.get("java.lang.Short"), true, null);
 2605  1 VariableData vd2Prim = new VariableData("j", _publicMav, SymbolData.SHORT_TYPE, true, null);
 2606  1 MethodData md1 =
 2607    new MethodData("myMethod2", _publicMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE,
 2608    new VariableData[] {vd1Prim, vd2Prim}, new String[0], _sd1, NULL_LITERAL);
 2609  1 MethodData md2 =
 2610    new MethodData("myMethod2", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE,
 2611    new VariableData[] {vd1Obj, vd2Obj}, new String[0], _sd1, NULL_LITERAL);
 2612  1 vd1Obj.setEnclosingData(md2);
 2613  1 vd1Prim.setEnclosingData(md1);
 2614  1 vd2Obj.setEnclosingData(md2);
 2615  1 vd2Prim.setEnclosingData(md1);
 2616   
 2617  1 _sd1.setMethods(new LinkedList<MethodData>());
 2618  1 _sd1.addMethod(md1);
 2619  1 _sd1.addMethod(md2);
 2620  1 _sd1.setVars(new LinkedList<VariableData>());
 2621  1 _sd1.addVar(vd1Prim);
 2622  1 _sd1.addVar(vd2Obj);
 2623  1 Expression[] expr2 =
 2624    new Expression[]{new SimpleNameReference(NONE, new Word(NONE, "i")),
 2625    new SimpleNameReference(NONE, new Word(NONE, "j"))};
 2626  1 e = new SimpleMethodInvocation(NONE,
 2627    new Word(NONE, "myMethod2"),
 2628    new ParenthesizedExpressionList(NONE, expr2));
 2629  1 bii = new BodyItemI[] {new ExpressionStatement(NONE, e)};
 2630  1 b = new BracedBody(NONE, bii);
 2631   
 2632  1 b.visit(new ClassBodyTypeChecker(_sd1, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2633    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2634   
 2635  1 assertEquals("There should be one error", 1, errors.size());
 2636  1 assertEquals("The error message should be correct",
 2637    "myMethod2(int, java.lang.Short) is an ambiguous invocation. " +
 2638    "It matches both myMethod2(int, short) and myMethod2(java.lang.Integer, java.lang.Short)",
 2639    errors.get(0).getFirst());
 2640   
 2641    // test that if a method is overridden that it still works
 2642  1 SymbolData subSd = new SymbolData("sub");
 2643  1 subSd.setSuperClass(_sd1);
 2644  1 subSd.setIsContinuation(false);
 2645   
 2646  1 _sd1.setMethods(new LinkedList<MethodData>());
 2647  1 _sd1.addMethod(md1);
 2648  1 MethodData md3 = new MethodData("myMethod2", _publicMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE,
 2649    new VariableData[] {vd1Prim, vd2Prim}, new String[0], _sd1,
 2650    NULL_LITERAL);
 2651  1 b.visit(new ClassBodyTypeChecker(subSd, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2652    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2653  1 assertEquals("There should still be one error", 1, errors.size()); // Generated a duplicate error
 2654   
 2655    // test that if a sd1 has something that's ambiguous, so the superclass is ambiguous, the error is only thrown
 2656    // once when calling the method in the subclass.
 2657  1 subSd.setMethods(new LinkedList<MethodData>());
 2658  1 _sd1.addMethod(md2);
 2659  1 b.visit(new ClassBodyTypeChecker(subSd, _btc._file, "", new LinkedList<String>(), new LinkedList<String>(),
 2660    _sd1.getVars(), new LinkedList<Pair<SymbolData, JExpression>>()));
 2661  1 assertEquals("There should still be one error", 1, errors.size());
 2662  1 assertEquals("The error message should be correct",
 2663    "myMethod2(int, java.lang.Short) is an ambiguous invocation. It matches both " +
 2664    "myMethod2(int, short) and myMethod2(java.lang.Integer, java.lang.Short)",
 2665    errors.get(0).getFirst());
 2666    }
 2667   
 2668  1 public void testForInnerClassDef() {
 2669    //TODO: implement this test (for advanced level)
 2670    }
 2671    }
 2672    }