Clover coverage report - Java Language Levels Test Coverage (javalanglevels-20120305-r5436)
Coverage timestamp: Sun Mar 4 2012 22:02:46 CST
file stats: LOC: 3,447   Methods: 127
NCLOC: 2,019   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
LanguageLevelVisitor.java 77.9% 93.6% 91.3% 89.7%
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 org.objectweb.asm.*;
 40    import edu.rice.cs.javalanglevels.tree.*;
 41    import edu.rice.cs.javalanglevels.tree.Type; // resolve ambiguity
 42    import edu.rice.cs.javalanglevels.parser.JExprParser;
 43    import edu.rice.cs.javalanglevels.parser.ParseException;
 44    import edu.rice.cs.javalanglevels.util.Log;
 45    import edu.rice.cs.javalanglevels.util.Utilities;
 46    import java.util.*;
 47    import java.io.*;
 48    import edu.rice.cs.plt.reflect.JavaVersion;
 49    import edu.rice.cs.plt.iter.*;
 50    import edu.rice.cs.plt.io.IOUtil;
 51   
 52    import junit.framework.TestCase;
 53   
 54    /** Top-level Language Level Visitor that implements the constraint checking and symbol table building that is common to
 55    * first pass processing for the Functional and FullJava levels. There are two major complications in performing this
 56    * pass. First, references to symbols appear in the signatures of type (class/interface) definitions that have not yet
 57    * been defined. In the symbol table, the binding of these references must be deferred until a fixup list is executed
 58    * after the first pass visit has finished. This visitor and its descendants maintain a FixUp list for this purpose.
 59    * Second, the loading of signature information into the symbol table (called "resolving" in this documentation) is
 60    * deferred for some symbols. A dummy entry called a "continuation" is created in the symbol table for each such
 61    * symbol.
 62    */
 63    public class LanguageLevelVisitor extends JExpressionIFPrunableDepthFirstVisitor {
 64   
 65    public static final ModifiersAndVisibility PUBLIC_MAV =
 66    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
 67    public static final ModifiersAndVisibility PROTECTED_MAV =
 68    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
 69    public static final ModifiersAndVisibility PRIVATE_MAV =
 70    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
 71    public static final ModifiersAndVisibility PACKAGE_MAV =
 72    new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
 73    public static final ModifiersAndVisibility FINAL_MAV =
 74    new ModifiersAndVisibility(SourceInfo.NONE, new String[]{"final"});
 75   
 76    /** Errors we have encountered during this pass: string is the text of the error, JExpressionIF is the part of
 77    * the AST where the error occurs. */
 78    protected static LinkedList<Pair<String, JExpressionIF>> errors;
 79   
 80    /** Stores the classes we have referenced, and all their information, once they are resolved. Bound to static field
 81    * LanguageLevelConverter.symboltable. */
 82    public final Symboltable symbolTable;
 83   
 84    /** A table of the names of symbols for which dummy symbol entries (continuations) have been created and resolution
 85    * has been deferred. In some cases (symbols subsequently defined in a file being converted), resolution occurs
 86    * during execution. TODO: make this field dynamic. */
 87    static Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations;
 88   
 89    /** A table of the commands to be executed after this visitation is complete; these commands fill in missing objects
 90    * in the symbolTable (which were not available at the time the containing object was constructed.
 91    * TODO: make this field dynamic. */
 92    static LinkedList<Command> fixUps;
 93   
 94    // TODO: !!! This field appears vestigal; it does not appear to affect execution. Eliminate it
 95    /* A list of other files that are being visited. If the SourceFile is not null, then the source file was
 96    * visited as opposed to the class file. This info is used by LanguageLevelConverter in DrJava.
 97    * We keep the LLV rather than the file, because the LLV has a file, and we need some other information
 98    * stored in the LLV to properly look up the file.
 99    */
 100    static LinkedList<Pair<LanguageLevelVisitor, SourceFile>> visitedFiles;
 101   
 102    /**True once we have encountered an error we cannot recover from. TODO: ??? recover in what sense. */
 103    static boolean _errorAdded;
 104   
 105    /** The source file that is being compiled */
 106    File _file;
 107   
 108    /** The package of the current file */
 109    String _package;
 110   
 111    /** The name of the current enclosing class. This is null for a top-level visitor but is bound to an object in
 112    * IntermediateVisitor/FullJavaVisitor. The package name prefix is included. Inner class names include class
 113    * qualifiers. */
 114    String _enclosingClassName;
 115   
 116    /** A list of file names (classes) imported by the current file. TODO: change the name to _importedClasses or
 117    * _importedTypes. */
 118    LinkedList<String> _importedFiles;
 119   
 120    /** A list of package names imported by the current file. */
 121    LinkedList<String> _importedPackages;
 122   
 123    // A mapping from in scope generic type parameters to their bounds.
 124    public HashMap<String, SymbolData> _genericTypes;
 125   
 126    /** The fully qualified class names for top level ClassDefs and InterfaceDefs in the current file that have not
 127    * yet been defined. This filed is used to optimize symbol table lookups obviating the need for some fixups. */
 128    HashSet<String> _classesInThisFile;
 129   
 130    // /** The inner classes in this class body; null if this is not within a class body. */
 131    // HashSet<String> _innerClassesInThisBody;
 132   
 133    protected static final Log _log = new Log("LLConverter.txt", false);
 134   
 135    /** This constructor is called from the subclasses of LanguageLevelVisitor.
 136    * @param file The File corresponding to the source file we are visiting
 137    * @param packageName The name of the package corresponding to the file
 138    * @param importedFiles The list of files (classes) imported by this source file
 139    * @param importedPackages The list of packages imported by this source file
 140    * @param classesInThisFile The list of names of classes defined in this file
 141    * @param continuations The table of classes we have encountered but still need to resolve
 142    */
 143  2138 public LanguageLevelVisitor(File file,
 144    String packageName,
 145    String enclosingClassName,
 146    LinkedList<String> importedFiles,
 147    LinkedList<String> importedPackages,
 148    HashSet<String> classesInThisFile,
 149    Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations,
 150    LinkedList<Command> fixUps,
 151    HashMap<String, SymbolData> genericTypes) {
 152  2138 _file = file;
 153  2138 _package = packageName;
 154  2138 _enclosingClassName = enclosingClassName;
 155  2138 if (_enclosingClassName != null && _enclosingClassName.startsWith("null")) assert false;
 156  2138 _importedFiles = importedFiles;
 157  2138 _importedPackages = importedPackages;
 158  2138 _classesInThisFile = classesInThisFile;
 159    // _innerClassesInThisBody = new HashSet<String>();
 160  2138 this.continuations = continuations;
 161  2138 this.fixUps = fixUps;
 162  2138 _genericTypes = genericTypes;
 163   
 164  2138 symbolTable = LanguageLevelConverter.symbolTable;
 165   
 166  2138 assert fixUps != null;
 167  2138 assert _genericTypes != null;
 168   
 169    // Ensure that the imported packages include "java.lang"
 170  135 if (! _importedPackages.contains("java.lang")) _importedPackages.addFirst("java.lang");
 171    // Ensure that the symbol table contains the essential types; TODO: this is kludge; fix it !!!
 172  2138 LanguageLevelConverter.loadSymbolTable();
 173    }
 174   
 175    /** This constructor is used only in testing.
 176    * @param file The File corresponding to the source file we are visiting
 177    * @param packageName The name of the package corresponding to the file
 178    * @param importedFiles The list of files (classes) imported by this source file
 179    * @param importedPackages The list of packages imported by this source file
 180    * @param classesInThisFile The list of names of classes defined in this file
 181    * @param continuations The table of classes we have encountered but still need to resolve
 182    */
 183  491 public LanguageLevelVisitor(File file,
 184    String packageName,
 185    String enclosingClassName,
 186    LinkedList<String> importedFiles,
 187    LinkedList<String> importedPackages,
 188    HashSet<String> classesInThisFile,
 189    Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations,
 190    LinkedList<Command> fixUps) {
 191  491 this(file, packageName, enclosingClassName, importedFiles, importedPackages, classesInThisFile, continuations, fixUps,
 192    new HashMap<String, SymbolData>());
 193    }
 194   
 195    /* Reset the nonStatic fields of this visitor. Used during testing. */
 196  0 protected void _resetNonStaticFields() {
 197  0 _file = new File("");
 198  0 _enclosingClassName = null;
 199  0 _package = "";
 200  0 _importedFiles = new LinkedList<String>();
 201  0 _importedPackages = new LinkedList<String>();
 202    }
 203   
 204    /** @return the accessor name corresponding to given field name. */
 205  136 public static String getFieldAccessorName(String name) { return name; }
 206   
 207    /**@return the source file*/
 208  0 public File getFile() { return _file; }
 209   
 210    /** @return true if this data is a constructor, i.e., it is a method data, its name and return type are the same, and
 211    * its return type matches its enclosing sd.
 212    */
 213  14 protected boolean isConstructor(Data d) {
 214  1 if ( !(d instanceof MethodData) ) return false;
 215  13 MethodData md = (MethodData) d;
 216  13 SymbolData rt = md.getReturnType();
 217  13 SymbolData sd = md.getSymbolData(); // if this is a constructor, sd must be a defined symbol
 218   
 219  13 return (rt != null && sd != null && rt.getName().indexOf(md.getName()) != -1 && rt == sd);
 220    }
 221   
 222    /** Factory method that constructs an appropriate class body visitor for this visitor class (either
 223    * ClassBodyIntermediateVisitor or ClassBodyFullJavaVisitor). This class and method should be abstract, but the LLV
 224    * class is used concretely in testing and elswhere. The default choice is ClassBodyFullJavaVisitor. */
 225  0 public LanguageLevelVisitor newClassBodyVisitor(SymbolData anonSD, String anonName) {
 226  0 return new ClassBodyFullJavaVisitor(anonSD, anonName, _file, _package, _importedFiles, _importedPackages,
 227    _classesInThisFile, continuations, fixUps);
 228    }
 229   
 230    /** Takes a classname and returns only the final segment of it. This removes all the dots. Returns "" for anonymous
 231    * class names. TODO: Do we need to fix this? */
 232  70144 public static String getUnqualifiedClassName(String className) {
 233  70144 int lastIndexOfDot = className.lastIndexOf('.');
 234  70144 if (lastIndexOfDot != -1) {
 235  66552 className = className.substring(lastIndexOfDot + 1);
 236    }
 237  70144 int lastIndexOfDollar = className.lastIndexOf('$');
 238  70144 if (lastIndexOfDollar != -1) {
 239  10124 className = className.substring(lastIndexOfDollar + 1);
 240    }
 241    // Remove any leading numbers TODO: why do this? If we encounter a
 242  70144 while (className.length() > 0 && Character.isDigit(className.charAt(0))) {
 243  2182 className = className.substring(1, className.length());
 244    }
 245  70144 return className;
 246    }
 247   
 248    /** Convert the ReferenceType[] to a String[] with the names of the ReferenceTypes. */
 249  222 protected static String[] referenceType2String(ReferenceType[] rts) {
 250  222 String[] throwStrings = new String[rts.length];
 251  222 for (int i = 0; i < throwStrings.length; i++) {
 252  9 throwStrings[i] = rts[i].getName();
 253    }
 254  222 return throwStrings;
 255    }
 256   
 257   
 258    // /** Build a SourceInfo corresponding to the specified class name, with -1 as the
 259    // * value for row and column of the start and finish.
 260    // */
 261    // protected static SourceInfo _makeSourceInfo(String qualifiedClassName) {
 262    // return new SourceInfo(new File(qualifiedClassName), -1, -1, -1, -1);
 263    // }
 264   
 265    /** Check to see if the specified classname is the name of a fully qualified java library class. */
 266  3398 public static boolean isJavaLibraryClass(String className) {
 267  3398 return className.startsWith("java.") ||
 268    className.startsWith("javax.") ||
 269    className.startsWith("org.ietf.") ||
 270    className.startsWith("org.omg.") ||
 271    className.startsWith("org.w3c.") ||
 272    className.startsWith("org.xml.") ||
 273    className.startsWith("sun.") ||
 274    className.startsWith("junit.framework."); //TODO: help!
 275    }
 276   
 277    /** @return true if the specified VariableData overwrites one of the members of the list of VariableDatas
 278    * and false otherwise. A VariableData is overwritten if its name is shadowed.
 279    */
 280  0 public static boolean isDuplicateVariableData(LinkedList<VariableData> vds, VariableData toInsert) {
 281  0 for (int i = 0; i<vds.size(); i++) {
 282  0 VariableData temp = vds.get(i);
 283  0 if (temp.getName().equals(toInsert.getName())) {
 284  0 return true;
 285    }
 286    }
 287  0 return false;
 288    }
 289   
 290    /* Creates a new ArrayData of the element type specified by eltSd with llv and si as the corresponding
 291    * LanguageLevelVisitor and SourceInfo and enters it in the SymbolTable. NOTE: this code erroneously
 292    * marks an array symbol as a non-continuations when the element symbol is still a continuation!
 293    */
 294  19 public ArrayData defineArraySymbolData(SymbolData eltSd, LanguageLevelVisitor llv, SourceInfo si) {
 295  19 ArrayData arraySd = new ArrayData(eltSd, llv, si); // sets _ isContinuation to false!
 296    // System.err.println("##### Defining the array symbol " + arraySd.getName());
 297  19 symbolTable.put(arraySd.getName(), arraySd);
 298  19 return arraySd;
 299    }
 300   
 301    /* Convenience method used in testing. */
 302  26 private SymbolData getArraySymbolData(String eltClassName, SourceInfo si, boolean addError, boolean checkImports) {
 303  26 return _getArraySymbolData(eltClassName, si, addError, checkImports /*, _classesInThisFile*/);
 304    }
 305   
 306    /** Gets the SymbolData for an array type given className, the class name for its element type. First, it looks up the
 307    * the SymbolData for className. If it's not null, then it tries to lookup the SymbolData for className + "[]"
 308    * If it's found, return it. If not, create a new ArrayData and put it in the symbolTable. This method is a leaf
 309    * in the 'get...Symbol' hierarchy.
 310    * @param className The String name of the array type we're trying to resolve.
 311    * @param si The SourceInfo corresponding to the class. Used if an error is encountered..
 312    */
 313  26 private SymbolData _getArraySymbolData(String eltClassName, SourceInfo si, boolean addError, boolean checkImports/*,
 314    HashSet<String> classesInThisFile*/) {
 315    // resolve should only be true when post-visitation resolution is performed
 316    // if (eltClassName.equals("String[]")) System.err.println("String[] passed to getArraySymbolData");
 317    // if (eltClassName.equals("String")) System.err.println("String passed to getArraySymbolData");
 318  26 SymbolData eltSD = getSymbolData(eltClassName, si, addError, checkImports/*, classesInThisFile*/);
 319  26 if (eltSD != null) {
 320    // if (eltSD.getName().equals("java.lang.String")) System.err.println("java.lang.String FOUND");
 321  21 SymbolData sd = symbolTable.get(eltSD.getName() + "[]"); // Look up fully qualified name
 322  11 if (sd != null) return sd;
 323  10 else return defineArraySymbolData(eltSD, this, si /*, classesInThisFile*/);
 324    }
 325  5 else return null;
 326    }
 327   
 328    /** Get the SymbolData for the array type given the fully qualified className for the element type. Lookup the
 329    * element type; if it's not null, then try to lookup the symbol for the qualifiedClassName + "[]". If it's already
 330    * there, return it. If not, create a new ArrayData and put it in the Symbol Table. This method is a leaf in the
 331    * 'get...SymbolDataHelper' hierarchy.
 332    * @param className The String name of the array type we're trying to resolve.
 333    * @param si The SourceInfo corresponding to the class. Used if an error is encountered.
 334    * @param resolve true if this SymbolData needs to be completely resolved.
 335    * @param fromClassFile true if this type is from a class file.
 336    */
 337  40 private SymbolData _getQualifiedArraySymbolData(String eltClassName, SourceInfo si, boolean resolve,
 338    boolean fromClassFile /*, HashSet<String> classesInThisFile*/) {
 339    // resolve should only be true when post-visitation resolution is performed
 340  40 SymbolData eltSD = getQualifiedSymbolData(eltClassName, si, resolve, fromClassFile, true /*, classesInThisFile*/);
 341  40 if (eltSD != null) {
 342  9 SymbolData sd = symbolTable.get(eltSD.getName() + "[]"); // Look up fully qualified name
 343  0 if (sd != null) return sd;
 344  9 else return defineArraySymbolData(eltSD, this, si /*, classesInThisFile*/);
 345    }
 346  31 else return null;
 347    }
 348   
 349    /** Checks the file system for the class name, returning the corresponding SymbolData if there is an up-to-date match.
 350    * If resolve is false but a corresponding source file is matched, a continuation is returned. If no source file is
 351    * found but a class file is found, the symbol is resolved against the class file even if resolve is false.
 352    * If resolve is true and a corresponding source file is found, the symbol is resolved against the corresponding
 353    * class file provided it is up-to-date. If it is not up-to-date, the method throws an error message. If no source
 354    * file or class file corresponding to the class is found, SymbolData.NOT_FOUND is returned.
 355    * @param qualifiedClassName The name of the class we're looking up.
 356    * @param si Information about where the class was called from.
 357    * @param resolve true if we want to fully resolve the SymbolData.
 358    * @param addError true if we want to throw errors.
 359    ` */
 360  14 protected SymbolData _getSymbolDataFromFileSystem(final String qualifiedClassName, SourceInfo si, boolean resolve,
 361    boolean addError) {
 362    // If qualifiedClassName is already defined (and not a continuation to resolve), return
 363  14 SymbolData sd = symbolTable.get(qualifiedClassName);
 364  7 if (sd != null && (! sd.isContinuation() || ! resolve)) return sd;
 365    // Note: sd != null && ! sd.isContinuation => sd has already been resolved
 366   
 367    // // Is qualifiedClassName in _classesInThisFile, look it up directly in the parsed ASTs
 368    // boolean present = _classesInThisFile.contains(qualifiedClassName);
 369    // if (present) return _identifyTypeFromClassNamesInThisfile(qualifiedClassName, si, resolve);
 370   
 371    /* If qualifiedClassName is not in the symbol table or list of classes to be parsed, check if the class is defined
 372    * in this package tree.
 373    */
 374  7 String qualifiedClassNameWithSlashes =
 375    qualifiedClassName.replace('.', System.getProperty("file.separator").charAt(0));
 376  7 File _fileParent = _file.getParentFile();
 377    // Create var that is eventually set to root of package (for _file)
 378  7 String programRoot = (_fileParent == null) ? "" : _fileParent.getAbsolutePath();
 379  7 assert (programRoot != null); // parent != null => parent exists.
 380   
 381  7 final String path; // The expected path name of the class file (less .class) for qualifiedClassName
 382   
 383  7 if (programRoot.length() > 0) {
 384  6 String packageWithSlashes = _package.replace('.', System.getProperty("file.separator").charAt(0));
 385    // Get index of slash preceding first char of package name
 386  6 int indexOfPackage = programRoot.lastIndexOf(packageWithSlashes);
 387  1 if (indexOfPackage < 0) path = qualifiedClassName;
 388    else {
 389  5 programRoot = programRoot.substring(0, indexOfPackage);
 390  5 path = programRoot + System.getProperty("file.separator") + qualifiedClassNameWithSlashes;
 391    }
 392    }
 393    else {
 394  1 path = qualifiedClassNameWithSlashes; // Using file system root for programRoot
 395    }
 396   
 397  7 String dirPath; /* the expected directory of the file we're trying to resolve */
 398  7 String newPackage = ""; /* the package of the file we're trying to resolve */
 399  7 int lastSlashIndex = qualifiedClassNameWithSlashes.lastIndexOf(System.getProperty("file.separator"));
 400  7 if (lastSlashIndex != -1) {
 401  2 String newPackageWithSlashes = qualifiedClassNameWithSlashes.substring(0, lastSlashIndex);
 402  2 dirPath = programRoot + System.getProperty("file.separator") + newPackageWithSlashes;
 403  2 newPackage = newPackageWithSlashes.replace(System.getProperty("file.separator").charAt(0), '.');
 404    }
 405    else {
 406  5 int lastPathSlashIndex = path.lastIndexOf(System.getProperty("file.separator"));
 407  4 if (lastPathSlashIndex != -1) dirPath = path.substring(0, lastPathSlashIndex);
 408  1 else dirPath = "";
 409    }
 410   
 411    // Find class file and matching source file for qualifiedClassName -- if they exist
 412   
 413  7 File classFile = new File(path + ".class"); // create File object for class file
 414   
 415    // Then look for the most recently modified matching source (.djx or .java) file.
 416  7 File[] sourceFiles = new File(dirPath).listFiles(new FileFilter() {
 417  152 public boolean accept(File f) {
 418  152 try {
 419  152 f = f.getCanonicalFile();
 420  152 return new File(path + ".dj").getCanonicalFile().equals(f) ||
 421    new File(path + ".dj0").getCanonicalFile().equals(f) ||
 422    new File(path + ".dj1").getCanonicalFile().equals(f) ||
 423    new File(path + ".dj2").getCanonicalFile().equals(f) ||
 424    new File(path + ".java").getCanonicalFile().equals(f);
 425    }
 426  0 catch (IOException e) { return false; }
 427    }});
 428   
 429  7 File sourceFile = null; // sourceFile is either null or an existing file
 430  7 if (sourceFiles != null) {
 431  5 long mostRecentTime = 0;
 432  5 for (File f : sourceFiles) {
 433  5 long currentLastModified = f.lastModified();
 434  5 if (f.exists() && mostRecentTime < currentLastModified) {
 435  5 mostRecentTime = currentLastModified;
 436  5 sourceFile = f;
 437    }
 438    }
 439    }
 440   
 441    // // Claim: sourceFile is not the current file or sd is an inner class. Otherwise, className would have been in
 442    // // _classesInThisFile.
 443   
 444    // If sourceFile exists, we have identified the class corresponding to qualifiedClassName. If resolve is false,
 445    // simply create and return the appropriate continuation, deferring the loading of class information until reolution
 446    // time. If there is no corresponding class file or the class file is not
 447    // up-to-date, signal an error. Otherwise load the symbol table information from the class file
 448   
 449  7 if (sourceFile != null) {
 450    // First see if we even need to resolve this class. If not, create a continuation and return it.
 451  4 if (! resolve) {
 452  0 assert sd == null;
 453  0 sd = makeContinuation(si, qualifiedClassName); // create a continuation for qualifiedClassName; defer resolution
 454  0 return sd;
 455    // else {
 456    // sd = new SymbolData(qualifiedClassName);
 457    // continuations.put(qualifiedClassName,
 458    // new Triple<SourceInfo, LanguageLevelVisitor, SymbolData>(si, this, sd));
 459    // symbolTable.put(qualifiedClassName, sd);
 460    // return sd;
 461    }
 462    // Get last modified time of corresponding class file
 463  4 long classModTime = classFile.lastModified();
 464  1 if (classModTime == 0L) return null; // if classFile does not exist, return
 465   
 466  3 if (sourceFile.lastModified() > classModTime) { // the class file is out of date
 467  0 if (addError) {
 468  0 _addAndIgnoreError("The file " + sourceFile.getAbsolutePath() +
 469    " needs to be recompiled; it's class files either do not exist or are out of date.",
 470    new NullLiteral(si));
 471    }
 472  0 return null;
 473    }
 474    }
 475   
 476    // if source file exists, confirm that the corresponding class file is up to date
 477    // if source file does not exist, confirm that a class file does exist
 478  6 if (classFile.exists()) {
 479    // read this classfile, create the SymbolData and return it
 480  4 _log.log("Reading classFile " + qualifiedClassName);
 481  4 sd = LanguageLevelConverter._classFile2SymbolData(qualifiedClassName, programRoot);
 482  4 if (sd == null) {
 483  0 if (addError) {
 484  0 _addAndIgnoreError("File " + classFile + " is not a valid class file.", new NullLiteral(si));
 485    }
 486  0 return null;
 487    }
 488  4 _log.log("Returning symbol constructed by loading class file");
 489  4 return sd;
 490    }
 491  2 return SymbolData.NOT_FOUND;
 492    }
 493   
 494    /** Resolves the continuation cont. */
 495  6 public SymbolData resolveSymbol(SourceInfo si, SymbolData cont) {
 496    // System.err.println("***ALARM*** resolveSymbol called for '" + cont + "'");
 497  6 return getQualifiedSymbolData(cont.getName(), si, true);
 498    }
 499   
 500    /** Call getSymbolData with some default values. By default addError is true, since we want to
 501    * display errors. By default checkImports is true, since we want to consider imported packages and classes.
 502    * @param className The referenced name of the class to resolve.
 503    * @param si The SourceInfo corresponding to the reference to the type
 504    */
 505  1461 public SymbolData getSymbolData(String className, SourceInfo si) {
 506  1461 return getSymbolData(className, si, true, true);
 507    }
 508   
 509    /** Call getSymbolData with some default values. By default checkImports will be true, since we want to
 510    * consider imported packages and classes initially.
 511    * @param className The referenced name of the class to identify
 512    * @param si The SourceInfo corresponding to the reference to the type
 513    * @param addError true if we want to give an error if this class cannot be resolved.
 514    */
 515  257 protected SymbolData getSymbolData(String className, SourceInfo si, boolean addError) {
 516  257 return this.getSymbolData(className, si, addError, true);
 517    }
 518   
 519    /** Simple signature for getSymbol that uses the current context to fill in context information, i.e., it passes _file
 520    * for file, _package for pkg, _importedFiles for importedFiles, _importedPackages for importedPackages, and
 521    * _enclosingClass for enclosingClassName. This version should be used in all contexts EXCEPT fixups which are
 522    * executed outside of any context and must provide saved context information.
 523    */
 524  3149 protected SymbolData getSymbolData(String className, SourceInfo si, boolean addError, boolean checkImports) {
 525  3149 return getSymbolData(_file, _package, _importedFiles, _importedPackages, _enclosingClassName,
 526    className, si, addError, checkImports);
 527    }
 528   
 529    /** This method processes classNames which may or may not include qualifying prefixes. Array types are recognized and
 530    * treated recursively. The raw className is initially compared with:
 531    * * top-level classes defined in the this file;
 532    * * fully qualified classes in the file system;
 533    * * inner classes defined in the enclosing class;
 534    * * classes in the same package defined in other files;
 535    * * imported classes; and
 536    * * classes in imported packages.
 537    * Then className is decomposed in a prefix and an extension where prefixes are matched against symbols as described
 538    * above. If a matching prefix is found, the remainder is matched against inner classes of the matched symbol.
 539    * The protocol does not exactly match the one in the JLS.
 540    * This results of method are relative to _file, _package, _importedFiles, _importedPackages, and _enclosingClassName.
 541    * The external variables _classesInThisFile and _innerClassesInThisBody are used to reduce the number of fixups but
 542    * should not affect the ultimate results (after fixups) of any searches.
 543    * This method calls getQualifiedSymbolData to look up fully qualified class names in the symbol table; this process
 544    * does not depend on anything but the contents of the symbol table.
 545    * @param file The file containing the className reference.
 546    * @param package The package corresponding to file.
 547    * @param importedFiles The imported files for this file
 548    * @param importedPackages The imported Packages for this file
 549    * @param enclosingClassName The enclosing className
 550    * @param className The referenced name of the class to lookup.
 551    * @param si The SourceInfo of the reference to className used in case of an error.
 552    * @param addError Whether to add errors or not
 553    * @param checkImports Whether to try prepending the imported package names
 554    */
 555  3149 protected SymbolData getSymbolData(File file,
 556    String pkg,
 557    LinkedList<String> importedFiles,
 558    LinkedList<String> importedPackages,
 559    String enclosingClassName,
 560    String className,
 561    SourceInfo si,
 562    boolean addError,
 563    boolean checkImports) {
 564   
 565  3149 if (className == null) {
 566    // System.err.println("***ERROR*** getSymbolData called with null className");
 567    assert false;
 568    }
 569   
 570    /** Check to see if type with className (as is) can be found (including a check against generic type variables). */
 571  3149 SymbolData existingSD = getQualifiedSymbolData(className, si, false, false, addError);
 572  2379 if (existingSD != null) return existingSD;
 573   
 574  770 if (className.endsWith("[]")) { // className refers to an array type
 575  21 String eltClassName = className.substring(0, className.length() - 2); // may not be fully qualified
 576    // if (eltClassName.equals("String")) System.err.println("getSymbolData called for String[]");
 577  21 return getArraySymbolData(/* file, pkg, importedFiles, importedPackages, enclosingClassName, */
 578    eltClassName, si, addError, checkImports);
 579    }
 580   
 581    // Try matching the className against current package
 582  749 String qualClassName = getQualifiedClassName(pkg, className); // TODO: make this work for an inner class
 583  749 existingSD = getQualifiedSymbolData(qualClassName, si);
 584  8 if (existingSD != null) return existingSD;
 585   
 586    // Check for relative inner class reference
 587  741 if (enclosingClassName != null) {
 588    // Assume that className is an inner class relative to _enclosingClassName (which always holds for local
 589    // classes and often holds for immediate inner class references. Fortunately, local class references cannot be
 590    // forward references.
 591  377 SymbolData enclosingSD = getQualifiedSymbolData(enclosingClassName, si);
 592  377 if (enclosingSD != null) {
 593  371 SymbolData sd = enclosingSD.getInnerClassOrInterface(className);
 594  13 if (sd != null) return sd;
 595    // // NOTE: the following should be unnecessary since the forward referenced inner symbol should be sd above
 596    // // Check for forward reference to an inner class of the enclosing class
 597    // String qualifiedName = enclosingSD + '.' + className;
 598    // if (_innerClassesInThisBody.contains(qualifiedName)) // forward reference to inner class/interface
 599    // return getQualifiedSymbolData(qualifiedName, si); // return continuation
 600    }
 601    }
 602   
 603    // TODO: imported inner class can have qualification so the following logic is broken. The following logic
 604    // ignores the possibility of importing an inner class. Fix this !!!
 605  728 if (className.indexOf('.') == -1) { // className has no qualification; may be imported
 606   
 607    // Check if the className's package was imported.
 608  659 if (checkImports) {
 609    // if (className.equals("Object")) System.err.println("***SHOUT*** checking imports for 'Object'");
 610   
 611    // Check if className was specifically imported.
 612    // We will not check that the package is correct here, because it is caught in the type checker.
 613  658 Iterator<String> iter = importedFiles.iterator();
 614  658 while (iter.hasNext()) {
 615  38 String s = iter.next();
 616  38 if (s.endsWith(className)) {
 617  13 SymbolData importSD = symbolTable.get(s); // All imported files should be in the symbol table.
 618    // if (importSD == null) System.err.println("***ALARM*** Imported symbol lookup failed for " + s);
 619    // if importSD is a continuation it will be subsequently be resolved
 620  13 return importSD;
 621    }
 622    }
 623    }
 624   
 625    // Look for a match against imported packages
 626    // TODO: Within a relative class name the separators must be converted from '.' to '$'
 627  646 SymbolData resultSD = null;
 628  646 assert importedPackages.contains("java.lang");
 629    // assert symbolTable.containsKey("java.lang.Object");
 630  646 for (String prefix: importedPackages) {
 631  685 String s = prefix + '.' + className;
 632    // if (className.equals("java.lang.Object")) System.err.println("***ALARM*** Looking up: " + s);
 633  685 SymbolData sD = getQualifiedSymbolData(s, si, false, false, false);
 634    // if (qualClassName.equals("java.lang.Object"))
 635    // System.err.println("matching sd is: " + sD + "\nsymbolTable.get(\"" + s + "\") = "+ symbolTable.get(s));
 636  685 if (sD != null) {
 637  382 if (resultSD == null || resultSD.equals(sD)) resultSD = sD;
 638    else { // sD is NOT the first match; flag an error
 639  1 if (addError) { // TODO: why do we suppress this error in some cases?
 640  1 _addAndIgnoreError("The class name " + qualClassName + " is ambiguous. It could be " + resultSD.getName()
 641    + " or " + sD.getName(), new NullLiteral(si));
 642  1 return null;
 643    }
 644    }
 645    }
 646    }
 647  376 if (resultSD != null) return resultSD;
 648  269 else return null; // subsequent searching assumes that className is qualified.
 649    }
 650   
 651    // Decompose class name as fully qualified name followed by an inner class reference
 652    // TODO: the separator within inner class names is '$'
 653  69 int indexOfNextDot = 0;
 654    // int indexOfNextDollar = className.indexOf("$"); // '$' only appears as separator for inner class names
 655  69 SymbolData sd;
 656  69 int length = className.length();
 657  69 while (indexOfNextDot != length) {
 658  150 indexOfNextDot = className.indexOf('.', indexOfNextDot + 1);
 659  51 if (indexOfNextDot == -1) { indexOfNextDot = length; }
 660  150 String prefix = className.substring(0, indexOfNextDot);
 661   
 662    /* We want to try finding each prefix in the symbol table; the decomposition is putative. */
 663  150 sd = getQualifiedSymbolData(prefix, si, false, false, false);
 664  150 if (sd != null && sd != SymbolData.AMBIGUOUS_REFERENCE) { // prefix matches an existing symbol
 665  23 String outerClassName = prefix;
 666  23 String innerClassName = "";
 667  23 if (indexOfNextDot != length) {
 668  23 SymbolData outerClassSD = sd;
 669  23 innerClassName = className.substring(indexOfNextDot + 1); // putative relative name of inner class
 670    // System.err.println("Outer class prefix found: " + prefix + " inner class extension: " + innerClassName);
 671    // NOTE: should be able to search symbolTable using getSymbolData
 672  23 sd = outerClassSD.getInnerClassOrInterface(innerClassName);
 673  18 if (sd != null) return sd;
 674    // System.err.println("Corresponding symbol = " + sd);
 675    // if (sd == null) { // create continuation for inner class; we are forbidding some ambiguities Java may permit
 676    // sd = addInnerSymbolData(si, outerClassName + '.' + innerClassName, outerClassSD);
 677    // }
 678    /* otherwise try another decomposition. */
 679    }
 680    }
 681    }
 682  51 return null;
 683    }
 684   
 685    /** Try to look up name from the context of the lhs.
 686    * @param lhs The TypeData corresponding to the enclosing of this name reference
 687    * @param name The name piece to look up from the context of lhs
 688    * @param si The SourceInfo corresponding to this reference
 689    * @param addError true if an error should be added
 690    * @return The SymbolData corresponding to this lookup, or NOT_FOUND or null if it could not be found
 691    */
 692  21 protected SymbolData getSymbolData(TypeData lhs, String name, SourceInfo si, boolean addError) {
 693    //arguments we do not need to pass in
 694  21 boolean checkImports = false;
 695   
 696  5 if (lhs == null) return null;
 697   
 698  16 else if (lhs instanceof PackageData) {
 699  0 String qualClassName = lhs.getName() + '.' + name;
 700  0 return getQualifiedSymbolData(qualClassName, si, false, false, addError);
 701    }
 702   
 703    else { // if (lhs instanceof SymbolData) {
 704  16 SymbolData result = lhs.getInnerClassOrInterface(name);
 705  16 if (result == SymbolData.AMBIGUOUS_REFERENCE) {
 706  0 if (addError) { _addAndIgnoreError("Ambiguous reference to class or interface " + name, new NullLiteral(si)); }
 707  0 return null;
 708    }
 709  16 return result;
 710    }
 711    }
 712   
 713    /** Tries to find (or in some cases creates) the SymbolData for the fiven fully qualified class name. It
 714    * searches imported files, primitive types, as well as types in the symbol table. */
 715  235 protected SymbolData getQualifiedSymbolData(String qualClassName) {
 716  235 return getQualifiedSymbolData(qualClassName, SourceInfo.NONE);
 717    }
 718   
 719    /** Tries to find (or in some cases creates) the SymbolData for the fiven fully qualified class name. It
 720    * searches imported files, primitive types, as well as types in the symbol table. */
 721  1423 protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si) {
 722  1423 return getQualifiedSymbolData(qualClassName, si, false, false, true);
 723    }
 724   
 725    /** This method tries to find (or in some cases creates) the SymbolData for the fiven fully qualified class name. It
 726    * searches imported files, primitive types, as well as types in the symbol table. If resolve is true, it loads the
 727    * symbolTable with all of the requisite information about qualClassName. */
 728  57 protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si, boolean resolve) {
 729  57 return getQualifiedSymbolData(qualClassName, si, resolve, false, true);
 730    }
 731   
 732   
 733    /** This method tries to find (or in some cases creates) the SymbolData for the fiven fully qualified class name or
 734    * class name. It uses _classesInThisFile to avoid returning null in some cases (eliminating the need for some
 735    * fixups). Except for the _classesInThisFile optimization (which works uniformly if it is set to null during
 736    * continuation resolution and fixups), this lookup only depends on the contents of the symbol table and the file
 737    * system.
 738    * @param qualClassName The fully qualified name of the class to lookup.
 739    * @param si The SourceInfo of the reference to qualClassName used in case of an error.
 740    * @param resolve Whether to return a continuation or fully parse the class.
 741    * @param fromClassFile Whether this was called from the class file reader.
 742    * @param addError Whether to add errors. We don't add errors when iterating through a qualified class name's
 743    * package. (??)
 744    */
 745  5727 protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si, boolean resolve, boolean fromClassFile,
 746    boolean addError) {
 747  5727 assert qualClassName != null;
 748    // if (qualClassName.startsWith("RefInnerClassCrazy"))
 749    // System.err.println("ALARM: getQualifiedSymbolData called for '" + qualClassName + "'");
 750    //
 751  5727 if (qualClassName.equals("java.lang.Throwable")) {
 752    // System.err.println("***ALARM: getQualifiedSymbolData called for '" + qualClassName + "'");
 753    // if (symbolTable.get(qualClassName) != null) System.err.println("***ALARM: java.lang.Throwable already exists");
 754    }
 755   
 756  5727 assert (qualClassName != null && ! qualClassName.equals(""));
 757   
 758    // Check for primitive types.
 759    // System.err.println("***** Checking for primitive symbol " + qualClassName);
 760  5727 SymbolData sd = LanguageLevelConverter._getPrimitiveSymbolData(qualClassName);
 761  5727 if (sd != null) {
 762    // System.err.println("***** Matched for primitive symbol " + sd);
 763  599 return sd;
 764    }
 765   
 766    // Check for references to generic types (only happens in FullJava code)
 767    // TODO !!! Does not handle forward references
 768  5128 String name = getUnqualifiedClassName(qualClassName);
 769  5128 if (_genericTypes.containsKey(name)) {
 770    // Utilities.show("Return type " + name + " is generic and value is " + _genericTypes.get(name));
 771  0 return _genericTypes.get(name);
 772    }
 773   
 774    // Check for already defined types
 775  5128 SymbolData existingSD = symbolTable.get(qualClassName);
 776  2864 if (existingSD != null && (! resolve || ! existingSD.isContinuation())) return existingSD;
 777   
 778    // Check for array types.
 779  2264 if (qualClassName.endsWith("[]"))
 780  40 return _getQualifiedArraySymbolData(qualClassName.substring(0, qualClassName.length() - 2), si, resolve,
 781    fromClassFile);
 782    // Check for generic type variables
 783  2224 SymbolData genericBinding = _genericTypes.get(qualClassName);
 784  0 if (genericBinding != null) return genericBinding; // may return SymbolData.NOT_FOUND because bound is undefined
 785   
 786    // If qualClassName is a library file, resolve it immediately by reading its class file.
 787  2224 if (isJavaLibraryClass(qualClassName)) {
 788  695 _log.log("Calling _classFile2SymbolData");
 789  695 SymbolData cfSD = LanguageLevelConverter._classFile2SymbolData(qualClassName, null);
 790  695 if (! qualClassName.startsWith("java.") && ! qualClassName.startsWith("sun."))
 791    // System.err.println("Defining class file symbol " + qualClassName);
 792  72 assert cfSD == null || symbolTable.contains(cfSD);
 793  695 return cfSD;
 794    }
 795   
 796  1529 if (_classesInThisFile.contains(qualClassName)) // Make continuation for top level class not yet parsed in this file
 797  12 return makeContinuation(si, qualClassName);
 798   
 799    // If performing post-visit resolution, read the signature info for this symbol from a class file
 800  1517 if (resolve) { // Look for up-to-date class file
 801  2 SymbolData newSd = _getSymbolDataFromFileSystem(qualClassName, si, true, true); // resolve, addError = true
 802  2 if (newSd != null && newSd != SymbolData.NOT_FOUND) {
 803  2 _log.log("Returning " + sd + " from file system");
 804  2 return newSd;
 805    }
 806    else {
 807    // System.err.println("********* ALARM: The class " + qualClassName + " was not found. Symbol = " + newSd);
 808  0 _addAndIgnoreError("The class " + qualClassName + " was not found.", new NullLiteral(si));
 809    assert false;
 810    }
 811    }
 812  1515 return null; // qualClassName not found
 813    }
 814   
 815   
 816    /** The Qualified Class Name is the package, followed by a dot, followed by the rest of the class name.
 817    * If the provided className is already qualified, just return it. If the package is not empty,
 818    * and the className does not start with the package, append the package name onto the className, and return it.
 819    * @param className The className to qualify.
 820    */
 821  880 protected String getQualifiedClassName(String className) { return getQualifiedClassName(_package, className); }
 822   
 823    /** If the specified package pkg is empty or pkg is a prefix of className, return className. Otherwise return
 824    * className qualified with the pkg prefix.
 825    * @param pkg The package name to use as a prefix.
 826    * @param className The className to qualify.
 827    */
 828  1629 public static String getQualifiedClassName(String pkg, String className) {
 829    // if (className.equals("java")) throw new RuntimeException("BOGUS getQualifiedClassName call on 'java'");
 830  112 if (! pkg.equals("") && ! className.startsWith(pkg)) return pkg + '.' + className;
 831  1517 else return className;
 832    }
 833   
 834    // Creates a continuation for an inner class/interface; qualifiedTypeName is known to exist
 835  0 protected SymbolData addInnerSymbolData(SourceInfo si, String qualifiedTypeName, Data enclosing) {
 836  0 SymbolData sd = makeContinuation(si, qualifiedTypeName); // create continuation
 837  0 SymbolData enclosingSD = enclosing.getSymbolData(); // must exist in symbol table
 838    // if qualifiedTypeName refers to an external inner class, the following will likely fail. TODO: eliminate this
 839  0 enclosing.getSymbolData().addInnerClass(sd);
 840  0 sd.setOuterData(enclosingSD);
 841  0 return sd;
 842    }
 843   
 844    /** This method creates the specified continuation in the symbol table. Assumes qualClassName is fully qualified.
 845    * @param si The SourceInfo corresponding to this occurrence of the class symbol
 846    * @param referencedClassName The referenced name for the class. In some cases, it is fully qualified.
 847    */
 848  44 protected SymbolData makeContinuation(SourceInfo si, String qualClassName) {
 849    // System.err.println("***** makeContinuation called for " + qualClassName);
 850  44 if (qualClassName.equals("D.E")) assert false;
 851  44 SymbolData sd = new SymbolData(qualClassName); // create a continuation
 852  44 symbolTable.put(qualClassName, sd);
 853  44 continuations.put(qualClassName, new Triple<SourceInfo, LanguageLevelVisitor, SymbolData>(si, this, sd));
 854    // System.err.println("Created continuation for " + qualClassName + " at LLV:1124");
 855  44 return sd;
 856    }
 857   
 858    /** Looks up the type with name rt (which is arbitrary source text for a type) from within the class name
 859    * qualifiedClassName. At top level, qualifiedClassName == null. The parameter qualifiedClassName is required
 860    * becaue this method may be called in a fixup. TODO: consolidate with _identifyType. */
 861  224 protected SymbolData _lookupTypeFromWithinClass(ReferenceType rt, String qualifiedClassName) {
 862    // Perform a raw lookup assuming name of rt is fully qualified
 863  224 String rtName = rt.getName();
 864  224 SourceInfo si = rt.getSourceInfo();
 865    // Perform a lookup at top level.
 866  224 assert _importedPackages.contains("java.lang");
 867  224 SymbolData sD = getSymbolData(rtName, si, false);
 868    // if (rtName.equals("Object") && sD == null)
 869    // System.err.println("Looking up 'Object' in '" + qualifiedClassName + "' yields null");
 870  224 if (sD == null && qualifiedClassName != null) { // check if rt refers to an inner type of qualifiedClassName
 871  0 SymbolData sd = getQualifiedSymbolData(qualifiedClassName, SourceInfo.NONE);
 872  0 sD = sd.getInnerClassOrInterface(rtName);
 873  0 assert sD == getQualifiedSymbolData(qualifiedClassName + '.' + rtName, SourceInfo.NONE);
 874    } // The following case should be unncessary because getInnerClassOrInterface should look back through enclosing classes
 875  224 else if (qualifiedClassName != null) {
 876  33 int prefixLen = qualifiedClassName.lastIndexOf('.');
 877  33 if (sD == null && prefixLen >= 0) { // check if rt refers to an inner class of the class enclosing sd
 878    // Check to see if this is an inner class referencing an inner interface
 879  0 String qualifyingBase = qualifiedClassName.substring(0, qualifiedClassName.lastIndexOf('.'));
 880  0 SymbolData outerSD = getQualifiedSymbolData(qualifyingBase, SourceInfo.NONE);
 881  0 if (outerSD != null) {
 882  0 sD = outerSD.getInnerClassOrInterface(rtName);
 883  0 assert sD == getQualifiedSymbolData(qualifyingBase + '.' + rtName, si);
 884    // TODO: expand this search to include interfaces defined in any of the enclosing classes.
 885    }
 886    }
 887    }
 888  224 return sD;
 889    }
 890   
 891    /** Overloaded signature for defineSymbolData. Passes _enclosingClassName for enclosingClassName and
 892    * _classesInThisFile for classesInThisFile */
 893  221 protected SymbolData defineSymbolData(TypeDefBase typeDefBase, final String qualifiedTypeName) {
 894  221 return defineSymbolData(typeDefBase, qualifiedTypeName, _enclosingClassName /*, _classesInThisFile*/ );
 895    }
 896   
 897    /** Given a TypeDefBase (which is either a ClassDef or an InterfaceDef) and the corresponding qualifiedTypeName, this
 898    * method generates a SymbolData, and adds the name and SymbolData pair to the symbol table. It checks that this
 899    * class is not already in the symbol table. This error should never happen for an inner class or interface.
 900    * Assumes that the defined class is top level. If used for inner class definition, the caller must be perform
 901    * any special inner class initialization.
 902    * @param typeDefBase The AST node for the class def, interface def, inner class def, or inner interface def.
 903    * @param qualifiedTypeName The fully qualified name of the class or interface
 904    * @return the defined SymbolData or null if the type has already been defined
 905    */
 906  221 protected SymbolData defineSymbolData(final TypeDefBase typeDefBase, final String qualifiedTypeName,
 907    final String enclosingClassName /*, final HashSet<String> classesInThisFile*/) {
 908  221 assert (typeDefBase instanceof InterfaceDef) || (typeDefBase instanceof ClassDef);
 909  221 assert ! qualifiedTypeName.startsWith("null.");
 910  221 String name = qualifiedTypeName; // may be an interface
 911  221 SymbolData contSd = symbolTable.get(qualifiedTypeName);
 912    // System.err.println("In defineSymbolData call for " + qualifiedTypeName + ", contSd = " + contSd);
 913  221 if (contSd != null && ! contSd.isContinuation()) {
 914  1 _addAndIgnoreError("The class or interface " + name + " has already been defined.", typeDefBase);
 915  1 return null;
 916    }
 917    // If no continuation exists, create a SymbolData for this definition
 918  220 final SymbolData sd = (contSd == null) ? new SymbolData(qualifiedTypeName) : contSd;
 919  220 symbolTable.put(qualifiedTypeName, sd);
 920   
 921    // // Save _enclosingClassName in a final var; may be null if called at the top level, e.g. defining a
 922    // // top level class or interface.
 923    // final String enclosingClassName = _enclosingClassName;
 924   
 925    // Make this SymbolData as a non-continuation
 926  220 sd.setIsContinuation(false);
 927    //Set the package to be the current package
 928  220 sd.setPackage(_package);
 929    // Set the MAV and type parameters (the latter are not used currently)
 930  220 sd.setMav(typeDefBase.getMav());
 931  220 sd.setTypeParameters(typeDefBase.getTypeParameters());
 932   
 933    // Create the LinkedList for the SymbolDatas of the interfaces
 934  220 final ArrayList<SymbolData> interfaces = new ArrayList<SymbolData>();
 935   
 936    // Get or create SymbolDatas for the interfaces
 937  220 ReferenceType[] rts = typeDefBase.getInterfaces();
 938  220 for (int i = 0; i < rts.length; i++) {
 939  13 final ReferenceType rt = rts[i];
 940  13 final String rtName = rt.getName();
 941  13 boolean forwardRef = false;
 942  13 SymbolData iD = _lookupTypeFromWithinClass(rt, enclosingClassName);
 943  13 if (iD != null && ! iD.isContinuation() && ! iD.isInterface()) {
 944  0 _addAndIgnoreError("The symbol " + rtName + " is not an interface", typeDefBase);
 945    }
 946  13 if (iD == null || iD.isContinuation()) { // create a dummy symbol pending fixUp TODO: is this necessary?
 947  7 iD = new SymbolData(rtName);
 948  7 forwardRef = true;
 949    }
 950   
 951  13 interfaces.add(iD);
 952  13 if (forwardRef) {
 953    // create a fixup for this interface slot
 954  7 final int j = i;
 955  7 Command fixUp = new Command() {
 956  7 public void execute() {
 957  7 SymbolData newID = _lookupTypeFromWithinClass(rt, enclosingClassName);
 958  0 if (newID == null) _addAndIgnoreError("The symbol " + rtName + " is not defined", typeDefBase);
 959  7 else if (! newID.isInterface())
 960  0 _addAndIgnoreError("The symbol " + rtName + " is not an interface", typeDefBase);
 961  7 interfaces.set(j, newID);
 962  7 sd.addEnclosingData(newID);
 963    }
 964    };
 965  7 fixUps.add(fixUp);
 966    }
 967    }
 968   
 969    // Set the inferfaces; fixups will be done on the elements of the interface ArrayList, but this does not
 970    // add the found interface to the enclosing data of sd.
 971  220 sd.setInterfaces(interfaces);
 972   
 973    // Create SymbolData variable for superclass
 974  220 SymbolData superSD = null;
 975   
 976    // Get or create the SymbolData for the superclass/interface; setInterface and setSuperClass
 977   
 978  220 if (typeDefBase instanceof InterfaceDef) {
 979    // set Object as the super class of this, so that it will know it implements Object's methods.
 980  24 SymbolData objectSD = getSymbolData("java.lang.Object", typeDefBase.getSourceInfo(), false);
 981  24 sd.setInterface(true);
 982  24 sd.setSuperClass(objectSD);
 983    }
 984   
 985  196 else if (typeDefBase instanceof ClassDef) {
 986  196 sd.setInterface(false);
 987  196 ClassDef cd = (ClassDef) typeDefBase;
 988  196 final ReferenceType rt = cd.getSuperclass();
 989  196 superSD = _lookupTypeFromWithinClass(rt, enclosingClassName);
 990   
 991  188 if (superSD != null) sd.setSuperClass(superSD);
 992    else {
 993  8 Command fixUp = new Command() {
 994  8 public void execute() {
 995  8 SymbolData newSuperSD = _lookupTypeFromWithinClass(rt, enclosingClassName);
 996  8 if (newSuperSD == null)
 997  2 _addAndIgnoreError("The class " + sd + " has an undefined superclass " + rt, typeDefBase);
 998    else // TODO: Does not check that newSuperSD is not an interace
 999  6 sd.setSuperClass(newSuperSD);
 1000    }
 1001    };
 1002  8 fixUps.add(fixUp);
 1003    }
 1004    }
 1005   
 1006   
 1007    // Remove symbol name from continuation table.
 1008  220 _log.log("REMOVING continuation " + qualifiedTypeName);
 1009  220 continuations.remove(qualifiedTypeName);
 1010   
 1011    // Add sd to the list of classes defined in program text; used to generate constructors. TODO: What about Full Java?
 1012  196 if (! sd.isInterface()) { LanguageLevelConverter._newSDs.put(sd, this); }
 1013   
 1014  220 _classesInThisFile.remove(qualifiedTypeName); // a no-op if qualifiedClassName is an inner class
 1015  220 return sd;
 1016    }
 1017   
 1018    /** Takes in a TypeDefBase (which is either an InnerClassDef or an InnerInterfaceDef) and creates a SymbolData for it,
 1019    * either by converting a continuation to it or by creating a new symbol (if no continuationis present).
 1020    * @param typeDefBase The AST node for the class def, interface def, inner class def, or inner interface def.
 1021    * @param relName The relative (unqualified) name of the symbol
 1022    * @param qualifiedTypeName The fully qualified name for the class; null if this definition is a duplicate
 1023    * @param enclosing The enclosing SymbolData or MethodData (for a local class defined within a method).
 1024    */
 1025  38 protected SymbolData defineInnerSymbolData(TypeDefBase typeDefBase, String relName, String qualifiedTypeName,
 1026    Data enclosing) {
 1027  38 assert (enclosing instanceof SymbolData) || (enclosing instanceof MethodData);
 1028    /* IMPORTANT: this is defineSymbolData for inner classes! */
 1029   
 1030  38 SymbolData sd = defineSymbolData(typeDefBase, qualifiedTypeName /*, _classesInThisFile*/);
 1031    // if (sd == null) System.err.println("defineSymbolData failed for " + qualifiedTypeName);
 1032  38 assert sd != null;
 1033    // Set fields of sd that are required for innerSymbols
 1034   
 1035  38 sd.setOuterData(enclosing);
 1036   
 1037  38 if (sd.isInterface()) {
 1038    // assert enclosing instanceof SymbolData;
 1039    // assert enclosing.getName().equals(_enclosingClassName):
 1040  7 ((SymbolData) enclosing).addInnerInterface(sd);
 1041    }
 1042  31 else if (! enclosing.getName().equals(_enclosingClassName)) {
 1043    // sd is a local class embedded in a method. We need to add sd to the innerclasses of _enclosingClassName
 1044    // if (! (enclosing instanceof MethodData))
 1045    // System.err.println("***** In defineInnerSymbolData, enclosing = " + enclosing
 1046    // + " but _enclosingClassName = " + _enclosingClassName);
 1047  9 assert enclosing instanceof MethodData;
 1048  9 SymbolData enclosingClassSD = getQualifiedSymbolData(_enclosingClassName);
 1049  9 assert enclosingClassSD != null;
 1050  9 enclosingClassSD.addInnerClass(sd);
 1051  9 enclosing.addInnerClass(sd); // adds innerClass to list for the enclosing MethodData
 1052    }
 1053    else {
 1054    // sd is a non-local inner class
 1055  22 assert enclosing.getName().equals(_enclosingClassName);
 1056  22 enclosing.addInnerClass(sd);
 1057    // _innerClassesInThisBody.remove(sd); // a no-op if _innerClassesInThisBody is empty
 1058    }
 1059  38 return sd;
 1060    }
 1061   
 1062    /** This method takes in an AnonymousClassInstantion, generates a SymbolData for it, and
 1063    * adds the name and SymbolData pair to the symbol table.
 1064    * @param AnonymousClassInstantiation The AST node for the anonymous class instantiation.
 1065    * @param qualifiedTypeName The fully qualified name of the class
 1066    */
 1067  5 protected SymbolData defineAnonymousSymbolData(final AnonymousClassInstantiation anonInst,
 1068    final String qualifiedAnonName,
 1069    final String superName) {
 1070    // Generated name cannot be in symbolTable
 1071    // System.err.println("defineAnonymousSymbolData called for " + qualifiedAnonName + " extending " + superName);
 1072   
 1073  5 final SourceInfo si = anonInst.getSourceInfo();
 1074    // Create a SymbolData for this definition
 1075  5 final SymbolData sd = new SymbolData(qualifiedAnonName);
 1076  5 symbolTable.put(qualifiedAnonName, sd);
 1077   
 1078    // Make this SymbolData as a non-continuation
 1079  5 sd.setIsContinuation(false);
 1080    //Set the package to be the current package
 1081  5 sd.setPackage(_package);
 1082   
 1083    // sd.setMav(anonInst.getMav()); // What is Mav for anonymous class?
 1084    // sd.setTypeParameters(anonInst.getTypeParameters());
 1085   
 1086  5 if (_enclosingClassName != null) {
 1087  5 SymbolData enclosingSD = getQualifiedSymbolData(_enclosingClassName, SourceInfo.NONE);
 1088  5 assert (enclosingSD != null);
 1089  5 enclosingSD.addInnerClass(sd);
 1090   
 1091    // if (enclosingSD.getName().equals("HasAnonymousInnerClass"))
 1092    // System.err.println("****** The SymbolData for " + sd + " added to the inner classes of " + enclosingSD);
 1093   
 1094    // Set fields of sd that are required for innerSymbols
 1095  5 sd.setOuterData(enclosingSD);
 1096   
 1097    }
 1098   
 1099  5 SymbolData superSD = getSymbolData(superName, anonInst.getSourceInfo());
 1100   
 1101  5 if (superSD != null) {
 1102  4 if (superSD.isInterface()) {
 1103  0 sd.setSuperClass(getQualifiedSymbolData("java.lang.Object", si));
 1104  0 sd.setInterfaces(new ArrayList<SymbolData>(Arrays.asList(new SymbolData[] { superSD })));
 1105    }
 1106  4 else sd.setSuperClass(superSD); // By default sd.getInterfaces() == new ArrayList<SymbolData>()
 1107    }
 1108    else {
 1109    // Create a fixup
 1110  1 Command fixUp = new Command() {
 1111  0 public void execute() {
 1112  0 SymbolData superSD = getSymbolData(superName, si);
 1113  0 if (superSD == null)
 1114  0 _addAndIgnoreError("The class/interface " + superName + " was not found.", anonInst);
 1115  0 else if (superSD.isInterface()) {
 1116  0 sd.setSuperClass(getQualifiedSymbolData("java.lang.Object", si));
 1117  0 sd.setInterfaces(new ArrayList<SymbolData>(Arrays.asList(new SymbolData[] { superSD })));
 1118    }
 1119  0 else sd.setSuperClass(superSD); // By default sd.getInterfaces() == new ArrayList<SymbolData>()
 1120    }
 1121    };
 1122  1 fixUps.add(fixUp);
 1123    }
 1124  5 return sd;
 1125    }
 1126   
 1127    /** This method is factored out of formalParameters2VariableData so it can be overridden in FullJavaVisitor.
 1128    * @return the formal parameter mav appropriate for the language level; "Functional level" is default. */
 1129  163 protected String[] getFormalParameterMav(Data d) { return new String[] {"final"}; }
 1130   
 1131    /** Convert the specified array of FormalParameters into an array of VariableDatas which is then returned.
 1132    * All formal parameters are automatically made final.
 1133    * @param fps The AST node for the parameter list
 1134    * @param enclosing The SymbolData for the enclosing class (not method!)
 1135    * NOTE: enclosing refers to the enclosing class rather than enclosing method because any new types
 1136    * defined in the method are not visible in the parameter list.
 1137    * TODO: At the advanced level, this may need to be overwritten?
 1138    */
 1139  234 protected VariableData[] formalParameters2VariableData(FormalParameter[] fps, SymbolData enclosing) {
 1140  234 assert enclosing != null /* && (enclosing instanceof SymbolData || enclosing instanceof BlockData)*/;
 1141    // BodyData ::= MethodData | BlockData
 1142   
 1143    // Utilities.show("formalParameters2VariableData called on " + fps);
 1144    // Should consolidate with same method in FullJavadVisitor; almost identical
 1145  234 final VariableData[] varData = new VariableData[fps.length];
 1146  234 final String enclosingClassName = enclosing.getName();
 1147   
 1148  234 String[] mav = getFormalParameterMav(enclosing);
 1149   
 1150  234 for (int i = 0; i < fps.length; i++) {
 1151  95 VariableDeclarator vd = fps[i].getDeclarator();
 1152  95 String name = vd.getName().getText(); // getName returns a Word
 1153   
 1154  95 Type type = vd.getType();
 1155  95 final String typeName = type.getName();
 1156    // if (name.equals("myArray"))
 1157    // System.err.println("*** 2Var called for var " + name + " type = " + typeName);
 1158  95 final SourceInfo si = type.getSourceInfo();
 1159    // Note: typeName CANNOT be a local type; no such type is in scope
 1160  95 SymbolData sd = _identifyType(typeName, si, enclosingClassName);
 1161   
 1162  95 varData[i] =
 1163    new VariableData(name, new ModifiersAndVisibility(SourceInfo.NONE, mav), sd, true, enclosing);
 1164   
 1165  95 assert ! varData[i].isPrivate();
 1166   
 1167  95 if (sd == null || sd == SymbolData.NOT_FOUND) { // a forward Type reference
 1168    // To establish a reference to a not-yet-defined type, create a fixup
 1169  1 final int j = i;
 1170    /* The following is a kludge to make method signature collision detection work (unless different
 1171    * names are used for the same type). */
 1172  1 varData[j].setType(new SymbolData(typeName));
 1173  1 Command fixUp = new Command() {
 1174  1 public void execute() {
 1175  1 SymbolData newSd = _identifyType(typeName, si, enclosingClassName);
 1176  1 if (newSd == null || newSd == SymbolData.NOT_FOUND)
 1177  0 System.err.println("****** In fixUp, the type " + typeName + " at " + si + " was NOT found.");
 1178    // assert newSd != null && newSd != SymbolData.NOT_FOUND; // TODO !!!: Expand to error message?
 1179  1 if (newSd != null) varData[j].setType(newSd);
 1180    }
 1181    };
 1182  1 fixUps.add(fixUp);
 1183    }
 1184   
 1185    // System.err.println("For inner class/interface " + typeName + " found type " + type);
 1186  95 varData[i].gotValue();
 1187  95 varData[i].setIsLocalVariable(true);
 1188    }
 1189  234 return varData;
 1190    }
 1191   
 1192    // /** Identifies the SymbolData in symbolTable matching typeName. Returns null if no match is
 1193    // * found. Searches for typeName as a fully qualified Name and as a relative name within
 1194    // * the current class. TODO: match inner classes of classes enclosing the current class. */
 1195    // private SymbolData _identifyVarType(String typeName, SourceInfo si) {
 1196    // SymbolData sd = getSymbolData(typeName, si);
 1197    // if (sd != null) return sd;
 1198    // SymbolData enclosingSD = getQualifiedSymbolData(_enclosingClassName, SourceInfo.NONE);
 1199    // assert enclosingSD != null;
 1200    // return _enclosingClass.getInnerClassOrInterface(typeName);
 1201    // // TODO: fails for nested inner classes
 1202    // }
 1203   
 1204    /** Looks up the return type of a method. */
 1205  0 private SymbolData _lookupReturnString(String rtString, SourceInfo si) {
 1206  0 return rtString.equals("void") ? SymbolData.VOID_TYPE : getSymbolData(rtString, si);
 1207    }
 1208   
 1209    /** Creates a MethodData corresponding to the MethodDef within the context of the SymbolData sd. */
 1210  190 protected MethodData createMethodData(final MethodDef that, final SymbolData sd) {
 1211   
 1212  190 assert _enclosingClassName != null && getQualifiedSymbolData(_enclosingClassName).equals(sd);
 1213   
 1214    // _log.log("createMethodData(" + that + ", " + sd + ") called.");
 1215    // System.err.println("createMethodData(" + that.getName().getText() + ", " + sd + ") called.");
 1216    // System.err.println("_enclosingClassName = " + _enclosingClassName);
 1217  190 that.getMav().visit(this);
 1218  190 that.getName().visit(this);
 1219   
 1220    // Turn the thrown exceptions from a ReferenceType[] to a String[]
 1221  190 String[] throwStrings = referenceType2String(that.getThrows());
 1222   
 1223  190 final String rtString = that.getResult().getName();
 1224   
 1225    // Identify the return type
 1226  190 final SourceInfo si = that.getResult().getSourceInfo();
 1227    // if (! sd.equals(getQualifiedSymbolData(_enclosingClassName, SourceInfo.NONE))) {
 1228    // System.err.println("sd = " + sd);
 1229    // System.err.println("other = " + getQualifiedSymbolData(_enclosingClassName, SourceInfo.NONE));
 1230    // assert false;
 1231    // }
 1232    // Note: rtString cannot be a local type; no such type is in scope. BUT it can be a type variable or
 1233    // a forward reference.
 1234  190 SymbolData returnType = _identifyType(rtString, si, _enclosingClassName);
 1235   
 1236  190 final String name = that.getName().getText();
 1237    // System.err.println("Creating MethodData for " + name + " in type " + sd);
 1238  190 final MethodData md =
 1239    MethodData.make(name, that.getMav(), that.getTypeParams(), returnType, null, throwStrings, sd, that);
 1240  190 VariableData[] vds = formalParameters2VariableData(that.getParams(), sd);
 1241   
 1242  190 if (returnType == null) {
 1243    // System.err.println("Creating return type fixup for " + rtString + " in method " + name + " in class " + sd);
 1244  10 final String enclosingClassName = _enclosingClassName;
 1245  10 Command fixUp = new Command() {
 1246  10 public void execute() {
 1247  10 SymbolData newReturnType = _identifyType(rtString, si, enclosingClassName);
 1248  10 if (newReturnType == null && (! (LanguageLevelVisitor.this instanceof FullJavaVisitor))) {
 1249  1 _addAndIgnoreError("The return type " + rtString + " for method " + name + " in type " + sd + " is undefined.",
 1250    that);
 1251    // System.err.println("The return type " + rtString + " for method " + name + " in type " + sd + " is undefined.");
 1252    // assert false;
 1253    }
 1254    else {
 1255    // System.err.println("FixUp set the returnType of " + name + "in type " + sd + " to " + newReturnType);
 1256  9 md.setReturnType(newReturnType);
 1257    }
 1258    }
 1259    };
 1260  10 fixUps.add(fixUp);
 1261    }
 1262   
 1263    // System.err.println("Called createMethodData(" + name + ", " + sd.getName() + ")");
 1264    // _log.log("createMethodData called. Created MethodData " + md + '\n' + "with modifiers:" + md.getMav());
 1265    // Turn the parameters from a FormalParameterList to a VariableData[]
 1266   
 1267   
 1268  190 if (_checkError()) { //if there was an error converting the formalParameters, don't use them.
 1269  0 return md;
 1270    }
 1271   
 1272  190 md.setParams(vds);
 1273   
 1274    // Adds the formal parameters to the list of vars defined in this method.
 1275  190 if (! md.addVars(vds)) { //TODO: should this not have been changed from addFinalVars?
 1276  2 _addAndIgnoreError("You cannot have two method parameters with the same name", that);
 1277    }
 1278  190 return md;
 1279    }
 1280   
 1281    /** Generates a brief print string for a VariableDeclarator. */
 1282  0 private static String declaratorsToString(VariableDeclarator[] vds) {
 1283  0 StringBuilder printString = new StringBuilder("{ ");
 1284  0 for (VariableDeclarator vd: vds) {
 1285  0 printString.append(vd.getName().getText()).append(": ").append(vd.getType().getName()).append("; ");
 1286    }
 1287  0 return printString.append('}').toString();
 1288    }
 1289   
 1290    /** This method assumes that the modifiers for this particular VariableDeclaration have already been checked. It
 1291    * does no semantic checking. It simply converts the declarators to variable datas, by trying to resolve the types
 1292    * of each declarator. The VariableDeclaration may be a field declaration! The Data enclosing may be a MethodData!
 1293    */
 1294  177 protected VariableData[] _variableDeclaration2VariableData(VariableDeclaration vd, final Data enclosing) {
 1295  177 assert enclosing != null;
 1296    // System.err.println("*** 2Var called for \n" + declaratorsToString(vd.getDeclarators()) + "\nin " + enclosing);
 1297  177 LinkedList<VariableData> vds = new LinkedList<VariableData>();
 1298  177 ModifiersAndVisibility mav = vd.getMav();
 1299  177 VariableDeclarator[] declarators = vd.getDeclarators();
 1300  177 for (final VariableDeclarator declarator: declarators) {
 1301  192 declarator.visit(this); // Does NOTHING!
 1302  192 final Type type = declarator.getType();
 1303  192 final String name = declarator.getName().getText();
 1304  192 final String typeName = type.getName();
 1305    // assert enclosing == getQualifiedSymbolData(_enclosingClassName, SourceInfo.NONE);
 1306    // TODO: if enclosing is a MethodData, we should first look for a local class!!! This search will always
 1307    // succeed if a matching local class exists because no forward reference is possible. (Confirm this!) !!!
 1308    /* TODO: do we need to worry about case when enclosing is a MethodData? Yes. defineInnerSymbolData
 1309    * already treats local classes specially, but it doesn't help. References to local types use relative
 1310    * class names. */
 1311  192 SymbolData sd = _identifyType(typeName, declarator.getSourceInfo(), _enclosingClassName); // may be null
 1312  192 boolean initialized = declarator instanceof InitializedVariableDeclarator;
 1313    // want hasBeenAssigned to be true if this variable declaration is initialized, and false otherwise.
 1314    // System.err.println("Creating new VariableData " + name + " : " + typeName + " within " + _enclosingClassName);
 1315  192 final VariableData vdata = new VariableData(name, mav, sd, initialized, enclosing);
 1316  192 vdata.setHasInitializer(initialized);
 1317    // vdata.setIsLocalVariable(true);
 1318  192 vds.addLast(vdata);
 1319    // System.err.println("identifyReturnType(" + type + ", " + name + ", " + enclosing + ") returned null");
 1320  192 if (sd == null) { // TODO !!! Can this really happen?
 1321    // Create fixup
 1322  7 final String enclosingName = _enclosingClassName; // Grab the current enclosing class name
 1323    // System.err.println("**** Creating fixup for preceding VariableData");
 1324  7 Command fixup = new Command() {
 1325  6 public void execute() {
 1326    // System.err.println("**** Executing fixup for " + typeName + " within " + enclosingName);
 1327  6 SymbolData newSd = _identifyType(typeName, declarator.getSourceInfo(), enclosingName);
 1328  4 if (newSd != null) vdata.setType(newSd);
 1329  2 else if (! (LanguageLevelVisitor.this instanceof FullJavaVisitor) ) // TODO: fix this kludge!!!
 1330  2 _addAndIgnoreError("Class or Interface " + typeName + " not found", type);
 1331    }
 1332    };
 1333  7 fixUps.add(fixup);
 1334    }
 1335    }
 1336    // System.err.println("Returning VariableDatas " + vds);
 1337  177 return vds.toArray(new VariableData[vds.size()]);
 1338    }
 1339   
 1340    /** Identifies the SymbolData matching name in symbolTable. Returns null if no match is found. Searches for typeName
 1341    * as a fully qualified Name and as a relative name within the enclosing class. enclosingClassName is null if type
 1342    * is part of the header for a class or interface. Methods can introduce local types. Make sure that we can match
 1343    * inner classes of the chain of enclosing datas. We need to use the relative inner class name to do this. */
 1344  494 protected SymbolData _identifyType(String name, SourceInfo si, String enclosingClassName) {
 1345    // System.err.println("***** Calling _identifyType(" + name + ") within " + enclosingClassName);
 1346   
 1347    // If name is a type variable, return the binding
 1348  0 if (_genericTypes.containsKey(name)) return _genericTypes.get(name);
 1349   
 1350  494 SymbolData sd = getSymbolData(name, si); // TODO: uses wrong enclosingClassName!!!
 1351  473 if (sd != null) return sd;
 1352   
 1353    // if (name.equals("ResType") && sd == null)
 1354    // Utilities.show("_genericTypes = " + _genericTypes + "Trace follows.\n" + Utilities.getStackTrace());
 1355   
 1356    // if (enclosingClassName == null) Utilities.show("_identifyType called with null enclosingClassName. Trace follows.\n" +
 1357    // Utilities.getStackTrace());
 1358   
 1359    // System.err.println("***ERROR*** in _identifyType " + enclosingClassName + " NOT FOUND");
 1360  0 if (enclosingClassName == null) return null; // happens for binding occurrences of type variables?
 1361   
 1362  21 SymbolData enclosingSD = getQualifiedSymbolData(enclosingClassName, SourceInfo.NONE);
 1363  1 if (enclosingSD == null) return null;
 1364   
 1365  20 sd = enclosingSD.getInnerClassOrInterface(name);
 1366   
 1367    // // Create continuation for new type
 1368    // String qualifiedTypeName = enclosingClassName + '.' + name;
 1369    // if (_innerClassesInThisBody.contains(qualifiedTypeName)) {
 1370    // // reference to an inner class that will subsequently be defined
 1371    // sd = addInnerSymbolData(si, qualifiedTypeName, enclosingSD);
 1372    // }
 1373   
 1374    // System.err.println("***** _identifyType(" + name + ") within " + enclosingClassName + " RETURNED " + sd);
 1375  20 return sd; // Note: sd is null if name is not identified.
 1376    }
 1377   
 1378    /** This method is called when an error should be added to the static LinkedList of errors.
 1379    * This version is called from the DoFirst methods in the LanguageLevelVisitors to halt
 1380    * parsing of the construct.
 1381    */
 1382  26 protected static void _addError(String message, JExpressionIF that) {
 1383    // Utilities.show("_addError(" + message + ", " + that + ") called");
 1384  26 _errorAdded = true;
 1385  26 Pair<String, JExpressionIF> p = new Pair<String, JExpressionIF>(message, that);
 1386  25 if (! errors.contains(p)) errors.addLast(p);
 1387    }
 1388   
 1389    /** This method is called when an error should be added, but tree-walking should continue
 1390    * on this construct. Generally, if the error is not added in the DoFirst, the _errorAdded
 1391    * flag is not checked anyway, so this version should be called.
 1392    */
 1393  71 protected static void _addAndIgnoreError(String message, JExpressionIF that) {
 1394    // Utilities.show("_addAndIgnoreError(" + message + ", " + that + ") called");
 1395  71 if (_errorAdded) {
 1396  1 throw new RuntimeException("Internal Program Error: _addAndIgnoreError called while _errorAdded was true." +
 1397    " Please report this bug.");
 1398    }
 1399  70 _errorAdded = false;
 1400  70 Pair<String, JExpressionIF> newMsg = new Pair<String, JExpressionIF>(message, that);
 1401  69 if (! errors.contains(newMsg)) errors.addLast(newMsg);
 1402    // else System.err.println("Suppressing error as duplicate: " + newMsg);
 1403    }
 1404   
 1405  4142 protected boolean prune(JExpressionIF node) { return _checkError(); }
 1406   
 1407    /** If _errorAdded is true, set it back to false and return true.
 1408    * This will cause the current construct to be skipped, but will allow this first pass
 1409    * to otherwise continue unimpeded.
 1410    * Otherwise, return false, which will allow this first pass to continue normally.
 1411    */
 1412  4426 protected static boolean _checkError() {
 1413  4426 if (_errorAdded) {
 1414  24 _errorAdded = false;
 1415  24 return true;
 1416    }
 1417  4402 else return false;
 1418    }
 1419   
 1420    /** Add an error explaining the modifiers' conflict. */
 1421  7 public void _badModifiers(String first, String second, JExpressionIF that) {
 1422  7 _addError("Illegal combination of modifiers. Can't use " + first + " and " + second + " together.", that);
 1423    }
 1424   
 1425    /** Check for problems with modifiers that are common to all language levels: duplicate modifiers and illegal
 1426    * combinations of modifiers.
 1427    */
 1428  650 public Void forModifiersAndVisibilityDoFirst(ModifiersAndVisibility that) {
 1429  650 String[] modifiersAndVisibility = that.getModifiers();
 1430  650 Arrays.sort(modifiersAndVisibility);
 1431  650 if (modifiersAndVisibility.length > 0) {
 1432  185 String s = modifiersAndVisibility[0];
 1433    // check for duplicate modifiers
 1434  185 for (int i = 1; i < modifiersAndVisibility.length; i++) {
 1435  14 if (s.equals(modifiersAndVisibility[i])) {
 1436  1 _addError("Duplicate modifier: " + s, that);
 1437    }
 1438  14 s = modifiersAndVisibility[i];
 1439    }
 1440   
 1441    // check for illegal combination of modifiers
 1442  185 String visibility = "package";
 1443  185 boolean isAbstract = false;
 1444  185 boolean isStatic = false;
 1445  185 boolean isFinal = false;
 1446  185 boolean isSynchronized = false;
 1447  185 boolean isStrictfp = false;
 1448  185 boolean isTransient = false;
 1449  185 boolean isVolatile = false;
 1450  185 boolean isNative = false;
 1451  185 for (int i = 0; i < modifiersAndVisibility.length; i++) {
 1452  199 s = modifiersAndVisibility[i];
 1453  199 if (s.equals("public") || s.equals("protected") || s.equals("private")) {
 1454  1 if (! visibility.equals("package")) _badModifiers(visibility, s, that);
 1455  1 else if (s.equals("private") && isAbstract) _badModifiers("private", "abstract", that);
 1456  118 else visibility = s;
 1457    }
 1458  35 else if (s.equals("abstract")) isAbstract = true;
 1459  44 else if (s.equals("final")) {
 1460  15 isFinal = true;
 1461  2 if (isAbstract) _badModifiers("final", "abstract", that);
 1462    }
 1463  29 else if (s.equals("native")) {
 1464  1 isNative = true;
 1465  0 if (isAbstract) _badModifiers("native", "abstract", that);
 1466    }
 1467  28 else if (s.equals("synchronized")) {
 1468  1 isSynchronized = true;
 1469  0 if (isAbstract) _badModifiers("synchronized", "abstract", that);
 1470    }
 1471  27 else if (s.equals("volatile")) {
 1472  4 isVolatile = true;
 1473  2 if (isFinal) _badModifiers("final", "volatile", that);
 1474    }
 1475    }
 1476  185 return forJExpressionDoFirst(that); // Does nothing!
 1477    }
 1478  465 return null;
 1479    }
 1480   
 1481    /** Check for problems in ClassDefs. Make sure that the top level class is
 1482    * not private, and that the class name has not already been imported.
 1483    */
 1484  209 public Void forClassDefDoFirst(ClassDef that) {
 1485  209 String name = that.getName().getText(); // name of defined class
 1486  209 Iterator<String> iter = _importedFiles.iterator();
 1487  209 while (iter.hasNext()) {
 1488  14 String s = iter.next();
 1489  14 if (s.endsWith(name) && ! s.equals(getQualifiedClassName(name))) { // TODO: this test is too coarse!
 1490  1 _addAndIgnoreError("The class " + name + " was already imported.", that);
 1491    }
 1492    }
 1493   
 1494    // top level classes cannot be private.
 1495  209 String[] mavStrings = that.getMav().getModifiers();
 1496  209 if (! (that instanceof InnerClassDef)) {
 1497  177 for (int i = 0; i < mavStrings.length; i++) {
 1498  34 if (mavStrings[i].equals("private")) {
 1499  1 _addAndIgnoreError("Top level classes cannot be private", that);
 1500    }
 1501    }
 1502    }
 1503   
 1504    // See if this is a Blacklisted class. Blacklisted classes are any classes in java.lang or TestCase.
 1505  209 SymbolData javaLangClass =
 1506    getQualifiedSymbolData("java.lang." + that.getName().getText(), that.getSourceInfo(), false, false, false);
 1507  209 if (that.getName().getText().equals("TestCase") || (javaLangClass != null && ! javaLangClass.isContinuation())) {
 1508  2 _addError("You cannot define a class with the name " + that.getName().getText() +
 1509    " because that class name is reserved." +
 1510    " Please choose a different name for this class", that);
 1511    }
 1512  209 return forTypeDefBaseDoFirst(that);
 1513    }
 1514   
 1515    /** Check for problems with InterfaceDefs: specifically, top level interfaces cannot be private or final. */
 1516  22 public Void forInterfaceDefDoFirst(InterfaceDef that) {
 1517    //top level interfaces cannot be private or final.
 1518  22 String[] mavStrings = that.getMav().getModifiers();
 1519  22 for (int i = 0; i < mavStrings.length; i++) {
 1520  11 if (mavStrings[i].equals("private")) {
 1521  1 _addAndIgnoreError("Top level interfaces cannot be private", that);
 1522    }
 1523  11 if (mavStrings[i].equals("final")) {
 1524  1 _addAndIgnoreError("Interfaces cannot be final", that);
 1525    }
 1526    }
 1527  22 return forTypeDefBaseDoFirst(that);
 1528    }
 1529   
 1530    /** Check for problems with InnerInterfaceDefs that are common to all language levels: specifically, they cannot be
 1531    * final.
 1532    */
 1533  10 public Void forInnerInterfaceDefDoFirst(InnerInterfaceDef that) {
 1534  10 String[] mavStrings = that.getMav().getModifiers();
 1535  10 for (int i = 0; i < mavStrings.length; i++) {
 1536  3 if (mavStrings[i].equals("final")) {
 1537  1 _addAndIgnoreError("Interfaces cannot be final", that);
 1538    }
 1539    }
 1540  10 return forTypeDefBaseDoFirst(that);
 1541    }
 1542   
 1543    /** Do the common work for SimpleAnonymousClassInstantiations and ComplexAnonymousClassInstantiations
 1544    * and in FullJava and Functional Java.
 1545    * @param that The AnonymousClassInstantiation being visited.
 1546    * @param enclosing The SymbolData of the enclosing class.
 1547    * @param superC The super class being instantiated--i.e. new A() { ...}, would have a super class of A.
 1548    */
 1549  5 public void anonymousClassInstantiationHelper(AnonymousClassInstantiation that, SymbolData enclosing, String superName) {
 1550  5 that.getArguments().visit(this);
 1551  5 SymbolData enclosingSD = enclosing.getSymbolData();
 1552  5 String enclosingSDName = enclosingSD.getName();
 1553  5 assert enclosingSDName.equals(_enclosingClassName);
 1554  5 String anonName = getQualifiedClassName(enclosingSDName) + "$" + enclosingSD.preincrementAnonymousInnerClassNum();
 1555   
 1556    // System.err.println("****** In anonymousCIH the anonName = " + anonName + " superName = " + superName
 1557    // + " enclosing = " + enclosing);
 1558   
 1559    // Define the SymbolData that will correspond to this anonymous class
 1560  5 SymbolData anonSD = defineAnonymousSymbolData(that, anonName, superName);
 1561   
 1562    // if (this instanceof IntermediateVisitor) {
 1563    // These methods are no-ops in FullJavaVisitor
 1564  5 createToString(anonSD);
 1565  5 createHashCode(anonSD);
 1566  5 createEquals(anonSD);
 1567    // Accessors will be filled in in typeChecker pass
 1568    // }
 1569   
 1570    // Visit the body (with the appropritate class body visitor to get it all nice and resolved.
 1571    // System.err.println("Calling appropriate class body visitor for " + anonName);
 1572  5 that.getBody().visit(newClassBodyVisitor(anonSD, anonName));
 1573    }
 1574   
 1575    /** Processes the class body that. */
 1576  214 protected void identifyInnerClasses(TypeDefBase that) {
 1577  214 String prefix = _enclosingClassName == null ? "" : _enclosingClassName + '.';
 1578  214 String enclosingType = getQualifiedClassName(prefix + that.getName().getText());
 1579    // System.err.println("***** identifyInnerClasses called for " + enclosingType + " in file " + _file);
 1580  214 assert enclosingType != null;
 1581    // Process the members of this class
 1582    // System.err.println("Finding inner classes in " + enclosingType);
 1583  214 SymbolData sd = getSymbolData(enclosingType, SourceInfo.NONE);
 1584    // System.err.println("SymbolData for " + enclosingType + " is " + sd);
 1585  214 enclosingType = sd.getName(); // that may be a local class, which has a more elaborate name
 1586  214 BracedBody body = that.getBody();
 1587  214 for (BodyItemI bi: body.getStatements()) {
 1588  337 if (bi instanceof TypeDefBase) {
 1589  25 TypeDefBase type = (TypeDefBase) bi;
 1590  25 String rawClassName = type.getName().getText();
 1591    // System.err.println("Adding " + rawClassName + " to inner classes of " + enclosingType + "\n");
 1592  25 String fullClassName = enclosingType + '.' + rawClassName;
 1593    // System.err.println("Adding " + rawClassName + " to _innerClassesInThisBody inside " + that + "\n");
 1594   
 1595    // _innerClassesInThisBody.add(fullClassName);
 1596    // System.err.println("***** Making continuation for " + fullClassName + " in file " + _file);
 1597  25 SymbolData innerSD = makeContinuation(bi.getSourceInfo(), fullClassName);
 1598    // System.err.println("***** Continuation " + innerSD + " returned");
 1599    // Utilities.show("***** Continuation " + innerSD + " returned");
 1600  25 sd.addInnerClass(innerSD);
 1601    }
 1602    }
 1603    // System.err.println("_innerClassesInThisBody = " + _innerClassesInThisBody);
 1604    }
 1605   
 1606    /** Process the members/statements of the class body, method body, or ordinary body (e.g. a try body, catch clause
 1607    * body, or compound statement body. This is VERY BAD data design. These various bodies have significantly
 1608    * different meanings. */
 1609    // public Void forBracedBodyDoFirst(BracedBody that) {
 1610    // if (! (this instanceof BodyBodyFullJavaVisitor)) { // full Java method bodies are excluded by this test
 1611    // // Process the members of this class
 1612    // SymbolData sd = getSymbolData(_enclosingClassName, SourceInfo.NONE);
 1613    // for (BodyItemI bi: that.getStatements()) {
 1614    // if (bi instanceof TypeDefBase) {
 1615    // TypeDefBase type = (TypeDefBase) bi;
 1616    // String rawClassName = type.getName().getText();
 1617    // _log.log("Adding " + rawClassName + " to _innerClassesInThisBody inside " + that + "\n");
 1618    // String fullClassName = _enclosingClassName + '.' + rawClassName;
 1619    //// System.err.println("Adding " + rawClassName + " to _innerClassesInThisBody inside " + that + "\n");
 1620    //
 1621    // _innerClassesInThisBody.add(fullClassName);
 1622    // SymbolData innerSD = makeContinuation(bi.getSourceInfo(), fullClassName);
 1623    // sd.addInnerClass(innerSD);
 1624    // }
 1625    // }
 1626    // System.err.println("_innerClassesInThisBody = " + _innerClassesInThisBody);
 1627    // }
 1628    //
 1629    // return super.forBracedBodyDoFirst(that);
 1630    // }
 1631   
 1632    /** This sets the package name field in order to find other classes in the same package. */
 1633  16 public Void forPackageStatementOnly(PackageStatement that) {
 1634  16 CompoundWord cWord = that.getCWord();
 1635  16 Word[] words = cWord.getWords();
 1636  16 String newPackage;
 1637  16 String separator = System.getProperty("file.separator");
 1638  16 if (words.length > 0) {
 1639  15 _package = words[0].getText();
 1640  15 newPackage = _package;
 1641  15 for (int i = 1; i < words.length; i++) {
 1642  7 String temp = words[i].getText();
 1643  7 newPackage = newPackage + separator + temp;
 1644  7 _package = _package + '.' + temp;
 1645    }
 1646  15 String directory = _file.getParent();
 1647  15 if (directory == null || !directory.endsWith(newPackage)) {
 1648  1 _addAndIgnoreError("The package name must mirror your file's directory.", that);
 1649    }
 1650    }
 1651    // Call getSymbolData to see if this is actually a class as well as a Package Name. If it is, an error will be
 1652    // given in the TypeChecking step.
 1653    // If file is a .java file and not compiled, won't find it. This is not consistent with the JLS.
 1654    // if file is a ll file and not compiled, will find it, though this is not consistent with the JLS.
 1655    // getSymbolData(_package, that.getSourceInfo(), false);
 1656  16 return forJExpressionOnly(that);
 1657    }
 1658   
 1659   
 1660    /** Make sure the class being imported has not already been imported.
 1661    * If there are no errors, add it to the list of imported files, and create a continuation for it.
 1662    * The class will be resolved later.
 1663    */
 1664  10 public Void forClassImportStatementOnly(ClassImportStatement that) {
 1665  10 CompoundWord cWord = that.getCWord();
 1666  10 Word[] words = cWord.getWords();
 1667   
 1668    // Make sure that this specific imported class has not already been specifically imported
 1669  10 for (int i = 0; i < _importedFiles.size(); i++) {
 1670  2 String name = _importedFiles.get(i);
 1671  2 int indexOfLastDot = name.lastIndexOf('.');
 1672  2 if (indexOfLastDot != -1 &&
 1673    (words[words.length-1].getText()).equals(name.substring(indexOfLastDot + 1, name.length()))) {
 1674  1 _addAndIgnoreError("The class " + words[words.length-1].getText() + " has already been imported.", that);
 1675  1 return null;
 1676    }
 1677    }
 1678   
 1679  9 StringBuilder nameBuff = new StringBuilder(words[0].getText());
 1680  17 for (int i = 1; i < words.length; i++) {nameBuff.append('.' + words[i].getText());}
 1681   
 1682  9 String qualifiedTypeName = nameBuff.toString();
 1683   
 1684    // // Make sure that this imported class does not duplicate the package. WHY? FIX THIS.
 1685    // // Although this is allowed in full java, we decided to not allow it at any LanguageLevel.
 1686    // int indexOfLastDot = qualifiedTypeName.lastIndexOf('.');
 1687    // if (indexOfLastDot != -1) {
 1688    // if (_package.equals(qualifiedTypeName.substring(0, indexOfLastDot))) {
 1689    // _addAndIgnoreError("You do not need to import " + qualifiedTypeName
 1690    // + ". It is in your package so it is already visible",
 1691    // that);
 1692    // return null;
 1693    // }
 1694    // }
 1695   
 1696    //Now add the class to the list of imported files
 1697  9 _importedFiles.addLast(qualifiedTypeName);
 1698   
 1699    // Create a continuation for imported class if one does not already exist
 1700  9 createImportedSymbolContinuation(qualifiedTypeName, that.getSourceInfo());
 1701  9 return forImportStatementOnly(that);
 1702    }
 1703   
 1704    /** Create a continuation for imported class specified by qualifiedName if one does not already exist. */
 1705  12 protected SymbolData createImportedSymbolContinuation(String qualifiedTypeName, SourceInfo si) {
 1706   
 1707  12 SymbolData sd = symbolTable.get(qualifiedTypeName);
 1708  12 if (sd == null) {
 1709    // Create a continuation for the imported class and put it into the symbol table so
 1710    // that on lookup, we can check imported classes before classes in the same package.
 1711    // System.err.println("Creating continuation for imported class " + temp);
 1712  7 sd = makeContinuation(si, qualifiedTypeName);
 1713    }
 1714  12 return sd;
 1715    }
 1716   
 1717    /**Check to make sure that this package import statement is not trying to import the current pacakge. */
 1718  8 public Void forPackageImportStatementOnly(PackageImportStatement that) {
 1719  8 CompoundWord cWord = that.getCWord();
 1720  8 Word[] words = cWord.getWords();
 1721  8 StringBuilder tempBuff = new StringBuilder(words[0].getText());
 1722  8 for (int i = 1; i < words.length; i++) { tempBuff.append('.' + words[i].getText()); }
 1723  8 String temp = tempBuff.toString();
 1724   
 1725   
 1726    //make sure this imported package does not match the current package
 1727  8 if (_package.equals(temp)) {
 1728  1 _addAndIgnoreError("You do not need to import package " + temp +
 1729    ". It is your package so all public classes in it are already visible.", that);
 1730  1 return null;
 1731    }
 1732   
 1733  7 if (! _importedPackages.contains(temp)) _importedPackages.addLast(temp);
 1734   
 1735  7 return forImportStatementOnly(that);
 1736    }
 1737   
 1738    /** Makes sure that this concrete method def is not declared to be abstract. */
 1739  149 public Void forConcreteMethodDefDoFirst(ConcreteMethodDef that) {
 1740  149 ModifiersAndVisibility mav = that.getMav();
 1741  149 String[] modifiers = mav.getModifiers();
 1742    // Concrete methods can be public, private, protected, or static at the Intermediate (Functional) level.
 1743  149 for (int i = 0; i < modifiers.length; i++) {
 1744  47 if (modifiers[i].equals("abstract")) {
 1745  2 _addError("Methods that have a braced body cannot be declared \"abstract\"", that);
 1746  2 break;
 1747    }
 1748    }
 1749  149 return super.forConcreteMethodDefDoFirst(that);
 1750    }
 1751   
 1752    /** Makes sure that this abstract method def is not declared to be static. */
 1753  43 public Void forAbstractMethodDefDoFirst(AbstractMethodDef that) {
 1754  43 ModifiersAndVisibility mav = that.getMav();
 1755  43 String[] modifiers = mav.getModifiers();
 1756    // Concrete methods can now be public, private, protected at the Intermediate level. They still cannot be static.
 1757  1 if (Utilities.isStatic(modifiers)) _badModifiers("static", "abstract", that);
 1758  43 return super.forAbstractMethodDefDoFirst(that);
 1759    }
 1760   
 1761    /** Bitwise operators are allowed in Full Java */
 1762  3 public Void forShiftAssignmentExpressionDoFirst(ShiftAssignmentExpression that) { return null; }
 1763  3 public Void forBitwiseAssignmentExpressionDoFirst(BitwiseAssignmentExpression that) { return null; }
 1764  0 public Void forBitwiseBinaryExpressionDoFirst(BitwiseBinaryExpression that) { return null; }
 1765  3 public Void forBitwiseOrExpressionDoFirst(BitwiseOrExpression that) { return null; }
 1766  1 public Void forBitwiseXorExpressionDoFirst(BitwiseXorExpression that) { return null; }
 1767  1 public Void forBitwiseAndExpressionDoFirst(BitwiseAndExpression that) { return null; }
 1768  1 public Void forBitwiseNotExpressionDoFirst(BitwiseNotExpression that) { return null; }
 1769  3 public Void forShiftBinaryExpressionDoFirst(ShiftBinaryExpression that) { return null; }
 1770  0 public Void forBitwiseNotExpressionDoFirst(ShiftBinaryExpression that) { return null; }
 1771   
 1772    /** The EmptyExpression is a sign of an error. It means that we were missing something
 1773    * we needed when the parser built the AST*/
 1774  1 public Void forEmptyExpressionDoFirst(EmptyExpression that) {
 1775  1 _addAndIgnoreError("You appear to be missing an expression here", that);
 1776  1 return null;
 1777    }
 1778   
 1779    /** The NoOp expression signifies a missing binary operator that was encountered when the
 1780    * parser built the AST. */
 1781  1 public Void forNoOpExpressionDoFirst(NoOpExpression that) {
 1782  1 _addAndIgnoreError("You are missing a binary operator here", that);
 1783  1 return null;
 1784    }
 1785   
 1786    /** If a ClassDef defined in this source file is a TestCase class, make sure it is the only thing in the file. */
 1787  137 public Void forSourceFileDoFirst(SourceFile that) {
 1788   
 1789  137 for (int i = 0; i < that.getTypes().length; i++) {
 1790  174 if (that.getTypes()[i] instanceof ClassDef) {
 1791  160 ClassDef c = (ClassDef) that.getTypes()[i];
 1792  160 String superName = c.getSuperclass().getName();
 1793  160 if (superName.equals("TestCase") || superName.equals("junit.framework.TestCase")) {
 1794    // TODO; add code to exclude the following test for FullJava files
 1795  5 if (that.getTypes().length > 1) {
 1796  0 _addAndIgnoreError("TestCases must appear in files by themselves in functional code", c);
 1797    }
 1798    }
 1799    }
 1800    }
 1801  137 return null;
 1802    }
 1803   
 1804    /** Check to make sure there aren't any immediate errors in this SourceFile by calling the
 1805    * doFirst method. Then, check to make sure that java.lang is imported, and if it is not, add
 1806    * it to the list of importedpackages, since it is imported by default. Make a list of all classes
 1807    * defined in this file.
 1808    * Then, visit them one by one.
 1809    */
 1810  137 public Void forSourceFile(SourceFile that) {
 1811    // System.err.println("Processing source file " + that.getSourceInfo().getFile());
 1812  137 forSourceFileDoFirst(that); // Confirms that TestCase classes appear alone in files
 1813  0 if (prune(that)) return null;
 1814   
 1815    // The parser enforces that there is either zero or one PackageStatement.
 1816  13 for (int i = 0; i < that.getPackageStatements().length; i++) that.getPackageStatements()[i].visit(this);
 1817  13 for (int i = 0; i < that.getImportStatements().length; i++) that.getImportStatements()[i].visit(this);
 1818  0 if (! _importedPackages.contains("java.lang")) _importedPackages.addFirst("java.lang");
 1819   
 1820  137 TypeDefBase[] types = that.getTypes();
 1821    // store the qualified names of all classes defined in this file in:
 1822  137 _classesInThisFile = new HashSet<String>();
 1823  137 for (int i = 0; i < types.length; i++) {
 1824    // TODO: Add inner classes to this list?
 1825   
 1826  174 String qualifiedClassName = getQualifiedClassName(types[i].getName().getText());
 1827  174 _classesInThisFile.add(qualifiedClassName);
 1828    // System.err.println("Adding " + qualifiedClassName + " to _classesInThisFile");
 1829  174 _log.log("Adding " + qualifiedClassName + " to _classesInThisFile");
 1830    }
 1831   
 1832  137 for (int i = 0; i < types.length; i++) {
 1833    // Remove the class that is about to be visited from the list of ClassDefs in this file.
 1834  174 String qualifiedClassName = getQualifiedClassName(types[i].getName().getText());
 1835    // Only visit a class if _classesInThisFile contains it. Otherwise, this class has
 1836    // already been processed since it was a superclass of a previous class.
 1837  174 if (_classesInThisFile.contains(qualifiedClassName)) {
 1838  174 types[i].visit(this);
 1839    }
 1840    }
 1841   
 1842  137 return forSourceFileOnly(that);
 1843    }
 1844   
 1845    /** Call the ResolveNameVisitor to see if this is a reference to a Type name. */
 1846  185 public Void forSimpleNameReference(SimpleNameReference that) {
 1847  185 that.visit(new ResolveNameVisitor());
 1848  185 return null;
 1849    }
 1850   
 1851    /** Call the ResolveNameVisitor to see if this is a reference to a Type name. */
 1852  20 public Void forComplexNameReference(ComplexNameReference that) {
 1853  20 that.visit(new ResolveNameVisitor());
 1854  20 return null;
 1855    }
 1856   
 1857    /** Do nothing. This is handled in the forVariableDeclarationOnly case.*/
 1858  175 public Void forVariableDeclaration(VariableDeclaration that) {
 1859    // System.err.println("forVariableDeclaration in LLV called for " + that);
 1860  175 forVariableDeclarationDoFirst(that);
 1861   
 1862  1 if (prune(that)) return null;
 1863    // System.err.println("forVariableDeclarationDoFirst(...) completed with no errors");
 1864  174 that.getMav().visit(this);
 1865    // System.err.println("Mav visit completed in forVariableDeclaration; getClass() = " + getClass());
 1866  174 return forVariableDeclarationOnly(that);
 1867    }
 1868   
 1869    /** If the method being generated already exists in the SymbolData,
 1870    * throw an error, because generated methods cannot be overwritten.
 1871    */
 1872  599 protected static void addGeneratedMethod(SymbolData sd, MethodData md) {
 1873  599 MethodData rmd = SymbolData.repeatedSignature(sd.getMethods(), md);
 1874  599 if (rmd == null) {
 1875  589 sd.addMethod(md, true);
 1876  589 md.setGenerated(true);
 1877    }
 1878   
 1879  10 else if (!(getUnqualifiedClassName(sd.getName()).equals(md.getName()))) {
 1880    //if it is not a constructor, it cannot be overridden--give an error
 1881  1 _addAndIgnoreError("The method " + md.getName() + " is automatically generated, and thus you cannot override it",
 1882    rmd.getJExpression());
 1883    }
 1884    }
 1885   
 1886    /** Creates the automatically generated constructor for this class. It needs to take in the same arguments as its
 1887    * super class' constructor as well as its fields. If there are multiple constructors in the super class, pick the
 1888    * one with the least number of parameters. No constructor is created if this is an advanced level file (overridden
 1889    * at advanced level), because no code augmentation is done.
 1890    */
 1891  111 public void createConstructor(SymbolData sd) {
 1892  0 if (LanguageLevelConverter.isAdvancedFile(_file)) return;
 1893   
 1894    // System.err.println("**** createConstructor called for " + sd);
 1895   
 1896    // if (sd == null) {
 1897    // System.err.println("**** Error **** After fixups, SymbolData " + sd + " has null for a super class");
 1898    // assert false;
 1899    // }
 1900    //
 1901  111 if (sd.isContinuation()) {
 1902  0 _addAndIgnoreError("Could not generate constructor for class " + sd + " because it has no definition",
 1903    new NullLiteral(SourceInfo.NONE));
 1904  0 return;
 1905    }
 1906   
 1907  111 SymbolData superSd = sd.getSuperClass();
 1908  111 if (superSd == null) {
 1909  2 _addAndIgnoreError("Could not generate constructor for class " + sd + " because it has no superclass",
 1910    new NullLiteral(SourceInfo.NONE));
 1911  2 return;
 1912    }
 1913   
 1914    else {
 1915  109 LinkedList<MethodData> superMethods = superSd.getMethods();
 1916  109 String superUnqualifiedName = getUnqualifiedClassName(superSd.getName());
 1917   
 1918  109 LanguageLevelVisitor sslv = LanguageLevelConverter._newSDs.remove(superSd);
 1919   
 1920    // if sslv == null, the superclass constructor has already been generated or we are caught in a cyclic
 1921    // inheritance hierarchy
 1922  109 if (sslv != null) {
 1923  8 sslv.createConstructor(superSd);
 1924    // System.err.println("Creating constructor for superclass " + superSd);
 1925    }
 1926   
 1927    // Find the super's smallest constructor.
 1928  109 MethodData superConstructor = null;
 1929  109 for (MethodData superMd: superMethods) {
 1930    // Iterator<MethodData> iter = superMethods.iterator();
 1931    // while (iter.hasNext()) {
 1932    // MethodData superMd = iter.next();
 1933  1234 if (superMd.getName().equals(superUnqualifiedName)) {
 1934  110 if (superConstructor == null || superMd.getParams().length < superConstructor.getParams().length) {
 1935  106 superConstructor = superMd;
 1936    }
 1937    }
 1938    }
 1939  109 if (superConstructor == null) {
 1940  4 _addAndIgnoreError("Could not generate constructor for class " + sd + " superclass has no constructor, perhaps"
 1941    + " because the class hierarchy is cyclic.",
 1942    new NullLiteral(SourceInfo.NONE));
 1943  4 return;
 1944    }
 1945    // if (superConstructor == null) {
 1946    // System.err.println("**** Error **** The superclass " + superSd + " has no constructors ");
 1947    // }
 1948  105 String name = getUnqualifiedClassName(sd.getName());
 1949  105 MethodData md = new MethodData(name,
 1950    PUBLIC_MAV,
 1951    new TypeParameter[0],
 1952    sd,
 1953    new VariableData[0], // Parameters to be filled in later.
 1954    new String[0],
 1955    sd,
 1956    null);
 1957   
 1958  105 LinkedList<VariableData> params = new LinkedList<VariableData>();
 1959    // if (superConstructor != null) {
 1960  105 for (VariableData superParam : superConstructor.getParams()) {
 1961  10 String paramName = md.createUniqueName("super_" + superParam.getName());
 1962  10 SymbolData superParamSD = superParam.getType();
 1963  10 assert superParamSD != null;
 1964  10 VariableData newParam = new VariableData(paramName, PACKAGE_MAV, superParamSD, true, sd); // Note: sd was md
 1965  10 newParam.setGenerated(true);
 1966  10 params.add(newParam);
 1967    // Next line done on each iteration so that createUniqueName handles nameless super parameters (in class files)
 1968  10 md.addVar(newParam); // Fixups have already been executed
 1969    }
 1970    // }
 1971   
 1972    // only add in those fields that do not have a value and are not static.
 1973  105 boolean hasOtherConstructor = sd.hasMethod(name);
 1974   
 1975  105 for (VariableData field : sd.getVars()) {
 1976   
 1977  87 if (! field.hasInitializer() && ! field.hasModifier("static")) {
 1978  63 if (! hasOtherConstructor) { field.gotValue(); } // Set hasValue if no other constructors need to be visited
 1979    // Rather than creating a new parameter, we use the field, since all the important data is the same in both of
 1980    // them.
 1981  72 VariableData param = field.copyWithoutVisibility();
 1982  72 params.add(param);
 1983    }
 1984    }
 1985    // Some fields may be declared private, but parameters cannot be; unprivatize the
 1986   
 1987  105 md.setParams(params.toArray(new VariableData[params.size()]));
 1988  105 md.setVars(params);
 1989   
 1990    // System.err.println("**** Adding constructor " + md + " **** to symbol " + sd);
 1991    // if (md.getName().equals("ClassName"))
 1992    // System.err.println("****** constructor visibility = " + md.getMav());
 1993  105 addGeneratedMethod(sd, md);
 1994    }
 1995  105 LanguageLevelConverter._newSDs.remove(sd); // this won't do anything if sd is not in _newSDs.
 1996    }
 1997   
 1998    /** Create a method that is an accessor for each field in the class.
 1999    * File file is passed in so this can remain a static method
 2000    * TODO: should this be called AFTER all fixups have been performed? No method needs to be in
 2001    * symbol table.
 2002    */
 2003  132 protected static void createAccessors(SymbolData sd, File file) {
 2004  0 if (LanguageLevelConverter.isAdvancedFile(file)) return;
 2005  132 LinkedList<VariableData> fields = sd.getVars();
 2006  132 for (final VariableData vd: fields) {
 2007  85 if (! vd.hasModifier("static")) {
 2008  74 String name = getFieldAccessorName(vd.getName());
 2009  74 SymbolData returnTypeSD = vd.getType();
 2010  74 final MethodData md = new MethodData(name,
 2011    PUBLIC_MAV,
 2012    new TypeParameter[0],
 2013    returnTypeSD,
 2014    new VariableData[0],
 2015    new String[0],
 2016    sd,
 2017    null); // no SourceInfo
 2018  74 addGeneratedMethod(sd, md);
 2019  74 if (returnTypeSD == null) { // create a fixup to patch the return type of md; vd may have pending return type
 2020  3 Command fixUp = new Command() {
 2021  3 public void execute() { md.setReturnType(vd.getType()); }
 2022    };
 2023  3 fixUps.add(fixUp);
 2024    }
 2025    }
 2026    }
 2027    }
 2028   
 2029    /** Create a method called toString that returns type String. Overridden at the Advanced Level files, because n code
 2030    * augmentation is done for them so you don't want to create this method.
 2031    */
 2032  119 protected void createToString(SymbolData sd) {
 2033  119 String name = "toString";
 2034  119 MethodData md = new MethodData(name,
 2035    PUBLIC_MAV,
 2036    new TypeParameter[0],
 2037    getSymbolData("java.lang.String", SourceInfo.make("java.lang.String")),
 2038    new VariableData[0],
 2039    new String[0],
 2040    sd,
 2041    null); // no SourceInfo
 2042  119 addGeneratedMethod(sd, md);
 2043    }
 2044   
 2045    /** Creates a method called hashCode that returns an int. Overriden for FullJava files, because no code augmentation
 2046    * is done for them, so we don't want to create this method.
 2047    */
 2048  119 protected void createHashCode(SymbolData sd) {
 2049  119 String name = "hashCode";
 2050  119 MethodData md = new MethodData(name,
 2051    PUBLIC_MAV,
 2052    new TypeParameter[0],
 2053    SymbolData.INT_TYPE,
 2054    new VariableData[0],
 2055    new String[0],
 2056    sd,
 2057    null); // no SourceInfo
 2058  119 addGeneratedMethod(sd, md);
 2059    }
 2060   
 2061    /** Creates a method called equals() that takes in an Object argument and returns a boolean. Overriden for FullJava
 2062    * files, because no code augmentation is done for them, so we don't want to create this method.
 2063    */
 2064  119 protected void createEquals(SymbolData sd) {
 2065  119 String name = "equals";
 2066  119 SymbolData type = getSymbolData("java.lang.Object", SourceInfo.make("java.lang.Object"));
 2067  119 VariableData param = new VariableData(type);
 2068  119 MethodData md = new MethodData(name,
 2069    PUBLIC_MAV,
 2070    new TypeParameter[0],
 2071    SymbolData.BOOLEAN_TYPE,
 2072    new VariableData[] {param},
 2073    new String[0],
 2074    sd,
 2075    null); // no SourceInfo
 2076  119 param.setEnclosingData(md);
 2077  119 addGeneratedMethod(sd, md);
 2078    }
 2079   
 2080    /**
 2081    * This is overwritten because we don't want to visit each half of
 2082    * MemberType recursively. Just take the whole thing and look for it in
 2083    * forMemberTypeOnly (calls forTypeOnly eventually to get looked up).
 2084    */
 2085  4 public Void forMemberType(MemberType that) {
 2086  4 forMemberTypeDoFirst(that);
 2087  0 if (prune(that)) return null;
 2088  4 return forMemberTypeOnly(that);
 2089    }
 2090   
 2091    /**Return the SymbolData for java.lang.String by default*/
 2092  49 public Void forStringLiteralOnly(StringLiteral that) {
 2093  49 getQualifiedSymbolData("java.lang.String", that.getSourceInfo(), true);
 2094  49 return null;
 2095    }
 2096   
 2097    /** Try to resolve the type of the instantiation, and make sure there are no errors*/
 2098  45 public Void forSimpleNamedClassInstantiation(SimpleNamedClassInstantiation that) {
 2099  45 forSimpleNamedClassInstantiationDoFirst(that);
 2100  0 if (prune(that)) return null;
 2101  45 that.getType().visit(this);
 2102  45 that.getArguments().visit(this);
 2103   
 2104    // Put the allocated type into the symbol table
 2105    /* TODO!: Shouldn't this happen for all Instantiations?
 2106    * Even for all Types, regardless of where they show up?
 2107    */
 2108  45 getSymbolData(that.getType().getName(), that.getSourceInfo());
 2109   
 2110    // TODO? create a fixup?
 2111   
 2112  45 return forSimpleNamedClassInstantiationOnly(that);
 2113    }
 2114   
 2115   
 2116    /** Determines whether array1 equals array2 using the equals method on Object[] arrays in java.util.Arrays.
 2117    * @return true if the two array argument (which may be null) are equal.
 2118    */
 2119  89993 public static boolean arrayEquals(Object[] array1, Object[] array2) {
 2120    // return Arrays.equals(array1, array2);
 2121  89993 int n = array1.length;
 2122  7 if (n != array2.length) return false;
 2123  89986 for (int i = 0; i < n; i++) {
 2124  36 Object o1 = array1[i];
 2125  36 Object o2 = array2[i];
 2126  0 if (o1 == null && o2 != null) return false;
 2127  2 if (! o1.equals(o2)) return false;
 2128    };
 2129  89984 return true;
 2130    }
 2131   
 2132    /** Use this to see if a name references a type that needs to be added to the symbolTable. */
 2133    private class ResolveNameVisitor extends JExpressionIFAbstractVisitor<TypeData> {
 2134   
 2135  205 public ResolveNameVisitor() { }
 2136   
 2137    /** Most expressions are not relevant for this check--visit them with outer visitor. */
 2138  2 public TypeData defaultCase(JExpressionIF that) {
 2139  2 that.visit(LanguageLevelVisitor.this);
 2140  2 return null;
 2141    }
 2142   
 2143    /** Try to look up this simple name reference and match it to a symbol data. If it could not be matched, return a
 2144    * package data.
 2145    * @param that The thing we're trying to match to a type
 2146    */
 2147  203 public TypeData forSimpleNameReference(SimpleNameReference that) {
 2148  203 SymbolData result = getSymbolData(that.getName().getText(), that.getSourceInfo());
 2149    // it could not be resolved: return a Package Data
 2150    // TODO: create a fixup !!!
 2151  203 if (result == SymbolData.NOT_FOUND) {
 2152  0 return new PackageData(that.getName().getText());
 2153    }
 2154  203 return result;
 2155    }
 2156   
 2157    /** Try to look up the enclosing of this complex name reference and then try to match the name on the right
 2158    * within that context to a type. If it could not be matched, return a package data.
 2159    * @param that The thing we're trying to match to a type
 2160    */
 2161  21 public TypeData forComplexNameReference(ComplexNameReference that) {
 2162  21 TypeData lhs = that.getEnclosing().visit(this);
 2163  21 SymbolData result = getSymbolData(lhs, that.getName().getText(), that.getSourceInfo(), true);
 2164   
 2165    // TODO: create a fixup?
 2166  21 if (result == SymbolData.NOT_FOUND) {
 2167  0 if (lhs instanceof PackageData) {
 2168  0 return new PackageData((PackageData) lhs, that.getName().getText());
 2169    }
 2170  0 return null;
 2171    }
 2172  21 return result;
 2173    }
 2174    }
 2175   
 2176    /** Test the methods defined in the above class.*/
 2177    public static class LanguageLevelVisitorTest extends TestCase {
 2178   
 2179    private LanguageLevelVisitor testLLVisitor;
 2180    private Hashtable<SymbolData, LanguageLevelVisitor> testNewSDs;
 2181   
 2182    private SymbolData _sd1;
 2183    private SymbolData _sd2;
 2184    private SymbolData _sd3;
 2185    private SymbolData _sd4;
 2186    private SymbolData _sd5;
 2187    private SymbolData _sd6;
 2188   
 2189  0 public LanguageLevelVisitorTest() { this(""); }
 2190  27 public LanguageLevelVisitorTest(String name) { super(name); }
 2191   
 2192  27 public void setUp() {
 2193  27 Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations =
 2194    new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
 2195  27 LinkedList<Command> fixUps = new LinkedList<Command>();
 2196    // The following ensures that essential symbols have been loaded into the symbolTable, a static field of
 2197    // LanguageLevelConverter.
 2198  27 testLLVisitor = new LanguageLevelVisitor(new File(""),
 2199    "",
 2200    "i.like.monkey",
 2201    new LinkedList<String>(),
 2202    new LinkedList<String>(),
 2203    new HashSet<String>(),
 2204    continuations,
 2205    fixUps);
 2206  27 errors = new LinkedList<Pair<String, JExpressionIF>>();
 2207  27 _errorAdded = false;
 2208   
 2209  27 visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>();
 2210    // _hierarchy = new Hashtable<String, TypeDefBase>();
 2211  27 testLLVisitor._classesInThisFile = new HashSet<String>();
 2212  0 if (! testLLVisitor._importedPackages.contains("java.lang")) testLLVisitor._importedPackages.add("java.lang");
 2213   
 2214  27 _sd1 = new SymbolData("i.like.monkey");
 2215  27 _sd2 = new SymbolData("i.like.giraffe");
 2216  27 _sd3 = new SymbolData("zebra");
 2217  27 _sd4 = new SymbolData("u.like.emu");
 2218  27 _sd5 = new SymbolData("");
 2219  27 _sd6 = new SymbolData("cebu");
 2220    }
 2221   
 2222    /** Tests the getUnqualifiedClassName method. */
 2223  1 public void testGetUnqualifiedClassName() {
 2224  1 assertEquals("getUnqualifiedClassName with a qualified name with an inner class", "innermonkey",
 2225    testLLVisitor.getUnqualifiedClassName("i.like.monkey$innermonkey"));
 2226  1 assertEquals("getUnqualifiedClassName with a qualified name", "monkey",
 2227    testLLVisitor.getUnqualifiedClassName("i.like.monkey"));
 2228  1 assertEquals("getUnqualifiedClassName with an unqualified name", "monkey",
 2229    testLLVisitor.getUnqualifiedClassName("monkey"));
 2230  1 assertEquals("getUnqualifiedClassName with an empty string", "", testLLVisitor.getUnqualifiedClassName(""));
 2231    }
 2232   
 2233  1 public void testClassFile2SymbolData() {
 2234   
 2235    //test a java.lang symbol data
 2236  1 SymbolData objectSD = LanguageLevelConverter._classFile2SymbolData("java.lang.Object", "");
 2237  1 SymbolData stringSD = LanguageLevelConverter._classFile2SymbolData("java.lang.String", "");
 2238  1 MethodData md = new MethodData("substring", PUBLIC_MAV, new TypeParameter[0], stringSD,
 2239    new VariableData[] {new VariableData(SymbolData.INT_TYPE)},
 2240    new String[0], stringSD, null);
 2241  1 assertTrue("java.lang.String should have been converted successfully",
 2242    stringSD.getName().equals("java.lang.String"));
 2243  1 assertEquals("java.lang.String's superSD should should be java.lang.Object",
 2244    objectSD,
 2245    stringSD.getSuperClass());
 2246   
 2247  1 LinkedList<MethodData> methods = stringSD.getMethods();
 2248  1 Iterator<MethodData> iter = methods.iterator();
 2249  1 boolean found = false;
 2250   
 2251  32 while (iter.hasNext()) {
 2252  32 MethodData currMd = iter.next();
 2253  32 if (currMd.getName().equals("substring") && currMd.getParams().length == 1 &&
 2254    currMd.getParams()[0].getInstanceData() == SymbolData.INT_TYPE.getInstanceData()) {
 2255    // TODO: comparing getInstanceData() on preceding line is goofy; should check getType() instead
 2256  1 found = true;
 2257  1 md.getParams()[0].setEnclosingData(currMd);
 2258  1 break;
 2259    }
 2260    }
 2261   
 2262  1 assertTrue("Should have found method substring(int) in java.lang.String", found);
 2263   
 2264  1 assertEquals("java.lang.String should be packaged correctly", "java.lang",
 2265    testLLVisitor.getSymbolData("java.lang.String", SourceInfo.NONE).getPackage());
 2266   
 2267    //now, test that a second call to the same method won't replace the symbol data that is already there.
 2268  1 SymbolData newStringSD = LanguageLevelConverter._classFile2SymbolData("java.lang.String", "");
 2269  1 assertTrue("Second call to classFileToSymbolData should not change sd in hash table.",
 2270    stringSD == LanguageLevelConverter.symbolTable.get("java.lang.String"));
 2271  1 assertTrue("Second call to classFileToSymbolData should return same SD.",
 2272    newStringSD == LanguageLevelConverter.symbolTable.get("java.lang.String"));
 2273    //now, test one of our own small class files.
 2274   
 2275  1 SymbolData bartSD = LanguageLevelConverter._classFile2SymbolData("Bart", "testFiles");
 2276  1 assertFalse("bartSD should not be null", bartSD == null);
 2277  1 assertFalse("bartSD should not be a continuation", bartSD.isContinuation());
 2278  1 MethodData md1 =
 2279    new MethodData("myMethod", PROTECTED_MAV,
 2280    new TypeParameter[0], SymbolData.BOOLEAN_TYPE,
 2281    new VariableData[] { new VariableData(SymbolData.INT_TYPE) },
 2282    new String[] {"java.lang.Exception"}, bartSD, null);
 2283   
 2284  1 md1.getParams()[0].setEnclosingData(bartSD.getMethods().getLast());
 2285  1 MethodData md2 = new MethodData("Bart", PUBLIC_MAV, new TypeParameter[0], bartSD,
 2286    new VariableData[0], new String[0], bartSD, null);
 2287   
 2288  1 VariableData vd1 = new VariableData("i", PUBLIC_MAV, SymbolData.INT_TYPE, true, bartSD);
 2289   
 2290  1 LinkedList<MethodData> bartsMD = new LinkedList<MethodData>();
 2291  1 bartsMD.addFirst(md1);
 2292  1 bartsMD.addFirst(md2);
 2293   
 2294  1 LinkedList<VariableData> bartsVD = new LinkedList<VariableData>();
 2295  1 bartsVD.addLast(vd1);
 2296   
 2297  1 assertEquals("Bart's super class should be java.lang.Object: errors = " + errors, objectSD,
 2298    bartSD.getSuperClass());
 2299  1 assertEquals("Bart's Variable Data should be a linked list containing only vd1", bartsVD, bartSD.getVars());
 2300  1 assertEquals("The first method data of bart's should be correct", md2, bartSD.getMethods().getFirst());
 2301   
 2302  1 assertEquals("The second method data of bart's should be correct", md1, bartSD.getMethods().getLast());
 2303  1 assertEquals("Bart's Method Data should be a linked list containing only md1", bartsMD, bartSD.getMethods());
 2304    }
 2305   
 2306    // public void testLookupFromClassesToBeParsed() {
 2307    // // Create a ClassDef. Recreate the ClassOrInterfaceType for Object instead of using
 2308    // // JExprParser.NO_TYPE since otherwise the ElementaryVisitor will complain that the
 2309    // // user must explicitly extend Object.
 2310    // ClassDef cd =
 2311    // new ClassDef(SourceInfo.NONE, PUBLIC_MAV,
 2312    // new Word(SourceInfo.NONE, "Lisa"),
 2313    // new TypeParameter[0],
 2314    // new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]),
 2315    // new ReferenceType[0],
 2316    // new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 2317    //
 2318    // // Use a ElementaryVisitor so lookupFromClassesToBeParsed will actually visit the ClassDef.
 2319    // IntermediateVisitor bv = new IntermediateVisitor(new File(""),
 2320    // errors,
 2321    // continuations,
 2322    // new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>());
 2323    //
 2324    // // Test that passing resolve equals false returns a continuation.
 2325    //// assertTrue("Should return a continuation",
 2326    //// testLLVisitor._identifyTypeFromClassesToBeParsed("Lisa", SourceInfo.NONE, false).isContinuation());
 2327    // // Put Lisa in the hierarchy and test that there is one error and that the message
 2328    // // says that there is cyclic inheritance.
 2329    //// _hierarchy.put("Lisa", cd);
 2330    //// _classesInThisFile.put("Lisa", new Pair<TypeDefBase, LanguageLevelVisitor>(cd, bv));
 2331    //// assertEquals("Should return null because Lisa is in the hierarchy",
 2332    //// null,
 2333    //// _llv._identifyTypeFromClassesToBeParsed("Lisa", SourceInfo.NONE, true));
 2334    //// assertEquals("Should be one error", 1, errors.size());
 2335    //// assertEquals("Error message should be correct", "Cyclic inheritance involving Lisa", errors.get(0).getFirst());
 2336    //// _hierarchy.remove("Lisa");
 2337    // //Re-add Lisa because the first call with resolve set to true removed it and
 2338    // // test that Lisa is actually visited and added to the symbolTable.
 2339    // testLLVisitor._classesInThisFile.put("Lisa", new Pair<TypeDefBase, LanguageLevelVisitor>(cd, bv));
 2340    // assertFalse("Should return a non-continuation",
 2341    // testLLVisitor._identifyTypeFromClassesToBeParsed("Lisa",
 2342    // SourceInfo.NONE,
 2343    // true).isContinuation());
 2344    // }
 2345   
 2346  1 public void testGetSymbolDataForClassFile() {
 2347    // Test that passing a legal class return a non-continuation.
 2348  1 assertFalse("Should return a non-continuation",
 2349    LanguageLevelConverter.getSymbolDataForClassFile("java.lang.String", null).isContinuation());
 2350   
 2351    // Test that passing a userclass that can't be found returns null and adds an error.
 2352  1 assertNull("Should return null with a user class that can't be found",
 2353    LanguageLevelConverter.getSymbolDataForClassFile("Marge", null));
 2354    // assertEquals("There should be one error", 1, errors.size());
 2355    // assertEquals("The error message should be correct", "Class Marge not found.", errors.get(0).getFirst());
 2356    }
 2357   
 2358   
 2359  1 public void testGetSymbolData_Primitive() {
 2360  1 assertEquals("should be boolean type", SymbolData.BOOLEAN_TYPE,
 2361    LanguageLevelConverter._getPrimitiveSymbolData("boolean"));
 2362  1 assertEquals("should be char type", SymbolData.CHAR_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("char"));
 2363  1 assertEquals("should be byte type", SymbolData.BYTE_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("byte"));
 2364  1 assertEquals("should be short type", SymbolData.SHORT_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("short"));
 2365  1 assertEquals("should be int type", SymbolData.INT_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("int"));
 2366  1 assertEquals("should be long type", SymbolData.LONG_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("long"));
 2367  1 assertEquals("should be float type", SymbolData.FLOAT_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("float"));
 2368  1 assertEquals("should be double type", SymbolData.DOUBLE_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("double"));
 2369  1 assertEquals("should be void type", SymbolData.VOID_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("void"));
 2370  1 assertEquals("should be null type", SymbolData.NULL_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("null"));
 2371  1 assertEquals("should return null--not a primitive", null,
 2372    LanguageLevelConverter._getPrimitiveSymbolData("java.lang.String"));
 2373    }
 2374   
 2375    // public void testGetQualifiedSymbolData() {
 2376    // testLLVisitor._file = new File("testFiles/Fake.dj0");
 2377    // SymbolData sd = new SymbolData("testPackage.File");
 2378    // testLLVisitor._package = "testPackage";
 2379    // LanguageLevelConverter.symbolTable.put("testPackage.File", sd);
 2380    //
 2381    // SymbolData sd1 = new SymbolData("java.lang.String");
 2382    // LanguageLevelConverter.symbolTable.put("java.lang.String", sd1);
 2383    //
 2384    // //Test that classes not in the symbol table are handled correctly.
 2385    // assertEquals("should the continuation symbol", sd,
 2386    // testLLVisitor._getQualifiedSymbolData("testPackage.File", SourceInfo.NONE, true, false, true));
 2387    //// assertEquals("should be one error so far.", 1, errors.size());
 2388    //
 2389    //
 2390    // SymbolData sd2 = testLLVisitor._getQualifiedSymbolData("java.lang.Integer", SourceInfo.NONE, true, true, true);
 2391    // assertEquals("should return non-continuation java.lang.Integer", "java.lang.Integer", sd2.getName());
 2392    // assertFalse("should not be a continuation.", sd2.isContinuation());
 2393    //
 2394    // SymbolData sd3 = testLLVisitor._getQualifiedSymbolData("Wow", SourceInfo.NONE, true, true, true);
 2395    // assertEquals("search should fail", null, sd3);
 2396    //// assertEquals("should return Wow", "Wow", sd3.getName());
 2397    //// assertFalse("Should not be a continuation.", sd3.isContinuation());
 2398    //
 2399    // // "testPackage.File" has been entered as a continuation in symbolTable. Why should the following lookup fail?
 2400    //// //Test that classes in the symbol table are handled correctly
 2401    //// assertEquals("should return null sd--does not exist", null,
 2402    //// _llv._getQualifiedSymbolData("testPackage.File", SourceInfo.NONE, false, false, true));
 2403    //// assertEquals("Should be 1 error", 1, errors.size());
 2404    //
 2405    // sd.setIsContinuation(false);
 2406    // assertEquals("should return non-continuation sd", sd,
 2407    // testLLVisitor._getQualifiedSymbolData("testPackage.File", SourceInfo.NONE, true, false, true));
 2408    //
 2409    //
 2410    // assertEquals("Should return sd1.", sd1,
 2411    // testLLVisitor._getQualifiedSymbolData("java.lang.String", SourceInfo.NONE, true, false, true));
 2412    // assertFalse("sd1 should no longer be a continuation.", sd1.isContinuation());
 2413    //
 2414    //
 2415    //
 2416    // //check that stuff not in symbol table and packaged incorrectly is handled right.
 2417    // assertEquals("should return null-because it's not a valid class", null,
 2418    // testLLVisitor._getQualifiedSymbolData("testPackage.not.in.symboltable",
 2419    // SourceInfo.NONE, true, false, true));
 2420    //
 2421    // assertEquals("should be two errors so far.", 2, errors.size());
 2422    // assertNull("should return null",
 2423    // testLLVisitor._getQualifiedSymbolData("testPackage.not.in.symboltable",
 2424    // SourceInfo.NONE, false, false, false));
 2425    //
 2426    // assertNull("should return null.",
 2427    // testLLVisitor._getQualifiedSymbolData("notRightPackage", SourceInfo.NONE, false, false, false));
 2428    // assertEquals("should still be two errors.", 2, errors.size());
 2429    // }
 2430   
 2431  1 public void testGetArraySymbolData() {
 2432    //Initially, force the inner sd of this array type to be null, to test that.
 2433  1 assertEquals("Should return null, because inner sd is null.", null,
 2434    testLLVisitor.getArraySymbolData("TestFile", SourceInfo.NONE, false, false));
 2435   
 2436    /**Now, put a real SymbolData base in the table.*/
 2437  1 SymbolData sd = new SymbolData("Iexist");
 2438  1 LanguageLevelConverter.symbolTable.put("Iexist", sd);
 2439  1 testLLVisitor.getArraySymbolData("Iexist", SourceInfo.NONE, false, false).getName();
 2440  1 assertTrue("Should have created an array data and add it to symbol table.",
 2441    LanguageLevelConverter.symbolTable.containsKey("Iexist[]"));
 2442  1 SymbolData ad = LanguageLevelConverter.symbolTable.get("Iexist[]");
 2443   
 2444    //make sure that ad has the appropriate fields and super classes and interfaces and methods
 2445  1 assertEquals("Should only have field 'length'", 1, ad.getVars().size());
 2446  1 assertNotNull("Should contain field 'length'", ad.getVar("length"));
 2447   
 2448  1 assertEquals("Should only have one method-clone", 1, ad.getMethods().size());
 2449  1 assertTrue("Should contain method clone", ad.hasMethod("clone"));
 2450   
 2451  1 assertEquals("Should have Object as super class",
 2452    LanguageLevelConverter.symbolTable.get("java.lang.Object"),
 2453    ad.getSuperClass());
 2454  1 assertEquals("Should have 2 interfaces", 2, ad.getInterfaces().size());
 2455  1 assertEquals("Interface 1 should be java.lang.Cloneable", "java.lang.Cloneable",
 2456    ad.getInterfaces().get(0).getName());
 2457  1 assertEquals("Interface 2 should be java.io.Serializable", "java.io.Serializable",
 2458    ad.getInterfaces().get(1).getName());
 2459   
 2460   
 2461    /**Now try it with the full thing already in the symbol table.*/
 2462  1 assertEquals("Since it's already in symbol table now, should just return it.", ad,
 2463    testLLVisitor.getArraySymbolData("Iexist", SourceInfo.NONE, false, false));
 2464   
 2465    /**Now, try it with a multiple dimension array.*/
 2466  1 testLLVisitor.getArraySymbolData("Iexist[]", SourceInfo.NONE, false, false);
 2467  1 assertTrue("Should have added a multidimensional array to the table.",
 2468    LanguageLevelConverter.symbolTable.containsKey("Iexist[][]"));
 2469   
 2470  1 SymbolData sd2 = new SymbolData("java.lang.String");
 2471  1 LanguageLevelConverter.symbolTable.put("java.lang.String", sd2);
 2472  1 testLLVisitor.getArraySymbolData("String[]", SourceInfo.NONE, false, true);
 2473  1 assertTrue("Should have added java.lang.String[] to table",
 2474    LanguageLevelConverter.symbolTable.containsKey("java.lang.String[]"));
 2475  1 assertTrue("Should have added java.lang.String[][] to table",
 2476    LanguageLevelConverter.symbolTable.containsKey("java.lang.String[][]"));
 2477    }
 2478    /** Tests _getSymbolDataFromFileSystem and one case of getQualifiedSymbolData. */
 2479  1 public void testGetSymbolDataFromFileSystem() {
 2480  1 _sd4.setIsContinuation(false);
 2481  1 _sd6.setIsContinuation(true);
 2482  1 LanguageLevelConverter.symbolTable.put("u.like.emu", _sd4);
 2483  1 LanguageLevelConverter.symbolTable.put("cebu", _sd6);
 2484   
 2485    // Test if it's already in the symbol table and doesn't need to be resolved not stopping when it should.
 2486    // get error b/c not in classes to be parsed
 2487  1 assertEquals("symbol data is a not a continuation, but resolve is false so should just be returned", _sd6,
 2488    testLLVisitor._getSymbolDataFromFileSystem("cebu", SourceInfo.NONE, false, true));
 2489  1 assertEquals("symbol data is a continuation, but resolve is false, so should just be returned.", _sd4,
 2490    testLLVisitor._getSymbolDataFromFileSystem("u.like.emu", SourceInfo.NONE, false, true));
 2491   
 2492    // Lookup a name not in the file system with resolve equal to false, to confirm that null is returned.
 2493   
 2494  1 assertEquals("Should return SymbolData.NOT_FOUND", SymbolData.NOT_FOUND,
 2495    testLLVisitor._getSymbolDataFromFileSystem("Corky", SourceInfo.NONE, false, true));
 2496    // TODO: fix this test
 2497    // SymbolData matchCorky = testLLVisitor._getSymbolDataFromFileSystem("Corky", SourceInfo.NONE, true);
 2498    // assertFalse("Should return a non-continuation", matchCorky.isContinuation());
 2499   
 2500    // Test if it needs to be resolved:
 2501  1 ClassDef cd =
 2502    new ClassDef(SourceInfo.NONE, PUBLIC_MAV,
 2503    new Word(SourceInfo.NONE, "Lisa"),
 2504    new TypeParameter[0],
 2505    new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]),
 2506    new ReferenceType[0],
 2507    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 2508   
 2509    // Use a ElementaryVisitor so lookupFromClassesToBeParsed will actually visit the ClassDef.
 2510  1 IntermediateVisitor bv = new IntermediateVisitor(new File(""));
 2511   
 2512  1 testLLVisitor._classesInThisFile.add("Lisa" /*, new Pair<TypeDefBase, LanguageLevelVisitor>(cd, bv)*/);
 2513  1 assert testLLVisitor._classesInThisFile.contains("Lisa");
 2514  1 SymbolData matchLisa =
 2515    testLLVisitor.getQualifiedSymbolData("Lisa", SourceInfo.NONE, true);
 2516  1 assertTrue("Should return a continuation", matchLisa.isContinuation());
 2517    }
 2518   
 2519  1 public void testGetSymbolDataFromFileSystem2() {
 2520    //what if it is in classes to be parsed?
 2521    //and what if the class we're looking up is in the same package as the current file?
 2522    //qualified
 2523  1 testLLVisitor._package="fully.qualified";
 2524  1 testLLVisitor._file = new File("testFiles/fully/qualified/Fake.dj0");
 2525  1 SymbolData sd2 = new SymbolData("fully.qualified.Woah"); // continuation
 2526  1 testLLVisitor.symbolTable.put("fully.qualified.Woah", sd2);
 2527   
 2528  1 SymbolData result =
 2529    testLLVisitor._getSymbolDataFromFileSystem("fully.qualified.Woah", SourceInfo.NONE, false, true);
 2530   
 2531  1 assertEquals("Should return sd2, unresolved.", sd2, result);
 2532  1 assertTrue("sd2 should still be unresolved", sd2.isContinuation());
 2533  1 assertEquals("Should be no errors", 0, errors.size());
 2534   
 2535    // result = _llv._getSymbolDataFromFileSystem("fully.qualified.Woah", SourceInfo.NONE, false, true);
 2536    // assertEquals("Should return sd2, now unresolved.", sd2, result);
 2537    // assertTrue("sd2 should not be resolved", sd2.isContinuation());
 2538    // assertEquals("Should be no errors", 0, errors.size());
 2539   
 2540    // result = _llv._getSymbolDataFromFileSystem("fully.qualified.Woah", SourceInfo.NONE, true, true);
 2541    // assertEquals("Should return sd2, now resolved.", sd2, result);
 2542    // assertFalse("sd2 should now be resolved", sd2.isContinuation());
 2543    // assertEquals("Should be no errors", 0, errors.size());
 2544   
 2545   
 2546    //what if the files are in different packages
 2547  1 testLLVisitor.symbolTable.remove("fully.qualified.Woah");
 2548  1 testLLVisitor.visitedFiles.clear();
 2549  1 testLLVisitor._package="another.package";
 2550  1 testLLVisitor._file = new File("testFiles/another/package/Wowsers.dj0");
 2551  1 sd2 = new SymbolData("fully.qualified.Woah");
 2552  1 testLLVisitor.symbolTable.put("fully.qualified.Woah", sd2);
 2553   
 2554  1 result = testLLVisitor._getSymbolDataFromFileSystem("fully.qualified.Woah", SourceInfo.NONE, false, true);
 2555   
 2556  1 assertEquals("Should return sd2, unresolved.", sd2, result);
 2557  1 assertTrue("sd2 should still be unresolved", sd2.isContinuation());
 2558  1 assertEquals("Should be no errors", 0, errors.size());
 2559   
 2560    // result = _llv._getSymbolDataFromFileSystem("fully.qualified.Woah", SourceInfo.NONE, true, true);
 2561    // assertEquals("Should return sd2, now resolved.", sd2, result);
 2562   
 2563    // assertFalse("sd2 should be resolved", sd2.isContinuation());
 2564    // assertEquals("Should be no errors", 0, errors.size());
 2565   
 2566    //what if there is no package
 2567    //Now, check cases when desired SymbolData is in the symbol table.
 2568  1 testLLVisitor._package = "";
 2569  1 testLLVisitor._file = new File ("testFiles/Cool.dj0"); // non-existent file
 2570   
 2571    //unqualified
 2572  1 SymbolData sd1 = new SymbolData("Wow");
 2573  1 SymbolData obj = testLLVisitor._getSymbolDataFromFileSystem("java.lang.Object", SourceInfo.NONE, true, true);
 2574  1 sd1.setSuperClass(obj);
 2575  1 testLLVisitor.symbolTable.put("Wow", sd1);
 2576   
 2577  1 result = testLLVisitor._getSymbolDataFromFileSystem("Wow", SourceInfo.NONE, false, true);
 2578  1 assertEquals("Should return sd1, unresolved.", sd1, result);
 2579  1 assertTrue("sd1 should still be unresolved.", sd1.isContinuation());
 2580  1 assertEquals("Should be no errors", 0, errors.size());
 2581   
 2582  1 result = testLLVisitor._getSymbolDataFromFileSystem("Wow", SourceInfo.NONE, true, true);
 2583  1 assertEquals("Should return sd1, resolved.", sd1, result);
 2584  1 assertFalse("sd1 should be resolved.", sd1.isContinuation());
 2585  1 assertEquals("Should be no errors", 0, errors.size());
 2586   
 2587  1 result = testLLVisitor._getSymbolDataFromFileSystem("Wow", SourceInfo.NONE, true, true);
 2588  1 assertEquals("Should return sd1.", sd1, result);
 2589  1 assertFalse("sd1 should still be resolved.", sd1.isContinuation());
 2590  1 assertEquals("Should be no errors", 0, errors.size());
 2591   
 2592   
 2593    //finding the most recent file
 2594  1 result = testLLVisitor._getSymbolDataFromFileSystem("James", SourceInfo.NONE, true, true);
 2595  1 assertEquals("Search for James should fail", null, result);
 2596    // assertEquals("Result should have 3 variables.", 3, result.getVars().size());
 2597    // assertEquals("Should be no errors", 0, errors.size());
 2598   
 2599    //returning NOT_FOUND when it doesn't exist.
 2600  1 testLLVisitor._package = "myPackage";
 2601  1 assertEquals("Should return NOT_FOUND-does not exist.",
 2602    SymbolData.NOT_FOUND,
 2603    testLLVisitor._getSymbolDataFromFileSystem("WrongPackage.className",
 2604    SourceInfo.NONE, true, false));
 2605  1 assertEquals("Should be no errors", 0, errors.size());
 2606   
 2607    // Now, test case where class file still exists, but java file is gone.
 2608  1 testLLVisitor._package = "";
 2609  1 testLLVisitor._file = new File("testFiles/Fake.dj0");
 2610  1 LinkedList<VariableData> vds = new LinkedList<VariableData>();
 2611  1 result = testLLVisitor._getSymbolDataFromFileSystem("Doh", SourceInfo.NONE, true, true);
 2612  1 vds.addLast(new VariableData("i", PACKAGE_MAV, SymbolData.INT_TYPE, true, result));
 2613  1 vds.addLast(new VariableData("o", PACKAGE_MAV, obj, true, result));
 2614    // Since some list elements are arrays, comparison test is suspect
 2615    // assertEquals("should have correct variable datas", vds, result.getVars());
 2616    // assertFalse("should not be a continuation", result.isContinuation());
 2617   
 2618    //Now test case where java file has been updated more recently than class file.
 2619    //TODO: How can we test this since repository is checked out (i.e. the files all have the same timestamp)?
 2620    }
 2621   
 2622  1 public void testGetSymbolData() {
 2623  1 testLLVisitor._package="";
 2624  1 testLLVisitor._file = new File("testFiles/akdjskj");
 2625   
 2626    // No dot case
 2627  1 SymbolData sd1 = new SymbolData("Wow");
 2628  1 testLLVisitor.symbolTable.put("Wow", sd1);
 2629  1 assertEquals("Should return an equal SymbolData",
 2630    sd1, testLLVisitor.getQualifiedSymbolData("Wow", SourceInfo.NONE, true));
 2631  1 assertFalse("Should not be a continuation", sd1.isContinuation()); // There is a pre-existing class file Wow!
 2632   
 2633    // Invalid case
 2634  1 SymbolData result = testLLVisitor.getSymbolData("ima.invalid", SourceInfo.NONE, true, false);
 2635  1 assertEquals("Should return null-invalid class name", null, result);
 2636  1 assertEquals("There should not be any errors", 0, testLLVisitor.errors.size());
 2637   
 2638    // Fully qualified class name
 2639  1 testLLVisitor._package="fully.qualified";
 2640  1 testLLVisitor._file = new File("testFiles/fully/qualified/Fake.dj0");
 2641  1 SymbolData sd2 = new SymbolData("fully.qualified.Symbol");
 2642  1 testLLVisitor.symbolTable.put("fully.qualified.Symbol", sd2);
 2643   
 2644  1 result = testLLVisitor.getSymbolData("fully.qualified.Symbol", SourceInfo.NONE, true, false);
 2645   
 2646  1 assertEquals("Should return sd2, resolved.", sd2, result);
 2647  1 assertTrue("sd2 should be resolved", sd2.isContinuation());
 2648   
 2649    // Inner class
 2650  1 sd1.setName("fully.qualified.Woah.Wow");
 2651  1 sd2.addInnerClass(sd1);
 2652  1 sd1.setOuterData(sd2);
 2653  1 testLLVisitor.symbolTable.put("fully.qualified.Woah.Wow", sd1);
 2654  1 testLLVisitor.symbolTable.remove("Wow");
 2655  1 sd1.setIsContinuation(false);
 2656  1 result = testLLVisitor.getSymbolData("fully.qualified.Woah.Wow", SourceInfo.NONE, true, false);
 2657  1 assertEquals("Should return sd1 (the inner class!)", sd1, result);
 2658   
 2659    // Inner inner class
 2660  1 SymbolData sd3 = new SymbolData("fully.qualified.Woah.Wow.James");
 2661  1 sd1.addInnerClass(sd3);
 2662    // System.err.println("SYMBOL TABLE ENTRY FOR \"fully.qualified.Woah.Wow.James\" = " +
 2663    // _llv.symbolTable.get("fully.qualified.Woah.Wow.James"));
 2664  1 sd3.setOuterData(sd1);
 2665    // System.err.println("INNER CLASS LOOKUP YIELDS: " + sd1.getInnerClassOrInterface("James"));
 2666  1 result = testLLVisitor.getSymbolData("fully.qualified.Woah.Wow.James", SourceInfo.NONE, true, false);
 2667  1 assertEquals("Should return sd3", sd3, result);
 2668    }
 2669   
 2670  1 public void testGetQualifiedSymbolData() {
 2671    // Primitive types
 2672  1 assertEquals("should return the int SymbolData", SymbolData.INT_TYPE,
 2673    testLLVisitor.getQualifiedSymbolData("int", SourceInfo.NONE, true, true, true));
 2674  1 assertEquals("should return the byte SymbolData", SymbolData.BYTE_TYPE,
 2675    testLLVisitor.getQualifiedSymbolData("byte", SourceInfo.NONE, false, false, false));
 2676   
 2677    // Array types
 2678  1 ArrayData ad = new ArrayData(SymbolData.INT_TYPE, testLLVisitor, SourceInfo.NONE);
 2679  1 SymbolData result = testLLVisitor.getQualifiedSymbolData("int[]", SourceInfo.NONE, true, true, true);
 2680  1 ad.getVars().get(0).setEnclosingData(result); //.equals(...) on VariableData compares enclosing datas with ==.
 2681  1 ad.getMethods().get(0).setEnclosingData(result.getMethods().get(0).getEnclosingData()); //similar hack
 2682  1 assertEquals("should return the array type", ad, result);
 2683   
 2684    // Qualified types
 2685  1 SymbolData sd = new SymbolData("java.lang.System");
 2686  1 LanguageLevelConverter.symbolTable.put("java.lang.System", sd);
 2687  1 assertEquals("should return the same sd", sd,
 2688    testLLVisitor.getQualifiedSymbolData("java.lang.System", SourceInfo.NONE, false, true, true));
 2689  1 assertTrue("should be a continuation", sd.isContinuation());
 2690  1 assertEquals("should return the now resolved sd", sd,
 2691    testLLVisitor.getQualifiedSymbolData("java.lang.System", SourceInfo.NONE, true, false, true));
 2692  1 assertFalse("should not be a continuation", sd.isContinuation());
 2693   
 2694    // In this file
 2695  1 sd = new SymbolData("fully.qualified.Qwerty");
 2696  1 LanguageLevelConverter.symbolTable.put("fully.qualified.Qwerty", sd);
 2697  1 testLLVisitor._classesInThisFile.add("fully.qualified.Qwerty");
 2698    // Use a ElementaryVisitor so lookupFromClassesToBeParsed will actually visit the ClassDef.
 2699  1 IntermediateVisitor bv = new IntermediateVisitor(new File(""),
 2700    errors,
 2701    continuations,
 2702    fixUps,
 2703    new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>());
 2704  1 bv._package = "fully.qualified";
 2705  1 bv._file = new File("testFiles/fully/qualified/Fake.dj0");
 2706  1 ClassDef cd = new ClassDef(SourceInfo.NONE,
 2707    PACKAGE_MAV,
 2708    new Word(SourceInfo.NONE, "Qwerty"),
 2709    new TypeParameter[0],
 2710    new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]),
 2711    new ReferenceType[0],
 2712    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 2713  1 bv._classesInThisFile.add("fully.qualified.Qwerty" /*, new Pair<TypeDefBase, LanguageLevelVisitor>(cd, bv)*/);
 2714  1 assertEquals("should return sd the continuation", sd,
 2715    bv.getSymbolData("Qwerty", SourceInfo.NONE, true, true));
 2716  1 assertTrue("should be a continuation", sd.isContinuation());
 2717  1 assertEquals("should also return a continuation", sd,
 2718    bv.getQualifiedSymbolData("fully.qualified.Qwerty", SourceInfo.NONE, false, false, true));
 2719  1 assertTrue("should be a continuation", sd.isContinuation());
 2720   
 2721    // Imported files
 2722  1 testLLVisitor._importedFiles.addLast("a.b.c");
 2723  1 sd = new SymbolData("a.b.c");
 2724    // System.err.println("SymbolData for 'a.b.c' is " + sd);
 2725  1 LanguageLevelConverter.symbolTable.put("a.b.c", sd);
 2726    // System.err.println("SymbolTable entry for 'a.b.c' is " + LanguageLevelConverter.symbolTable.get("a.b.c"));
 2727    // LanguageLevelConverter.symbolTable.put("foobar", new SymbolData("This is strange"));
 2728    // System.err.println("SymbolTable entry for 'foobar' is " + LanguageLevelConverter.symbolTable.get("foobar"));
 2729  1 assertEquals("should find the continuation in the symbol table", sd,
 2730    testLLVisitor.getQualifiedSymbolData("a.b.c", SourceInfo.NONE, false, true, true));
 2731    // TODO: create an import table to look at when no match is found in symbolTable.
 2732  1 assertTrue("should be a continuation", sd.isContinuation());
 2733   
 2734  1 testLLVisitor._package="fully.qualified";
 2735  1 testLLVisitor._file = new File("testFiles/fully/qualified/Fake.dj0");
 2736  1 testLLVisitor._importedFiles.addLast("fully.qualified.Woah");
 2737  1 SymbolData sd2 = new SymbolData("fully.qualified.Woah");
 2738  1 sd2.setIsContinuation(false);
 2739  1 LanguageLevelConverter.symbolTable.put("fully.qualified.Woah", sd2);
 2740  1 result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, true, false, true);
 2741    // System.err.println("result for 'fully.qualifed.Woah' is " + result);
 2742  1 assertEquals("should find the resolved symbol data in the symbol table", sd2, result);
 2743  1 assertFalse("should not be a continuation", sd2.isContinuation());
 2744   
 2745    // File System
 2746  1 testLLVisitor._importedFiles.clear();
 2747  1 testLLVisitor.visitedFiles.clear();
 2748  1 LanguageLevelConverter.symbolTable.remove("fully.qualified.Woah");
 2749  1 sd2 = new SymbolData("fully.qualified.Woah");
 2750  1 LanguageLevelConverter.symbolTable.put("fully.qualified.Woah", sd2);
 2751   
 2752    // System.err.println("_llv.getSymbolData for fully.qualified.Woah = " +
 2753    // _llv.getQualifiedSymbolData("fully.qualified.Woah",
 2754    // SourceInfo.NONE, true, true, true));
 2755   
 2756  1 result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, false, false, true);
 2757   
 2758  1 assertEquals("Should return sd2, unresolved.", sd2, result);
 2759  1 assertTrue("sd2 should still be unresolved", sd2.isContinuation());
 2760   
 2761  1 result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, false, false, true);
 2762  1 assertEquals("Should return sd2, now unresolved.", sd2, result);
 2763  1 assertTrue("sd2 should not be resolved", sd2.isContinuation());
 2764   
 2765    // The following "test" forces the definition of "Woah" to be retrieved from the file system but THERE IS NO CLASS
 2766    // FILE so the file system search returns null!
 2767  1 result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, true, false, true);
 2768  1 assertEquals("Should return sd2, now resolved.", sd2, result);
 2769  1 assertFalse("sd2 should now be resolved", sd2.isContinuation());
 2770   
 2771    // Imported Packages
 2772  1 LanguageLevelConverter.symbolTable.remove("fully.qualified.Woah");
 2773  1 testLLVisitor.visitedFiles.clear();
 2774  1 testLLVisitor._file = new File("testFiles/Fake.dj0");
 2775  1 testLLVisitor._package = "";
 2776  1 testLLVisitor._importedPackages.addLast("fully.qualified");
 2777  1 sd2 = new SymbolData("fully.qualified.Woah");
 2778  1 LanguageLevelConverter.symbolTable.put("fully.qualified.Woah", sd2);
 2779  1 assertEquals("should find the unresolved symbol data in the symbol table", sd2,
 2780    testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, false, false, true));
 2781  1 assertTrue("should not be a continuation", sd2.isContinuation());
 2782   
 2783  1 sd2.setIsContinuation(false);
 2784  1 result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, true, false, true);
 2785  1 assertEquals("should find the resolved symbol data in the symbol table", sd2, result);
 2786  1 assertFalse("should not be a continuation", sd2.isContinuation());
 2787   
 2788    //test java.lang classes that need to be looked up
 2789    //want to resolve
 2790  1 SymbolData stringSD = new SymbolData("java.lang.String");
 2791  1 SymbolData newsd1 = testLLVisitor.getQualifiedSymbolData("java.lang.String", SourceInfo.NONE, true, true, true);
 2792  1 assertEquals("should have correct name.", stringSD.getName(), newsd1.getName());
 2793  1 assertFalse("should not be a continuation", newsd1.isContinuation());
 2794   
 2795    // Test ambiguous class name (i.e. it is unqualified, and matches unqualified names in 2 or more packages.
 2796  1 LanguageLevelConverter.symbolTable.put("random.package.String", new SymbolData("random.package.String"));
 2797    // LanguageLevelConverter.symbolTable.put("java.lang.Object", new SymbolData("java.lang.Object"));
 2798  1 testLLVisitor._importedPackages.addLast("random.package");
 2799  1 result = testLLVisitor.getSymbolData("String", SourceInfo.NONE);
 2800  1 assertEquals("Result should be null", null, result);
 2801  1 assertEquals("There should be 1 error", 1, errors.size());
 2802  1 assertEquals("The error message should be correct", "The class name String is ambiguous." +
 2803    " It could be java.lang.String or random.package.String",
 2804    errors.get(0).getFirst());
 2805   
 2806  1 LanguageLevelConverter.symbolTable.remove("random.package.String");
 2807   
 2808    }
 2809   
 2810  1 public void test_forModifiersAndVisibility() {
 2811    // Test access specifiers.
 2812  1 testLLVisitor.forModifiersAndVisibility(PUBLIC_MAV);
 2813  1 testLLVisitor.forModifiersAndVisibility(PROTECTED_MAV);
 2814  1 testLLVisitor.forModifiersAndVisibility(PRIVATE_MAV);
 2815  1 testLLVisitor.forModifiersAndVisibility(PACKAGE_MAV);
 2816   
 2817   
 2818  1 assertEquals("There should be no errors.", 0, errors.size());
 2819   
 2820    // Test "public", "private"
 2821  1 ModifiersAndVisibility testMav =
 2822    new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "private"});
 2823  1 testLLVisitor.forModifiersAndVisibility(testMav);
 2824  1 assertEquals("There should be one error.", 1, errors.size());
 2825  1 assertEquals("The error message should be correct.", "Illegal combination of modifiers." +
 2826    " Can't use private and public together.", errors.get(0).getFirst());
 2827   
 2828    // Test "public", "abstract"
 2829  1 testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "abstract"});
 2830  1 testLLVisitor.forModifiersAndVisibility(testMav);
 2831  1 assertEquals("Still only one error.", 1, errors.size());
 2832   
 2833    // Test "abstract", "final"
 2834  1 testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract", "final"});
 2835  1 testLLVisitor.forModifiersAndVisibility(testMav);
 2836  1 assertEquals("There should be two errors.", 2, errors.size());
 2837  1 assertEquals("The error message should be correct.", "Illegal combination of modifiers." +
 2838    " Can't use final and abstract together.", errors.get(1).getFirst());
 2839   
 2840    // Test "final", "abstract"
 2841  1 testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final", "abstract"});
 2842  1 testLLVisitor.forModifiersAndVisibility(testMav);
 2843  1 assertEquals("There should still be two errors.", 2, errors.size()); // Generated error is duplicate
 2844  1 assertEquals("The error message should be correct.", "Illegal combination of modifiers." +
 2845    " Can't use final and abstract together.", errors.get(1).getFirst());
 2846   
 2847    // Test "volatile", "final"
 2848  1 testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"volatile", "final"});
 2849  1 testLLVisitor.forModifiersAndVisibility(testMav);
 2850  1 assertEquals("There should be three errors.", 3, errors.size()); // Generated one new error
 2851  1 assertEquals("The error message should be correct.", "Illegal combination of modifiers." +
 2852    " Can't use final and volatile together.", errors.get(2).getFirst());
 2853   
 2854    // Test "static", "final", "static"
 2855  1 testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static", "final", "static"});
 2856  1 testLLVisitor.forModifiersAndVisibility(testMav);
 2857  1 assertEquals("There should be four errors.", 4, errors.size()); // Generated one new error
 2858  1 assertEquals("The error message should be correct.", "Duplicate modifier: static", errors.get(3).getFirst());
 2859    }
 2860   
 2861  1 public void testGetQualifiedClassName() {
 2862    //first test when the package is empty:
 2863  1 testLLVisitor._package="";
 2864  1 assertEquals("Should not change qualified name.", "simpson.Bart",
 2865    testLLVisitor.getQualifiedClassName("simpson.Bart"));
 2866  1 assertEquals("Should not change unqualified name.", "Lisa", testLLVisitor.getQualifiedClassName("Lisa"));
 2867   
 2868    //now test when package is not empty.
 2869  1 testLLVisitor._package="myPackage";
 2870  1 assertEquals("Should not change properly packaged qualified name.", "myPackage.Snowball",
 2871    testLLVisitor.getQualifiedClassName("myPackage.Snowball"));
 2872  1 assertEquals("Should append package to front of not fully packaged name", "myPackage.simpson.Snowball",
 2873    testLLVisitor.getQualifiedClassName("simpson.Snowball"));
 2874  1 assertEquals("Should append package to front of unqualified class name.", "myPackage.Grandpa",
 2875    testLLVisitor.getQualifiedClassName("Grandpa"));
 2876    }
 2877   
 2878  1 public void testAddSymbolData() {
 2879    /**Put super class in symbol table.*/
 2880  1 SymbolData obj = LanguageLevelConverter.symbolTable.get("java.lang.Object");
 2881    // obj.setIsContinuation(false);
 2882    // LanguageLevelConverter.symbolTable.put("java.lang.Object", obj);
 2883   
 2884  1 ClassDef cd =
 2885    new ClassDef(SourceInfo.NONE, PUBLIC_MAV, new Word(SourceInfo.NONE, "Awesome"),
 2886    new TypeParameter[0],
 2887    new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]),
 2888    new ReferenceType[0],
 2889    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 2890   
 2891  1 SymbolData sd = new SymbolData("Awesome"); /**Create a continuation and store it in table.*/
 2892  1 sd.setSuperClass(LanguageLevelConverter.symbolTable.get("java.lang.Object"));
 2893  1 LanguageLevelConverter.symbolTable.put("Awesome", sd);
 2894  1 SymbolData result = testLLVisitor.defineSymbolData(cd, "Awesome");
 2895  1 assertFalse("result should not be a continuation.", result.isContinuation());
 2896  1 assertFalse("sd should also no longer be a continuation.", sd.isContinuation());
 2897  1 assertEquals("result and sd should be equal.", sd, result);
 2898   
 2899    // /**Hierarchy should be empty at the end.*/
 2900    // assertEquals("hierarchy should be empty", 0, _hierarchy.size());
 2901   
 2902    /**Check that if the class is already defined, an appropriate error is thrown.*/
 2903  1 assertEquals("Should return null, because it is already in the SymbolTable.", null,
 2904    testLLVisitor.defineSymbolData(cd, "Awesome"));
 2905  1 assertEquals("Length of errors should now be 1.", 1, errors.size());
 2906  1 assertEquals("Error message should be correct.", "The class or interface Awesome has already been defined.",
 2907    errors.get(0).getFirst());
 2908    // assertEquals("hierarchy should be empty.", 0, _hierarchy.size());
 2909   
 2910    }
 2911   
 2912  1 public void test_variableDeclaration2VariableData() {
 2913  1 VariableDeclarator[] d1 = {
 2914    new UninitializedVariableDeclarator(SourceInfo.NONE,
 2915    new PrimitiveType(SourceInfo.NONE, "int"),
 2916    new Word(SourceInfo.NONE, "i")) };
 2917  1 VariableDeclaration vd1 = new VariableDeclaration(SourceInfo.NONE,PUBLIC_MAV, d1);
 2918  1 VariableData[] vdata1 = { new VariableData("i", PUBLIC_MAV, SymbolData.INT_TYPE, false, _sd1) };
 2919   
 2920  1 assertTrue("Should properly recognize a basic VariableDeclaration",
 2921    arrayEquals(vdata1, testLLVisitor._variableDeclaration2VariableData(vd1, _sd1)));
 2922   
 2923  1 VariableDeclarator[] d2 = {
 2924    new UninitializedVariableDeclarator(SourceInfo.NONE,
 2925    new PrimitiveType(SourceInfo.NONE, "int"),
 2926    new Word(SourceInfo.NONE, "i")),
 2927    new InitializedVariableDeclarator(SourceInfo.NONE,
 2928    new PrimitiveType(SourceInfo.NONE, "boolean"),
 2929    new Word(SourceInfo.NONE, "b"),
 2930    new BooleanLiteral(SourceInfo.NONE, true)) };
 2931  1 VariableDeclaration vd2 = new VariableDeclaration(SourceInfo.NONE,PRIVATE_MAV, d2);
 2932  1 VariableData bData = new VariableData("b", PRIVATE_MAV, SymbolData.BOOLEAN_TYPE, true, _sd1);
 2933  1 bData.setHasInitializer(true);
 2934  1 VariableData[] vdata2 = {new VariableData("i", PRIVATE_MAV, SymbolData.INT_TYPE, false, _sd1),
 2935    bData};
 2936   
 2937  1 assertTrue("Should properly recognize a more complicated VariableDeclaration",
 2938    arrayEquals(vdata2, testLLVisitor._variableDeclaration2VariableData(vd2, _sd1)));
 2939   
 2940    //check that if the type cannot be found, no error is thrown.
 2941  1 VariableDeclarator[] d3 = {
 2942    new UninitializedVariableDeclarator(SourceInfo.NONE,
 2943    new ClassOrInterfaceType(SourceInfo.NONE, "LinkedList", new Type[0]),
 2944    new Word(SourceInfo.NONE, "myList"))};
 2945  1 VariableDeclaration vd3 = new VariableDeclaration(SourceInfo.NONE, PRIVATE_MAV, d3);
 2946  1 testLLVisitor._variableDeclaration2VariableData(vd3, _sd1);
 2947  1 assertEquals("There should now be no errors", 0, errors.size());
 2948    // assertEquals("The error message should be correct", "Class or Interface LinkedList not found",
 2949    // errors.get(0).getFirst());
 2950   
 2951    }
 2952   
 2953  1 public void test_addError() {
 2954  1 LinkedList<Pair<String, JExpressionIF>> e = new LinkedList<Pair<String, JExpressionIF>>();
 2955   
 2956  1 NullLiteral nl = new NullLiteral(SourceInfo.NONE);
 2957  1 NullLiteral nl2 = new NullLiteral(SourceInfo.NONE);
 2958   
 2959  1 e.addLast(new Pair<String,JExpressionIF>("Boy, is this an error!", nl));
 2960  1 _addError("Boy, is this an error!", nl);
 2961   
 2962  1 assertTrue("An error should have been added.", _errorAdded);
 2963  1 assertEquals("The errors list should be correct.", e, errors);
 2964   
 2965  1 e.addLast(new Pair<String,JExpressionIF>("Error again!", nl2));
 2966  1 _addError("Error again!", nl2);
 2967   
 2968  1 assertTrue("Another error should have been aded.", _errorAdded);
 2969  1 assertEquals("The new errors list should be correct.", e, errors);
 2970    }
 2971   
 2972  1 public void test_addAndIgnoreError() {
 2973  1 LinkedList<Pair<String, JExpressionIF>> e = new LinkedList<Pair<String, JExpressionIF>>();
 2974   
 2975  1 NullLiteral nl = new NullLiteral(SourceInfo.NONE);
 2976  1 NullLiteral nl2 = new NullLiteral(SourceInfo.NONE);
 2977   
 2978  1 _errorAdded = false;
 2979   
 2980  1 e.addLast(new Pair<String,JExpressionIF>("Nobody pays attention to me!", nl));
 2981  1 _addAndIgnoreError("Nobody pays attention to me!", nl);
 2982   
 2983  1 assertFalse("_errorAdded should be false.", _errorAdded);
 2984  1 assertEquals("The errors list should be correct.", e, errors);
 2985   
 2986  1 e.addLast(new Pair<String,JExpressionIF>("Cellophane, I'm Mr. Cellophane", nl2));
 2987  1 _addAndIgnoreError("Cellophane, I'm Mr. Cellophane", nl2);
 2988   
 2989  1 assertFalse("errorAdded should still be false.", _errorAdded);
 2990  1 assertEquals("The new errors list should be correct.", e, errors);
 2991   
 2992  1 _errorAdded = true;
 2993  1 try {
 2994  1 _addAndIgnoreError("This should throw an exception, because _errorAdded is true.", nl);
 2995  0 assertTrue("An error should have been thrown!", false);
 2996    }
 2997    catch (RuntimeException exc) {
 2998  1 assertEquals("Make sure runtime exception message is correct.",
 2999    "Internal Program Error: _addAndIgnoreError called while _errorAdded was true." +
 3000    " Please report this bug.",
 3001    exc.getMessage());
 3002    }
 3003  1 _errorAdded = false;
 3004    }
 3005   
 3006  1 public void test_checkError() {
 3007  1 _errorAdded = false;
 3008  1 assertFalse("_checkError should return false", _checkError());
 3009   
 3010  1 _errorAdded = true;
 3011  1 assertTrue("_checkError should return true", _checkError());
 3012  1 assertFalse("_checkError should have set _errorAdded to false.", _errorAdded);
 3013    }
 3014   
 3015  1 public void testForClassDefDoFirst() {
 3016  1 ClassDef cd =
 3017    new ClassDef(SourceInfo.NONE, PUBLIC_MAV,
 3018    new Word(SourceInfo.NONE, "Awesome"),
 3019    new TypeParameter[0],
 3020    new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]),
 3021    new ReferenceType[0],
 3022    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3023  1 testLLVisitor.forClassDefDoFirst(cd);
 3024  1 assertEquals("There should be no errors.", 0, errors.size());
 3025  1 testLLVisitor._importedFiles.addLast(new File("Awesome").getAbsolutePath());
 3026  1 testLLVisitor.forClassDefDoFirst(cd);
 3027  1 assertEquals("There should be one error.", 1, errors.size());
 3028  1 assertEquals("The error message should be correct.", "The class Awesome was already imported.",
 3029    errors.get(0).getFirst());
 3030   
 3031  1 ClassDef cd2 = new ClassDef(SourceInfo.NONE, PRIVATE_MAV,
 3032    new Word(SourceInfo.NONE, "privateClass"),
 3033    new TypeParameter[0],
 3034    new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]),
 3035    new ReferenceType[0],
 3036    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3037  1 testLLVisitor.forClassDefDoFirst(cd2);
 3038  1 assertEquals("There should be 2 errors", 2, errors.size());
 3039  1 assertEquals("The 2nd error message should be correct", "Top level classes cannot be private",
 3040    errors.get(1).getFirst());
 3041   
 3042    }
 3043   
 3044  1 public void testForInterfaceDefDoFirst() {
 3045  1 InterfaceDef id = new InterfaceDef(SourceInfo.NONE, PUBLIC_MAV,
 3046    new Word(SourceInfo.NONE, "Awesome"),
 3047    new TypeParameter[0], new ReferenceType[0],
 3048    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3049  1 testLLVisitor.forInterfaceDefDoFirst(id);
 3050  1 assertEquals("There should be no errors.", 0, errors.size());
 3051   
 3052  1 InterfaceDef id2 = new InterfaceDef(SourceInfo.NONE, PRIVATE_MAV,
 3053    new Word(SourceInfo.NONE, "privateinterface"),
 3054    new TypeParameter[0], new ReferenceType[0],
 3055    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3056  1 testLLVisitor.forInterfaceDefDoFirst(id2);
 3057  1 assertEquals("There should be 1 errors", 1, errors.size());
 3058  1 assertEquals("The error message should be correct", "Top level interfaces cannot be private",
 3059    errors.get(0).getFirst());
 3060   
 3061  1 InterfaceDef id3 = new InterfaceDef(SourceInfo.NONE, FINAL_MAV,
 3062    new Word(SourceInfo.NONE, "finalinterface"),
 3063    new TypeParameter[0], new ReferenceType[0],
 3064    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3065  1 testLLVisitor.forInterfaceDefDoFirst(id3);
 3066  1 assertEquals("There should be 2 errors", 2, errors.size());
 3067  1 assertEquals("The error message should be correct", "Interfaces cannot be final", errors.get(1).getFirst());
 3068    }
 3069   
 3070  1 public void testForInnerInterfaceDefDoFirst() {
 3071  1 InterfaceDef id = new InterfaceDef(SourceInfo.NONE, PUBLIC_MAV,
 3072    new Word(SourceInfo.NONE, "Awesome"),
 3073    new TypeParameter[0], new ReferenceType[0],
 3074    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3075  1 id.visit(testLLVisitor);
 3076  1 assertEquals("There should be no errors.", 0, errors.size());
 3077   
 3078  1 InnerInterfaceDef id2 =
 3079    new InnerInterfaceDef(SourceInfo.NONE, FINAL_MAV, new Word(SourceInfo.NONE, "finalinterface"),
 3080    new TypeParameter[0], new ReferenceType[0],
 3081    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3082  1 id2.visit(testLLVisitor);
 3083  1 assertEquals("There should be 1 error", 1, errors.size());
 3084  1 assertEquals("The error message should be correct", "Interfaces cannot be final", errors.get(0).getFirst());
 3085    }
 3086   
 3087  1 public void testForPackageStatementOnly() {
 3088  1 Word[] words = new Word[] {new Word(SourceInfo.NONE, "alpha"),
 3089    new Word(SourceInfo.NONE, "beta")};
 3090  1 CompoundWord cw = new CompoundWord(SourceInfo.NONE, words);
 3091  1 PackageStatement ps = new PackageStatement(SourceInfo.NONE, cw);
 3092  1 testLLVisitor._file = new File("alpha/beta/delta");
 3093  1 testLLVisitor.forPackageStatementOnly(ps);
 3094  1 assertEquals("_package should be set correctly.", "alpha.beta", testLLVisitor._package);
 3095  1 assertEquals("There should be no errors.", 0, errors.size());
 3096  1 testLLVisitor._file = new File("alpha/beta/beta/delta");
 3097  1 testLLVisitor.forPackageStatementOnly(ps);
 3098  1 assertEquals("_package should be set correctly.", "alpha.beta", testLLVisitor._package);
 3099  1 assertEquals("There should be one error.", 1, errors.size());
 3100  1 assertEquals("The error message should be correct.", "The package name must mirror your file's directory.",
 3101    errors.get(0).getFirst());
 3102    }
 3103   
 3104  1 public void testForClassImportStatementOnly() {
 3105   
 3106    //Test one that works
 3107  1 Word[] words = new Word[] { new Word(SourceInfo.NONE, "alpha"), new Word(SourceInfo.NONE, "beta")};
 3108  1 CompoundWord cw = new CompoundWord(SourceInfo.NONE, words);
 3109  1 ClassImportStatement cis = new ClassImportStatement(SourceInfo.NONE, cw);
 3110  1 SymbolData sd = new SymbolData("alpha.beta");
 3111  1 testLLVisitor.forClassImportStatementOnly(cis);
 3112  1 assertTrue("imported files should contain alpha.beta", testLLVisitor._importedFiles.contains("alpha.beta"));
 3113    // continuations should not appear in symbolTable
 3114    // assertEquals("There should be a continuation.", sd, LanguageLevelConverter.symbolTable.get("alpha.beta"));
 3115  1 assertTrue("It should be in continuations.", testLLVisitor.continuations.containsKey("alpha.beta"));
 3116   
 3117    // Test one that should throw an error: Class has already been imported. alpha.beta should now be in the
 3118    // symbolTable, and alpha should be in the list of packages, so this will throw an error
 3119  1 Word[] words2 = new Word[] { new Word(SourceInfo.NONE, "gamma"), new Word(SourceInfo.NONE, "beta")};
 3120  1 CompoundWord cw2 = new CompoundWord(SourceInfo.NONE, words2);
 3121  1 ClassImportStatement cis2 = new ClassImportStatement(SourceInfo.NONE, cw2);
 3122  1 cis2.visit(testLLVisitor);
 3123   
 3124  1 assertEquals("There should be one error", 1, errors.size());
 3125  1 assertEquals("The error message should be correct",
 3126    "The class beta has already been imported.",
 3127    errors.get(0).getFirst());
 3128   
 3129    // Consistent with javac, the following test no longer throws an error.
 3130    // //Test one that should throw an error: Importing a class from the current package
 3131    // testLLVisitor._package = "myPackage";
 3132    // Word[] words3 = new Word[] { new Word(SourceInfo.NONE, "myPackage"), new Word(SourceInfo.NONE, "cookie")};
 3133    // CompoundWord cw3 = new CompoundWord(SourceInfo.NONE, words3);
 3134    // ClassImportStatement cis3 = new ClassImportStatement(SourceInfo.NONE, cw3);
 3135    // cis3.visit(testLLVisitor);
 3136    //
 3137    // assertEquals("There should now be 2 errors", 2, errors.size());
 3138    // assertEquals("The second error message should be correct",
 3139    // "You do not need to import myPackage.cookie. It is in your package so it is already visible",
 3140    // errors.get(1).getFirst());
 3141    }
 3142   
 3143  1 public void testForPackageImportStatementOnly() {
 3144    //Test one that works
 3145  1 Word[] words = new Word[] {new Word(SourceInfo.NONE, "alpha"),
 3146    new Word(SourceInfo.NONE, "beta")};
 3147  1 CompoundWord cw = new CompoundWord(SourceInfo.NONE, words);
 3148  1 PackageImportStatement cis = new PackageImportStatement(SourceInfo.NONE, cw);
 3149  1 SymbolData sd = new SymbolData("alpha.beta");
 3150  1 testLLVisitor.forPackageImportStatementOnly(cis);
 3151  1 assertEquals("There should be no errorrs", 0, errors.size());
 3152  1 assertTrue("Imported Packages should now contain alpha.beta",
 3153    testLLVisitor._importedPackages.contains("alpha.beta"));
 3154   
 3155    //Test one that should not throw an error: Importing a subpackage of the current package
 3156  1 testLLVisitor._package = "myPackage";
 3157  1 Word[] words3 = new Word[] {new Word(SourceInfo.NONE, "myPackage"), new Word(SourceInfo.NONE,
 3158    "cookie")};
 3159  1 CompoundWord cw3 = new CompoundWord(SourceInfo.NONE, words3);
 3160  1 PackageImportStatement pis = new PackageImportStatement(SourceInfo.NONE, cw3);
 3161  1 pis.visit(testLLVisitor);
 3162   
 3163  1 assertEquals("There should be no errors", 0, errors.size());
 3164  1 assertTrue("Imported Packages should now contain myPackage.cookie",
 3165    testLLVisitor._importedPackages.contains("myPackage.cookie"));
 3166   
 3167   
 3168   
 3169    //Test one that should throw an error: Importing the current package
 3170  1 Word[] words2 = new Word[] {new Word(SourceInfo.NONE, "myPackage")};
 3171  1 CompoundWord cw2 = new CompoundWord(SourceInfo.NONE, words2);
 3172  1 PackageImportStatement pis2 = new PackageImportStatement(SourceInfo.NONE, cw2);
 3173  1 pis2.visit(testLLVisitor);
 3174   
 3175  1 assertEquals("There should now be 1 errors", 1, errors.size());
 3176  1 assertEquals("The error message should be correct", "You do not need to import package myPackage." +
 3177    " It is your package so all public classes in it are already visible.", errors.get(0).getFirst());
 3178   
 3179    }
 3180   
 3181  1 public void testForSourceFile() {
 3182  1 ClassDef cd = new ClassDef(SourceInfo.NONE, PUBLIC_MAV, new Word(SourceInfo.NONE, "Awesome"),
 3183    new TypeParameter[0],
 3184    new ClassOrInterfaceType(SourceInfo.NONE, "java.lang.Object", new Type[0]),
 3185    new ReferenceType[0],
 3186    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3187  1 ClassDef cd2 = new ClassDef(SourceInfo.NONE, PUBLIC_MAV, new Word(SourceInfo.NONE, "Gnarly"),
 3188    new TypeParameter[0],
 3189    new ClassOrInterfaceType(SourceInfo.NONE, "Awesome", new Type[0]),
 3190    new ReferenceType[0],
 3191    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3192  1 InterfaceDef id = new InterfaceDef(SourceInfo.NONE, PUBLIC_MAV,
 3193    new Word(SourceInfo.NONE, "NiftyWords"),
 3194    new TypeParameter[0],
 3195    new ReferenceType[0],
 3196    new BracedBody(SourceInfo.NONE, new BodyItemI[0]));
 3197   
 3198  1 SourceFile sf = new SourceFile(SourceInfo.NONE,
 3199    new PackageStatement[0],
 3200    new ImportStatement[0],
 3201    new TypeDefBase[] {cd, cd2, id});
 3202  1 testLLVisitor.forSourceFile(sf);
 3203   
 3204  1 assertTrue("_classesInThisFile should contain the two ClassDefs.",
 3205    testLLVisitor._classesInThisFile.contains("Awesome"));
 3206  1 assertTrue("_classesInThisFile should contain the two ClassDefs.",
 3207    testLLVisitor._classesInThisFile.contains("Gnarly"));
 3208   
 3209  1 assertTrue("_classesInThisFile should contain the InterfaceDef",
 3210    testLLVisitor._classesInThisFile.contains("NiftyWords"));
 3211  1 assertTrue("_classesInThisFile should contain the two ClassDefs.",
 3212    testLLVisitor._classesInThisFile.contains("Awesome"));
 3213  1 assertTrue("_classesInThisFile should contain the two ClassDefs.",
 3214    testLLVisitor._classesInThisFile.contains("Gnarly"));
 3215  1 assertTrue("_classesInThisFile should contain the InterfaceDef",
 3216    testLLVisitor._classesInThisFile.contains("NiftyWords"));
 3217   
 3218    }
 3219   
 3220  1 public void testReferenceType2String() {
 3221    // Try a TypeVariable
 3222  1 TypeVariable tv = new TypeVariable(SourceInfo.NONE, "T");
 3223  1 String[] result = testLLVisitor.referenceType2String(new ReferenceType[] { tv });
 3224  1 assertEquals("There should not be any errors.", 0, errors.size());
 3225  1 assertEquals("Results should have one String.", 1, result.length);
 3226  1 assertEquals("The String should be \"T\".", "T", result[0]);
 3227   
 3228    // Try a ClassOrInterfaceType
 3229  1 ClassOrInterfaceType coit = new ClassOrInterfaceType(SourceInfo.NONE,
 3230    "MyClass",
 3231    new Type[] { new TypeVariable(SourceInfo.NONE, "T"),
 3232    new TypeVariable(SourceInfo.NONE, "U")}
 3233    );
 3234  1 result = testLLVisitor.referenceType2String(new ReferenceType[] { tv, coit });
 3235  1 assertEquals("There should not be any errors.", 0, errors.size());
 3236  1 assertEquals("Results should have two Strings.", 2, result.length);
 3237  1 assertEquals("The first String should be \"T\".", "T", result[0]);
 3238  1 assertEquals("The second String should be \"MyClass\".", "MyClass", result[1]);
 3239   
 3240    // Try a MemberType
 3241  1 MemberType mt = new MemberType(SourceInfo.NONE,
 3242    "MyClass.MyClass2",
 3243    coit,
 3244    new ClassOrInterfaceType(SourceInfo.NONE,
 3245    "MyClass2",
 3246    new Type[0]));
 3247  1 result = testLLVisitor.referenceType2String(new ReferenceType[] { mt });
 3248  1 assertEquals("There should not be any errors.", 0, errors.size());
 3249  1 assertEquals("Results should have one String.", 1, result.length);
 3250  1 assertEquals("The first String should be \"MyClass.MyClass2\".", "MyClass.MyClass2", result[0]);
 3251    }
 3252   
 3253   
 3254  1 public void testExceptionsInSymbolTable() {
 3255   
 3256    // Make sure that exceptions are being added to symbol table
 3257  1 ClassOrInterfaceType exceptionType =
 3258    new ClassOrInterfaceType(SourceInfo.NONE, "java.util.prefs.BackingStoreException", new Type[0]);
 3259  1 ParenthesizedExpressionList expList = new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]);
 3260   
 3261  1 BracedBody bb =
 3262    new BracedBody(SourceInfo.NONE,
 3263    new BodyItemI[] { new ThrowStatement(SourceInfo.NONE,
 3264    new SimpleNamedClassInstantiation(SourceInfo.NONE,
 3265    exceptionType,
 3266    expList))});
 3267  1 bb.visit(testLLVisitor);
 3268  1 assertNotNull("The SymbolTable should have java.util.prefs.BackingStoreException",
 3269    LanguageLevelConverter.symbolTable.get("java.util.prefs.BackingStoreException"));
 3270   
 3271    }
 3272   
 3273  1 public void testShouldBreak() {
 3274    //shift assignment expressions:
 3275  1 LeftShiftAssignmentExpression shift1 =
 3276    new LeftShiftAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3277    new NullLiteral(SourceInfo.NONE));
 3278  1 RightUnsignedShiftAssignmentExpression shift2 =
 3279    new RightUnsignedShiftAssignmentExpression(SourceInfo.NONE,
 3280    new NullLiteral(SourceInfo.NONE),
 3281    new NullLiteral(SourceInfo.NONE));
 3282  1 RightSignedShiftAssignmentExpression shift3 =
 3283    new RightSignedShiftAssignmentExpression(SourceInfo.NONE,
 3284    new NullLiteral(SourceInfo.NONE),
 3285    new NullLiteral(SourceInfo.NONE));
 3286   
 3287   
 3288  1 shift1.visit(testLLVisitor);
 3289  1 assertEquals("Should be no errors", 0, errors.size());
 3290    // assertEquals("error message should be correct",
 3291    // "Shift assignment operators cannot be used at any language level",
 3292    // errors.getLast().getFirst());
 3293   
 3294  1 shift2.visit(testLLVisitor);
 3295  1 assertEquals("Should be no errors", 0, errors.size());
 3296    // assertEquals("error message should be correct",
 3297    // "Shift assignment operators cannot be used at any language level",
 3298    // errors.getLast().getFirst());
 3299   
 3300  1 shift3.visit(testLLVisitor);
 3301  1 assertEquals("Should be no errors", 0, errors.size());
 3302    // assertEquals("error message should be correct",
 3303    // "Shift assignment operators cannot be used at any language level",
 3304    // errors.getLast().getFirst());
 3305   
 3306    //BitwiseAssignmentExpressions
 3307  1 BitwiseAndAssignmentExpression bit1 =
 3308    new BitwiseAndAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3309    new NullLiteral(SourceInfo.NONE));
 3310  1 BitwiseOrAssignmentExpression bit2 =
 3311    new BitwiseOrAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3312    new NullLiteral(SourceInfo.NONE));
 3313  1 BitwiseXorAssignmentExpression bit3 =
 3314    new BitwiseXorAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3315    new NullLiteral(SourceInfo.NONE));
 3316   
 3317  1 bit1.visit(testLLVisitor);
 3318  1 assertEquals("Should be no errors", 0, errors.size());
 3319    // assertEquals("error message should be correct", "Bitwise operators cannot be used at any language level",
 3320    // errors.getLast().getFirst());
 3321   
 3322  1 bit2.visit(testLLVisitor);
 3323  1 assertEquals("Should be no errors", 0, errors.size());
 3324    // assertEquals("error message should be correct", "Bitwise operators cannot be used at any language level",
 3325    // errors.getLast().getFirst());
 3326   
 3327  1 bit3.visit(testLLVisitor);
 3328  1 assertEquals("Should be no errors", 0, errors.size());
 3329    // assertEquals("error message should be correct", "Bitwise operators cannot be used at any language level",
 3330    // errors.getLast().getFirst());
 3331   
 3332    //BitwiseExpressions
 3333  1 BitwiseAndExpression bit4 =
 3334    new BitwiseAndExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3335    new NullLiteral(SourceInfo.NONE));
 3336  1 BitwiseOrExpression bit5 =
 3337    new BitwiseOrExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3338    new NullLiteral(SourceInfo.NONE));
 3339  1 BitwiseXorExpression bit6 =
 3340    new BitwiseXorExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3341    new NullLiteral(SourceInfo.NONE));
 3342  1 BitwiseNotExpression bit7 =
 3343    new BitwiseNotExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE));
 3344   
 3345   
 3346  1 bit4.visit(testLLVisitor);
 3347  1 assertEquals("Should be no errors", 0, errors.size());
 3348    // assertEquals("error message should be correct",
 3349    // "Bitwise and expressions cannot be used at any language level." +
 3350    // " Perhaps you meant to compare two values using regular and (&&)",
 3351    // errors.getLast().getFirst());
 3352   
 3353  1 bit5.visit(testLLVisitor);
 3354  1 assertEquals("Should be no errors", 0, errors.size());
 3355    // assertEquals("error message should be correct",
 3356    // "Bitwise or expressions cannot be used in the functional level." +
 3357    // " Perhaps you meant to compare two values using regular or (||)",
 3358    // errors.getLast().getFirst());
 3359   
 3360  1 bit6.visit(testLLVisitor);
 3361  1 assertEquals("Should be no errors", 0, errors.size());
 3362    // assertEquals("error message should be correct", "Bitwise xor expressions cannot be used at any language level",
 3363    // errors.getLast().getFirst());
 3364   
 3365  1 bit7.visit(testLLVisitor);
 3366  1 assertEquals("Should be no errors", 0, errors.size());
 3367    // assertEquals("error message should be correct",
 3368    // "Bitwise not expressions cannot be used at any language level." +
 3369    // " Perhaps you meant to negate this value using regular not (!)",
 3370    // errors.getLast().getFirst());
 3371   
 3372    //shift binary expressions
 3373  1 LeftShiftExpression shift4 =
 3374    new LeftShiftExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3375    new NullLiteral(SourceInfo.NONE));
 3376  1 RightUnsignedShiftExpression shift5 =
 3377    new RightUnsignedShiftExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3378    new NullLiteral(SourceInfo.NONE));
 3379  1 RightSignedShiftExpression shift6 =
 3380    new RightSignedShiftExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3381    new NullLiteral(SourceInfo.NONE));
 3382   
 3383  1 shift4.visit(testLLVisitor);
 3384  1 assertEquals("Should be no errors", 0, errors.size());
 3385    // assertEquals("error message should be correct", "Bit shifting operators cannot be used at any language level",
 3386    // errors.getLast().getFirst());
 3387   
 3388  1 shift5.visit(testLLVisitor);
 3389  1 assertEquals("Should be no errors", 0, errors.size());
 3390    // assertEquals("error message should be correct", "Bit shifting operators cannot be used at any language level",
 3391    // errors.getLast().getFirst());
 3392   
 3393  1 shift6.visit(testLLVisitor);
 3394  1 assertEquals("Should be no errors", 0, errors.size());
 3395    // assertEquals("error message should be correct", "Bit shifting operators cannot be used at any language level",
 3396    // errors.getLast().getFirst());
 3397   
 3398    //empty expression
 3399  1 EmptyExpression e = new EmptyExpression(SourceInfo.NONE);
 3400  1 e.visit(testLLVisitor);
 3401  1 assertEquals("Should be 1 error", 1, errors.size());
 3402  1 assertEquals("Error message should be correct", "You appear to be missing an expression here",
 3403    errors.getLast().getFirst());
 3404   
 3405    //noop expression
 3406  1 NoOpExpression noop =
 3407    new NoOpExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE),
 3408    new NullLiteral(SourceInfo.NONE));
 3409  1 noop.visit(testLLVisitor);
 3410  1 assertEquals("Should be 2 errors", 2, errors.size());
 3411  1 assertEquals("Error message should be correct", "You are missing a binary operator here",
 3412    errors.getLast().getFirst());
 3413    }
 3414   
 3415  1 public void testIsConstructor() {
 3416  1 MethodData constr =
 3417    new MethodData("monkey", PUBLIC_MAV, new TypeParameter[0], _sd1, new VariableData[0], new String[0], _sd1,
 3418    new NullLiteral(SourceInfo.NONE));
 3419  1 MethodData notRightOuter =
 3420    new MethodData("monkey", PUBLIC_MAV, new TypeParameter[0], _sd1, new VariableData[0], new String[0], _sd2,
 3421    new NullLiteral(SourceInfo.NONE));
 3422  1 _sd2.setOuterData(_sd1);
 3423  1 _sd1.addInnerClass(_sd2);
 3424  1 MethodData notRightName =
 3425    new MethodData("chimp", PUBLIC_MAV, new TypeParameter[0], _sd1, new VariableData[0], new String[0], _sd1,
 3426    new NullLiteral(SourceInfo.NONE));
 3427  1 MethodData notRightReturnType =
 3428    new MethodData("monkey", PUBLIC_MAV, new TypeParameter[0], _sd2, new VariableData[0], new String[0], _sd1,
 3429    new NullLiteral(SourceInfo.NONE));
 3430   
 3431    //try one that works
 3432  1 assertTrue(testLLVisitor.isConstructor(constr));
 3433   
 3434    //wrong outer
 3435  1 assertFalse(testLLVisitor.isConstructor(notRightOuter));
 3436   
 3437    //wrong name
 3438  1 assertFalse(testLLVisitor.isConstructor(notRightName));
 3439   
 3440    //wrong return type
 3441  1 assertFalse(testLLVisitor.isConstructor(notRightReturnType));
 3442   
 3443    //not a method data
 3444  1 assertFalse(testLLVisitor.isConstructor(_sd1));
 3445    }
 3446    }
 3447    }