001    /*BEGIN_COPYRIGHT_BLOCK
002     *
003     * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
004     * All rights reserved.
005     * 
006     * Redistribution and use in source and binary forms, with or without
007     * modification, are permitted provided that the following conditions are met:
008     *    * Redistributions of source code must retain the above copyright
009     *      notice, this list of conditions and the following disclaimer.
010     *    * Redistributions in binary form must reproduce the above copyright
011     *      notice, this list of conditions and the following disclaimer in the
012     *      documentation and/or other materials provided with the distribution.
013     *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014     *      names of its contributors may be used to endorse or promote products
015     *      derived from this software without specific prior written permission.
016     * 
017     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020     * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026     * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028     *
029     * This software is Open Source Initiative approved Open Source Software.
030     * Open Source Initative Approved is a trademark of the Open Source Initiative.
031     * 
032     * This file is part of DrJava.  Download the current version of this project
033     * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034     * 
035     * END_COPYRIGHT_BLOCK*/
036    
037    package edu.rice.cs.javalanglevels;
038    
039    import org.objectweb.asm.*;
040    import edu.rice.cs.javalanglevels.tree.*;
041    import edu.rice.cs.javalanglevels.tree.Type; // resolve ambiguity
042    import edu.rice.cs.javalanglevels.parser.JExprParser;
043    import edu.rice.cs.javalanglevels.parser.ParseException;
044    import edu.rice.cs.javalanglevels.util.Log;
045    import edu.rice.cs.javalanglevels.util.Utilities;
046    import java.util.*;
047    import java.io.*;
048    import edu.rice.cs.plt.reflect.JavaVersion;
049    import edu.rice.cs.plt.iter.*;
050    import edu.rice.cs.plt.io.IOUtil;
051    
052    import junit.framework.TestCase;
053    
054    /** Top-level Language Level Visitor that implements the constraint checking and symbol table building that is common to
055      * first pass processing for the Functional and FullJava levels.  There are two major complications in performing this
056      * pass.  First, references to symbols appear in the signatures of type (class/interface) definitions that have not yet
057      * been defined.  In the symbol table, the binding of these references must be deferred until a fixup list is executed
058      * after the first pass visit has finished.  This visitor and its descendants maintain a FixUp list for this purpose.
059      * Second, the loading of signature information into the symbol table (called "resolving" in this documentation) is
060      * deferred for some symbols.  A dummy entry called a "continuation" is created in the symbol table for each such 
061      * symbol.  
062      */
063    public class LanguageLevelVisitor extends JExpressionIFPrunableDepthFirstVisitor {
064      
065      public static final ModifiersAndVisibility PUBLIC_MAV = 
066        new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
067      public static final ModifiersAndVisibility PROTECTED_MAV = 
068        new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
069      public static final ModifiersAndVisibility PRIVATE_MAV = 
070        new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
071      public static final ModifiersAndVisibility PACKAGE_MAV = 
072        new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
073      public static final ModifiersAndVisibility FINAL_MAV = 
074        new ModifiersAndVisibility(SourceInfo.NONE, new String[]{"final"});
075        
076      /** Errors we have encountered during this pass: string is the text of the error, JExpressionIF is the part of
077        * the AST where the error occurs. */
078      protected static LinkedList<Pair<String, JExpressionIF>> errors;
079      
080      /** Stores the classes we have referenced, and all their information, once they are resolved.  Bound to static field
081        * LanguageLevelConverter.symboltable. */
082      public final Symboltable symbolTable;
083      
084      /** A table of the names of symbols for which dummy symbol entries (continuations) have been created and resolution 
085        * has been deferred.  In some cases (symbols subsequently defined in a file being converted), resolution occurs 
086        * during execution.  TODO: make this field dynamic. */
087      static Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations;
088      
089      /** A table of the commands to be executed after this visitation is complete; these commands fill in missing objects
090        * in the symbolTable (which were not available at the time the containing object was constructed.
091        * TODO: make this field dynamic. */
092      static LinkedList<Command> fixUps;
093    
094      // TODO: !!! This field appears vestigal; it does not appear to affect execution.  Eliminate it
095      /* A list of other files that are being visited.  If the SourceFile is not null, then the source file was
096       * visited as opposed to the class file.  This info is used by LanguageLevelConverter in DrJava.
097       * We keep the LLV rather than the file, because the LLV has a file, and we need some other information
098       * stored in the LLV to properly look up the file.
099       */
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      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        _file = file;
153        _package = packageName;
154        _enclosingClassName = enclosingClassName;
155        if (_enclosingClassName != null && _enclosingClassName.startsWith("null")) assert false;
156        _importedFiles = importedFiles;
157        _importedPackages = importedPackages;
158        _classesInThisFile = classesInThisFile;
159    //    _innerClassesInThisBody = new HashSet<String>();
160        this.continuations = continuations;
161        this.fixUps = fixUps;
162        _genericTypes = genericTypes;
163        
164        symbolTable = LanguageLevelConverter.symbolTable;
165        
166        assert fixUps != null;
167        assert _genericTypes != null;
168        
169        // Ensure that the imported packages include "java.lang" 
170        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        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      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        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      protected void _resetNonStaticFields() {
197        _file = new File("");
198        _enclosingClassName = null;
199        _package = "";
200        _importedFiles = new LinkedList<String>();
201        _importedPackages = new LinkedList<String>();
202      }
203      
204      /** @return the accessor name corresponding to given field name. */
205      public static String getFieldAccessorName(String name) { return name; }
206      
207      /**@return the source file*/
208      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      protected boolean isConstructor(Data d) {
214        if ( !(d instanceof MethodData) ) return false;
215        MethodData md = (MethodData) d;
216        SymbolData rt = md.getReturnType();
217        SymbolData sd = md.getSymbolData();  // if this is a constructor, sd must be a defined symbol
218        
219        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      public LanguageLevelVisitor newClassBodyVisitor(SymbolData anonSD, String anonName) {
226        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      public static String getUnqualifiedClassName(String className) { 
233        int lastIndexOfDot = className.lastIndexOf('.');
234        if (lastIndexOfDot != -1) {
235          className = className.substring(lastIndexOfDot + 1);
236        }
237        int lastIndexOfDollar = className.lastIndexOf('$');
238        if (lastIndexOfDollar != -1) {
239          className = className.substring(lastIndexOfDollar + 1);
240        }
241        // Remove any leading numbers  TODO: why do this?  If we encounter a 
242        while (className.length() > 0 && Character.isDigit(className.charAt(0))) { 
243          className = className.substring(1, className.length());
244        }
245        return className;
246      }
247      
248      /** Convert the ReferenceType[] to a String[] with the names of the ReferenceTypes. */
249      protected static String[] referenceType2String(ReferenceType[] rts) {
250        String[] throwStrings = new String[rts.length];
251        for (int i = 0; i < throwStrings.length; i++) {
252          throwStrings[i] = rts[i].getName();
253        }
254        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      public static boolean isJavaLibraryClass(String className) {
267        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      public static boolean isDuplicateVariableData(LinkedList<VariableData> vds, VariableData toInsert) {
281        for (int i = 0; i<vds.size(); i++) {
282          VariableData temp = vds.get(i);
283          if (temp.getName().equals(toInsert.getName())) {
284            return true;
285          }
286        }
287        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      public ArrayData defineArraySymbolData(SymbolData eltSd, LanguageLevelVisitor llv, SourceInfo si) {
295        ArrayData arraySd = new ArrayData(eltSd, llv, si);  // sets _ isContinuation to false! 
296    //    System.err.println("##### Defining the array symbol " + arraySd.getName());
297        symbolTable.put(arraySd.getName(), arraySd);
298        return arraySd;
299      }
300      
301      /* Convenience method used in testing. */ 
302      private SymbolData getArraySymbolData(String eltClassName, SourceInfo si, boolean addError, boolean checkImports) {
303        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      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        SymbolData eltSD =  getSymbolData(eltClassName, si, addError, checkImports/*, classesInThisFile*/);
319        if (eltSD != null) {
320    //      if (eltSD.getName().equals("java.lang.String")) System.err.println("java.lang.String FOUND");
321          SymbolData sd = symbolTable.get(eltSD.getName() + "[]");  // Look up fully qualified name
322          if (sd != null) return sd;
323          else return defineArraySymbolData(eltSD, this, si /*, classesInThisFile*/);
324        }
325        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      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        SymbolData eltSD = getQualifiedSymbolData(eltClassName, si, resolve, fromClassFile, true /*, classesInThisFile*/);
341        if (eltSD != null) {
342          SymbolData sd = symbolTable.get(eltSD.getName() + "[]");  // Look up fully qualified name
343          if (sd != null) return sd;
344          else return defineArraySymbolData(eltSD, this, si /*, classesInThisFile*/);
345        }
346        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      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        SymbolData sd = symbolTable.get(qualifiedClassName);
364        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        String qualifiedClassNameWithSlashes = 
375          qualifiedClassName.replace('.', System.getProperty("file.separator").charAt(0));
376        File _fileParent = _file.getParentFile();
377        // Create var that is eventually set to root of package (for _file)
378        String programRoot = (_fileParent == null) ? "" : _fileParent.getAbsolutePath();  
379        assert (programRoot != null); // parent != null => parent exists.
380        
381        final String path;  // The expected path name of the class file (less .class) for qualifiedClassName
382    
383        if (programRoot.length() > 0) {      
384          String packageWithSlashes = _package.replace('.', System.getProperty("file.separator").charAt(0));
385          // Get index of slash preceding first char of package name
386          int indexOfPackage = programRoot.lastIndexOf(packageWithSlashes); 
387          if (indexOfPackage < 0) path = qualifiedClassName;
388          else {
389            programRoot = programRoot.substring(0, indexOfPackage);
390            path = programRoot + System.getProperty("file.separator") + qualifiedClassNameWithSlashes;
391          }
392        }
393        else {
394          path = qualifiedClassNameWithSlashes;  // Using file system root for programRoot
395        }
396        
397        String dirPath; /* the expected directory of the file we're trying to resolve */
398        String newPackage = ""; /* the package of the file we're trying to resolve */
399        int lastSlashIndex = qualifiedClassNameWithSlashes.lastIndexOf(System.getProperty("file.separator"));
400        if (lastSlashIndex != -1) {
401          String newPackageWithSlashes = qualifiedClassNameWithSlashes.substring(0, lastSlashIndex);
402          dirPath = programRoot + System.getProperty("file.separator") + newPackageWithSlashes;
403          newPackage = newPackageWithSlashes.replace(System.getProperty("file.separator").charAt(0), '.');
404        }
405        else {
406          int lastPathSlashIndex = path.lastIndexOf(System.getProperty("file.separator"));
407          if (lastPathSlashIndex != -1) dirPath = path.substring(0, lastPathSlashIndex);
408          else dirPath = "";
409        }
410        
411        // Find class file and matching source file for qualifiedClassName -- if they exist
412        
413        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        File[] sourceFiles = new File(dirPath).listFiles(new FileFilter() {
417          public boolean accept(File f) {
418            try {
419              f = f.getCanonicalFile();
420              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            catch (IOException e) { return false; }
427          }});
428        
429        File sourceFile = null; // sourceFile is either null or an existing file
430        if (sourceFiles != null) {
431          long mostRecentTime = 0;
432          for (File f : sourceFiles) {
433            long currentLastModified = f.lastModified();
434            if (f.exists() && mostRecentTime < currentLastModified) {
435              mostRecentTime = currentLastModified;
436              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        if (sourceFile != null) {
450          // First see if we even need to resolve this class. If not, create a continuation and return it.
451          if (! resolve) { 
452            assert sd == null;
453            sd = makeContinuation(si, qualifiedClassName); // create a continuation for qualifiedClassName; defer resolution
454            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          long classModTime = classFile.lastModified();
464          if (classModTime == 0L) return null;  // if classFile does not exist, return
465          
466          if (sourceFile.lastModified() > classModTime) { // the class file is out of date
467            if (addError) {
468              _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            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        if (classFile.exists()) {
479          // read this classfile, create the SymbolData and return it
480         _log.log("Reading classFile " + qualifiedClassName);
481          sd = LanguageLevelConverter._classFile2SymbolData(qualifiedClassName, programRoot);
482          if (sd == null) {
483            if (addError) {
484              _addAndIgnoreError("File " + classFile + " is not a valid class file.",  new NullLiteral(si));
485            }
486            return null;
487          }
488          _log.log("Returning symbol constructed by loading class file");
489          return sd;
490        }
491        return SymbolData.NOT_FOUND;
492      }
493     
494      /** Resolves the continuation cont. */
495      public SymbolData resolveSymbol(SourceInfo si, SymbolData cont) { 
496    //    System.err.println("***ALARM*** resolveSymbol called for '" + cont + "'");
497        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      public SymbolData getSymbolData(String className, SourceInfo si) {
506        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      protected SymbolData getSymbolData(String className, SourceInfo si, boolean addError) {
516        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      protected SymbolData getSymbolData(String className, SourceInfo si, boolean addError, boolean checkImports) {
525        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      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        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        SymbolData existingSD = getQualifiedSymbolData(className, si, false, false, addError);
572        if (existingSD != null) return existingSD;
573            
574        if (className.endsWith("[]")) { // className refers to an array type
575          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          return getArraySymbolData(/* file, pkg, importedFiles, importedPackages, enclosingClassName, */
578                                    eltClassName, si, addError, checkImports);
579        }
580        
581        // Try matching the className against current package
582        String qualClassName = getQualifiedClassName(pkg, className);  // TODO: make this work for an inner class
583        existingSD = getQualifiedSymbolData(qualClassName, si);
584        if (existingSD != null) return existingSD; 
585        
586        // Check for relative inner class reference
587        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          SymbolData enclosingSD = getQualifiedSymbolData(enclosingClassName, si);
592          if (enclosingSD != null) {
593            SymbolData sd = enclosingSD.getInnerClassOrInterface(className);
594            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        if (className.indexOf('.') == -1) { // className has no qualification; may be imported
606        
607          // Check if the className's package was imported.
608          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            Iterator<String> iter = importedFiles.iterator();
614            while (iter.hasNext()) {
615              String s = iter.next();
616              if (s.endsWith(className)) {
617                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                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          SymbolData resultSD = null;
628          assert importedPackages.contains("java.lang");
629    //      assert symbolTable.containsKey("java.lang.Object");
630          for (String prefix: importedPackages) {
631            String s = prefix + '.' + className;
632    //        if (className.equals("java.lang.Object")) System.err.println("***ALARM*** Looking up: " + s);
633            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            if (sD != null) {
637              if (resultSD == null || resultSD.equals(sD)) resultSD = sD;
638              else {  // sD is NOT the first match; flag an error
639                if (addError) {  // TODO: why do we suppress this error in some cases?
640                  _addAndIgnoreError("The class name " + qualClassName + " is ambiguous.  It could be " + resultSD.getName()
641                                       + " or " + sD.getName(), new NullLiteral(si));
642                  return null;
643                }
644              }
645            }
646          }
647          if (resultSD != null) return resultSD;
648          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        int indexOfNextDot = 0;
654    //    int indexOfNextDollar = className.indexOf("$");   // '$' only appears as separator for inner class names  
655        SymbolData sd;
656        int length = className.length();
657        while (indexOfNextDot != length) {
658          indexOfNextDot = className.indexOf('.', indexOfNextDot + 1);
659          if (indexOfNextDot == -1) { indexOfNextDot = length; }
660          String prefix = className.substring(0, indexOfNextDot);
661          
662          /* We want to try finding each prefix in the symbol table; the decomposition is putative. */
663          sd = getQualifiedSymbolData(prefix, si, false, false, false);
664          if (sd != null && sd != SymbolData.AMBIGUOUS_REFERENCE) { // prefix matches an existing symbol
665            String outerClassName = prefix;
666            String innerClassName = "";
667            if (indexOfNextDot != length) {
668              SymbolData outerClassSD = sd;
669              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              sd = outerClassSD.getInnerClassOrInterface(innerClassName);
673              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        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      protected SymbolData getSymbolData(TypeData lhs, String name, SourceInfo si, boolean addError) {
693        //arguments we do not need to pass in
694        boolean checkImports = false;
695        
696        if (lhs == null) return null;
697        
698        else if (lhs instanceof PackageData) {
699          String qualClassName = lhs.getName() + '.' + name;
700          return getQualifiedSymbolData(qualClassName, si, false, false, addError);
701        }
702        
703        else { // if (lhs instanceof SymbolData) {
704          SymbolData result = lhs.getInnerClassOrInterface(name);
705          if (result == SymbolData.AMBIGUOUS_REFERENCE) {
706            if (addError) { _addAndIgnoreError("Ambiguous reference to class or interface " + name, new NullLiteral(si)); }
707            return null;
708          }
709          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      protected SymbolData getQualifiedSymbolData(String qualClassName) {
716        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      protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si) {
722        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      protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si, boolean resolve) {
729        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      protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si, boolean resolve, boolean fromClassFile, 
746                                               boolean addError) {
747        assert qualClassName != null;
748    //    if (qualClassName.startsWith("RefInnerClassCrazy")) 
749    //      System.err.println("ALARM: getQualifiedSymbolData called for '" + qualClassName + "'");
750    //    
751        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        assert (qualClassName != null && ! qualClassName.equals(""));
757        
758        // Check for primitive types.
759    //    System.err.println("***** Checking for primitive symbol " + qualClassName);
760        SymbolData sd = LanguageLevelConverter._getPrimitiveSymbolData(qualClassName);
761        if (sd != null) { 
762    //      System.err.println("***** Matched for primitive symbol " + sd);
763          return sd; 
764        }
765        
766        // Check for references to generic types  (only happens in FullJava code)
767        // TODO !!! Does not handle forward references
768        String name = getUnqualifiedClassName(qualClassName);
769        if (_genericTypes.containsKey(name)) {
770    //      Utilities.show("Return type " + name + " is generic and value is " + _genericTypes.get(name));
771          return _genericTypes.get(name);
772        }
773        
774        // Check for already defined types
775        SymbolData existingSD = symbolTable.get(qualClassName);
776        if (existingSD != null && (! resolve || ! existingSD.isContinuation())) return existingSD;
777        
778        // Check for array types.
779        if (qualClassName.endsWith("[]"))
780          return _getQualifiedArraySymbolData(qualClassName.substring(0, qualClassName.length() - 2), si, resolve, 
781                                           fromClassFile);
782        // Check for generic type variables
783        SymbolData genericBinding = _genericTypes.get(qualClassName);
784        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        if (isJavaLibraryClass(qualClassName)) {
788          _log.log("Calling  _classFile2SymbolData");
789          SymbolData cfSD = LanguageLevelConverter._classFile2SymbolData(qualClassName, null);
790          if (! qualClassName.startsWith("java.") && ! qualClassName.startsWith("sun."))
791    //        System.err.println("Defining class file symbol " + qualClassName);
792          assert cfSD == null || symbolTable.contains(cfSD);
793          return cfSD;
794        }
795        
796        if (_classesInThisFile.contains(qualClassName))  // Make continuation for top level class not yet parsed in this file
797          return makeContinuation(si, qualClassName);
798        
799        // If performing post-visit resolution, read the signature info for this symbol from a class file
800        if (resolve) {  // Look for up-to-date class file
801          SymbolData newSd = _getSymbolDataFromFileSystem(qualClassName, si, true, true);  // resolve, addError = true
802          if (newSd != null && newSd != SymbolData.NOT_FOUND) {
803            _log.log("Returning " + sd + " from file system");
804            return newSd;
805          }
806          else {
807    //        System.err.println("********* ALARM: The class " + qualClassName + " was not found.  Symbol = " + newSd);
808            _addAndIgnoreError("The class " + qualClassName + " was not found.", new NullLiteral(si));
809            assert false;
810          }
811        }
812        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      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      public static String getQualifiedClassName(String pkg, String className) {
829    //    if (className.equals("java")) throw new RuntimeException("BOGUS getQualifiedClassName call on 'java'");
830        if (! pkg.equals("") && ! className.startsWith(pkg)) return pkg + '.' + className;
831        else return className;
832      }
833      
834      // Creates a continuation for an inner class/interface; qualifiedTypeName is known to exist
835      protected SymbolData addInnerSymbolData(SourceInfo si, String qualifiedTypeName, Data enclosing) {
836        SymbolData sd = makeContinuation(si, qualifiedTypeName); // create continuation
837        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        enclosing.getSymbolData().addInnerClass(sd);
840        sd.setOuterData(enclosingSD);
841        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      protected SymbolData makeContinuation(SourceInfo si, String qualClassName) {
849    //    System.err.println("***** makeContinuation called for " + qualClassName);
850        if (qualClassName.equals("D.E")) assert false;
851        SymbolData sd = new SymbolData(qualClassName);  // create a continuation
852        symbolTable.put(qualClassName, sd);
853        continuations.put(qualClassName, new Triple<SourceInfo, LanguageLevelVisitor, SymbolData>(si, this, sd));
854    //    System.err.println("Created continuation for " + qualClassName + " at LLV:1124");
855        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      protected SymbolData _lookupTypeFromWithinClass(ReferenceType rt, String qualifiedClassName) {
862        // Perform a raw lookup assuming name of rt is fully qualified
863        String rtName = rt.getName();
864        SourceInfo si = rt.getSourceInfo();
865        // Perform a lookup at top level.
866        assert _importedPackages.contains("java.lang");
867        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        if (sD == null && qualifiedClassName != null) { // check if rt refers to an inner type of qualifiedClassName
871          SymbolData sd = getQualifiedSymbolData(qualifiedClassName, SourceInfo.NONE);
872          sD = sd.getInnerClassOrInterface(rtName);
873          assert sD == getQualifiedSymbolData(qualifiedClassName + '.' + rtName, SourceInfo.NONE);
874        }  // The following case should be unncessary because getInnerClassOrInterface should look back through enclosing classes
875        else if (qualifiedClassName != null) {
876          int prefixLen = qualifiedClassName.lastIndexOf('.');
877          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            String qualifyingBase = qualifiedClassName.substring(0, qualifiedClassName.lastIndexOf('.'));
880            SymbolData outerSD = getQualifiedSymbolData(qualifyingBase, SourceInfo.NONE);
881            if (outerSD != null) {
882              sD = outerSD.getInnerClassOrInterface(rtName);
883              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        return sD;
889      }
890      
891      /** Overloaded signature for defineSymbolData.  Passes _enclosingClassName for enclosingClassName and
892        * _classesInThisFile for classesInThisFile */
893       protected SymbolData defineSymbolData(TypeDefBase typeDefBase, final String qualifiedTypeName) {
894         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      protected SymbolData defineSymbolData(final TypeDefBase typeDefBase, final String qualifiedTypeName,
907                                            final String enclosingClassName /*, final HashSet<String> classesInThisFile*/) {
908        assert (typeDefBase instanceof InterfaceDef) || (typeDefBase instanceof ClassDef);
909        assert ! qualifiedTypeName.startsWith("null.");
910        String name = qualifiedTypeName;  // may be an interface
911        SymbolData contSd = symbolTable.get(qualifiedTypeName);
912    //    System.err.println("In defineSymbolData call for " + qualifiedTypeName + ", contSd = " + contSd);
913        if (contSd != null && ! contSd.isContinuation()) {
914          _addAndIgnoreError("The class or interface " + name + " has already been defined.", typeDefBase);
915          return null;
916        }
917        // If no continuation exists, create a SymbolData for this definition
918        final SymbolData sd = (contSd == null) ? new SymbolData(qualifiedTypeName) : contSd;
919        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        sd.setIsContinuation(false);
927        //Set the package to be the current package
928        sd.setPackage(_package);
929        // Set the MAV and type parameters (the latter are not used currently)
930        sd.setMav(typeDefBase.getMav());
931        sd.setTypeParameters(typeDefBase.getTypeParameters());
932        
933        // Create the LinkedList for the SymbolDatas of the interfaces
934        final ArrayList<SymbolData> interfaces = new ArrayList<SymbolData>();
935        
936        // Get or create SymbolDatas for the interfaces
937        ReferenceType[] rts = typeDefBase.getInterfaces();
938        for (int i = 0; i < rts.length; i++) {
939          final ReferenceType rt = rts[i];
940          final String rtName = rt.getName();
941          boolean forwardRef = false;
942          SymbolData iD = _lookupTypeFromWithinClass(rt, enclosingClassName);
943          if (iD != null && ! iD.isContinuation() && ! iD.isInterface()) {
944            _addAndIgnoreError("The symbol " + rtName + " is not an interface", typeDefBase);
945          }
946          if (iD == null || iD.isContinuation())  { // create a dummy symbol pending fixUp TODO: is this necessary?
947            iD = new SymbolData(rtName);
948            forwardRef = true;
949          }
950          
951          interfaces.add(iD);                     
952          if (forwardRef) { 
953            // create a fixup for this interface slot
954            final int j = i;
955            Command fixUp = new Command() {
956              public void execute() {
957                SymbolData newID = _lookupTypeFromWithinClass(rt, enclosingClassName);
958                if (newID == null) _addAndIgnoreError("The symbol " + rtName + " is not defined", typeDefBase);
959                else if (! newID.isInterface()) 
960                  _addAndIgnoreError("The symbol " + rtName + " is not an interface", typeDefBase);
961                interfaces.set(j, newID);
962                sd.addEnclosingData(newID);
963              }
964            };
965            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        sd.setInterfaces(interfaces);
972         
973        // Create SymbolData variable for superclass
974        SymbolData superSD = null;
975        
976        // Get or create the SymbolData for the superclass/interface; setInterface and setSuperClass
977        
978        if (typeDefBase instanceof InterfaceDef) {
979          // set Object as the super class of this, so that it will know it implements Object's methods.
980          SymbolData objectSD = getSymbolData("java.lang.Object", typeDefBase.getSourceInfo(), false);
981          sd.setInterface(true);
982          sd.setSuperClass(objectSD);
983        }
984        
985        else if (typeDefBase instanceof ClassDef) {
986          sd.setInterface(false);
987          ClassDef cd = (ClassDef) typeDefBase;
988          final ReferenceType rt = cd.getSuperclass();
989          superSD = _lookupTypeFromWithinClass(rt, enclosingClassName);    
990          
991          if (superSD != null) sd.setSuperClass(superSD);
992          else {
993            Command fixUp = new Command() {
994              public void execute() { 
995                SymbolData newSuperSD = _lookupTypeFromWithinClass(rt, enclosingClassName);
996                if (newSuperSD == null)
997                  _addAndIgnoreError("The class " + sd + " has an undefined superclass " + rt, typeDefBase);
998                else  // TODO: Does not check that newSuperSD is not an interace  
999                  sd.setSuperClass(newSuperSD); 
1000              }
1001            };
1002            fixUps.add(fixUp);
1003          }
1004        }
1005    
1006    
1007        // Remove symbol name from continuation table.
1008        _log.log("REMOVING continuation " + qualifiedTypeName);
1009        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        if (! sd.isInterface()) { LanguageLevelConverter._newSDs.put(sd, this); }
1013        
1014        _classesInThisFile.remove(qualifiedTypeName);  // a no-op if qualifiedClassName is an inner class
1015        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      protected SymbolData defineInnerSymbolData(TypeDefBase typeDefBase, String relName, String qualifiedTypeName, 
1026                                                 Data enclosing) {
1027        assert (enclosing instanceof SymbolData) || (enclosing instanceof MethodData);
1028        /* IMPORTANT: this is defineSymbolData for inner classes! */
1029    
1030        SymbolData sd = defineSymbolData(typeDefBase, qualifiedTypeName /*, _classesInThisFile*/); 
1031    //    if (sd == null) System.err.println("defineSymbolData failed for " + qualifiedTypeName);
1032        assert sd != null;
1033        // Set fields of sd that are required for innerSymbols
1034    
1035        sd.setOuterData(enclosing);
1036        
1037        if (sd.isInterface()) {
1038    //      assert enclosing instanceof SymbolData;
1039    //      assert enclosing.getName().equals(_enclosingClassName):
1040          ((SymbolData) enclosing).addInnerInterface(sd); 
1041        }
1042        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          assert enclosing instanceof MethodData;
1048          SymbolData enclosingClassSD = getQualifiedSymbolData(_enclosingClassName);
1049          assert enclosingClassSD != null;
1050          enclosingClassSD.addInnerClass(sd);
1051          enclosing.addInnerClass(sd);  // adds innerClass to list for the enclosing MethodData 
1052        }
1053        else {
1054          // sd is a non-local inner class
1055          assert enclosing.getName().equals(_enclosingClassName);
1056          enclosing.addInnerClass(sd);
1057    //    _innerClassesInThisBody.remove(sd);  // a no-op if _innerClassesInThisBody is empty
1058        }
1059        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      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        final SourceInfo si = anonInst.getSourceInfo();
1074        // Create a SymbolData for this definition
1075        final SymbolData sd = new SymbolData(qualifiedAnonName);
1076        symbolTable.put(qualifiedAnonName, sd);
1077        
1078        // Make this SymbolData as a non-continuation
1079        sd.setIsContinuation(false);
1080        //Set the package to be the current package
1081        sd.setPackage(_package);
1082        
1083    //    sd.setMav(anonInst.getMav());  // What is Mav for anonymous class?
1084    //    sd.setTypeParameters(anonInst.getTypeParameters()); 
1085        
1086        if (_enclosingClassName != null) {
1087          SymbolData enclosingSD = getQualifiedSymbolData(_enclosingClassName, SourceInfo.NONE);
1088          assert (enclosingSD != null); 
1089          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          sd.setOuterData(enclosingSD);
1096    
1097        }
1098            
1099        SymbolData superSD = getSymbolData(superName, anonInst.getSourceInfo());
1100            
1101        if (superSD != null) {
1102          if (superSD.isInterface()) {
1103            sd.setSuperClass(getQualifiedSymbolData("java.lang.Object", si));
1104            sd.setInterfaces(new ArrayList<SymbolData>(Arrays.asList(new SymbolData[] { superSD })));
1105          }
1106          else sd.setSuperClass(superSD);  //  By default sd.getInterfaces() == new ArrayList<SymbolData>()
1107        }
1108        else {
1109          // Create a fixup
1110          Command fixUp = new Command() {
1111            public void execute() { 
1112              SymbolData superSD = getSymbolData(superName, si);
1113              if (superSD == null) 
1114                _addAndIgnoreError("The class/interface " + superName + " was not found.",  anonInst);
1115              else if (superSD.isInterface()) {
1116                sd.setSuperClass(getQualifiedSymbolData("java.lang.Object", si));
1117                sd.setInterfaces(new ArrayList<SymbolData>(Arrays.asList(new SymbolData[] { superSD })));
1118              }                        
1119              else sd.setSuperClass(superSD);  //  By default sd.getInterfaces() == new ArrayList<SymbolData>()
1120            }
1121          };
1122          fixUps.add(fixUp);
1123        }
1124        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      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      protected VariableData[] formalParameters2VariableData(FormalParameter[] fps, SymbolData enclosing) {
1140        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        final VariableData[] varData = new VariableData[fps.length];
1146        final String enclosingClassName = enclosing.getName();
1147        
1148        String[] mav = getFormalParameterMav(enclosing);
1149            
1150        for (int i = 0; i < fps.length; i++) {
1151          VariableDeclarator vd = fps[i].getDeclarator();
1152          String name = vd.getName().getText();  // getName returns a Word
1153         
1154          Type type = vd.getType();
1155          final String typeName = type.getName();
1156    //      if (name.equals("myArray")) 
1157    //        System.err.println("*** 2Var called for var " + name + " type = " + typeName);
1158          final SourceInfo si = type.getSourceInfo();
1159          // Note: typeName CANNOT be a local type; no such type is in scope
1160          SymbolData sd = _identifyType(typeName, si, enclosingClassName);
1161    
1162          varData[i] = 
1163            new VariableData(name, new ModifiersAndVisibility(SourceInfo.NONE, mav), sd, true, enclosing);
1164          
1165          assert ! varData[i].isPrivate();
1166          
1167          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            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            varData[j].setType(new SymbolData(typeName));
1173            Command fixUp = new Command() {
1174              public void execute() { 
1175                SymbolData newSd = _identifyType(typeName, si, enclosingClassName);
1176                if (newSd == null || newSd == SymbolData.NOT_FOUND) 
1177                  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                if (newSd != null) varData[j].setType(newSd);
1180              }
1181            };
1182            fixUps.add(fixUp);
1183          }
1184        
1185    //        System.err.println("For inner class/interface " + typeName + " found type " + type);
1186          varData[i].gotValue();
1187          varData[i].setIsLocalVariable(true);
1188        }
1189        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      private SymbolData _lookupReturnString(String rtString, SourceInfo si) {
1206        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      protected MethodData createMethodData(final MethodDef that, final SymbolData sd) {
1211        
1212        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        that.getMav().visit(this);
1218        that.getName().visit(this);
1219        
1220        // Turn the thrown exceptions from a ReferenceType[] to a String[]
1221        String[] throwStrings = referenceType2String(that.getThrows());
1222           
1223        final String rtString = that.getResult().getName();
1224    
1225        // Identify the return type
1226        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        SymbolData returnType = _identifyType(rtString, si, _enclosingClassName);
1235        
1236        final String name = that.getName().getText();
1237    //    System.err.println("Creating MethodData for " + name + " in type " + sd);
1238        final MethodData md = 
1239          MethodData.make(name, that.getMav(), that.getTypeParams(), returnType, null, throwStrings, sd, that);
1240        VariableData[] vds = formalParameters2VariableData(that.getParams(), sd);
1241            
1242        if (returnType == null) {
1243    //      System.err.println("Creating return type fixup for " + rtString + " in method " + name + " in class " + sd);
1244          final String enclosingClassName = _enclosingClassName;
1245          Command fixUp = new Command() {
1246            public void execute() {
1247              SymbolData newReturnType = _identifyType(rtString, si, enclosingClassName);
1248              if (newReturnType == null && (! (LanguageLevelVisitor.this instanceof FullJavaVisitor))) {
1249                _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                md.setReturnType(newReturnType);
1257              }
1258            }
1259          };
1260          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        if (_checkError()) {  //if there was an error converting the formalParameters, don't use them.
1269          return md;
1270        }
1271        
1272        md.setParams(vds);
1273        
1274        // Adds the formal parameters to the list of vars defined in this method.
1275        if (! md.addVars(vds)) { //TODO: should this not have been changed from addFinalVars?
1276          _addAndIgnoreError("You cannot have two method parameters with the same name", that);      
1277        }
1278        return md;
1279      }
1280      
1281      /** Generates a brief print string for a VariableDeclarator. */
1282      private static String declaratorsToString(VariableDeclarator[] vds) {
1283        StringBuilder printString = new StringBuilder("{ ");
1284        for (VariableDeclarator vd: vds) {
1285          printString.append(vd.getName().getText()).append(": ").append(vd.getType().getName()).append("; ");
1286        }
1287        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      protected VariableData[] _variableDeclaration2VariableData(VariableDeclaration vd, final Data enclosing) {
1295        assert enclosing != null;
1296    //    System.err.println("*** 2Var called for \n" + declaratorsToString(vd.getDeclarators()) + "\nin " + enclosing);
1297        LinkedList<VariableData> vds = new LinkedList<VariableData>();
1298        ModifiersAndVisibility mav = vd.getMav();
1299        VariableDeclarator[] declarators = vd.getDeclarators();
1300        for (final VariableDeclarator declarator: declarators) {
1301          declarator.visit(this); // Does NOTHING!
1302          final Type type = declarator.getType();
1303          final String name = declarator.getName().getText();
1304          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          SymbolData sd = _identifyType(typeName, declarator.getSourceInfo(), _enclosingClassName);  // may be null
1312          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          final VariableData vdata = new VariableData(name, mav, sd, initialized, enclosing); 
1316          vdata.setHasInitializer(initialized);
1317    //        vdata.setIsLocalVariable(true);
1318          vds.addLast(vdata); 
1319    //        System.err.println("identifyReturnType(" + type + ", " + name + ", " + enclosing + ") returned null");
1320          if (sd == null) { // TODO !!! Can this really happen?
1321            // Create fixup
1322            final String enclosingName = _enclosingClassName;  // Grab the current enclosing class name
1323    //        System.err.println("**** Creating fixup for preceding VariableData");
1324            Command fixup = new Command() {
1325              public void execute() {
1326    //            System.err.println("**** Executing fixup for " + typeName + " within " + enclosingName);
1327                SymbolData newSd = _identifyType(typeName, declarator.getSourceInfo(), enclosingName);
1328                if (newSd != null) vdata.setType(newSd);
1329                else if (! (LanguageLevelVisitor.this instanceof FullJavaVisitor) ) // TODO: fix this kludge!!!
1330                  _addAndIgnoreError("Class or Interface " + typeName + " not found", type);
1331              }
1332            };
1333            fixUps.add(fixup);       
1334          }
1335        }
1336    //    System.err.println("Returning VariableDatas " + vds);
1337        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      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        if (_genericTypes.containsKey(name)) return _genericTypes.get(name);
1349        
1350        SymbolData sd = getSymbolData(name, si);  // TODO: uses wrong enclosingClassName!!!
1351        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        if (enclosingClassName == null) return null;  // happens for binding occurrences of type variables?
1361        
1362        SymbolData enclosingSD = getQualifiedSymbolData(enclosingClassName, SourceInfo.NONE);   
1363        if (enclosingSD == null) return null;
1364        
1365        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        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      protected static void _addError(String message, JExpressionIF that) {
1383    //    Utilities.show("_addError(" + message + ", " + that + ") called");
1384        _errorAdded = true;
1385        Pair<String, JExpressionIF> p = new Pair<String, JExpressionIF>(message, that);
1386        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      protected static void _addAndIgnoreError(String message, JExpressionIF that) {
1394    //    Utilities.show("_addAndIgnoreError(" + message + ", " + that + ") called");
1395        if (_errorAdded) {
1396          throw new RuntimeException("Internal Program Error: _addAndIgnoreError called while _errorAdded was true." + 
1397                                     "  Please report this bug.");
1398        }
1399        _errorAdded = false;
1400        Pair<String, JExpressionIF> newMsg = new Pair<String, JExpressionIF>(message, that);
1401        if (! errors.contains(newMsg)) errors.addLast(newMsg);
1402    //    else System.err.println("Suppressing error as duplicate: " + newMsg);
1403      }
1404      
1405      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      protected static boolean _checkError() {
1413        if (_errorAdded) {
1414          _errorAdded = false;
1415          return true;
1416        }
1417        else return false;
1418      }
1419      
1420      /** Add an error explaining the modifiers' conflict. */
1421      public void _badModifiers(String first, String second, JExpressionIF that) {
1422        _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      public Void forModifiersAndVisibilityDoFirst(ModifiersAndVisibility that) {
1429        String[] modifiersAndVisibility = that.getModifiers();
1430        Arrays.sort(modifiersAndVisibility);
1431        if (modifiersAndVisibility.length > 0) {
1432          String s = modifiersAndVisibility[0];
1433          // check for duplicate modifiers
1434          for (int i = 1; i < modifiersAndVisibility.length; i++) {
1435            if (s.equals(modifiersAndVisibility[i])) {
1436              _addError("Duplicate modifier: " + s, that);
1437            }
1438            s = modifiersAndVisibility[i];
1439          }
1440          
1441          // check for illegal combination of modifiers
1442          String visibility = "package";
1443          boolean isAbstract = false;
1444          boolean isStatic = false;
1445          boolean isFinal = false;
1446          boolean isSynchronized = false;
1447          boolean isStrictfp = false;
1448          boolean isTransient = false;
1449          boolean isVolatile = false;
1450          boolean isNative = false;
1451          for (int i = 0; i < modifiersAndVisibility.length; i++) {
1452            s = modifiersAndVisibility[i];
1453            if (s.equals("public") || s.equals("protected") || s.equals("private")) {
1454              if (! visibility.equals("package")) _badModifiers(visibility, s, that);
1455              else if (s.equals("private") && isAbstract) _badModifiers("private", "abstract", that);
1456              else visibility = s;
1457            }
1458            else if (s.equals("abstract")) isAbstract = true;
1459            else if (s.equals("final")) { 
1460              isFinal = true;
1461              if (isAbstract) _badModifiers("final", "abstract", that);
1462            }
1463            else if (s.equals("native")) { 
1464              isNative = true;
1465              if (isAbstract) _badModifiers("native", "abstract", that);
1466            }
1467            else if (s.equals("synchronized")) { 
1468              isSynchronized = true;
1469              if (isAbstract) _badModifiers("synchronized", "abstract", that);
1470            }
1471            else if (s.equals("volatile")) { 
1472              isVolatile = true;
1473              if (isFinal) _badModifiers("final", "volatile", that);
1474            }
1475          }
1476          return forJExpressionDoFirst(that);  // Does nothing!
1477        }
1478        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      public Void forClassDefDoFirst(ClassDef that) {
1485        String name = that.getName().getText();  // name of defined class
1486        Iterator<String> iter = _importedFiles.iterator();
1487        while (iter.hasNext()) {
1488          String s = iter.next();
1489          if (s.endsWith(name) && ! s.equals(getQualifiedClassName(name))) {  // TODO: this test is too coarse!
1490            _addAndIgnoreError("The class " + name + " was already imported.", that);
1491          }
1492        }
1493        
1494        // top level classes cannot be private.
1495        String[] mavStrings = that.getMav().getModifiers();
1496        if (! (that instanceof InnerClassDef)) {
1497          for (int i = 0; i < mavStrings.length; i++) {
1498            if (mavStrings[i].equals("private")) {
1499              _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        SymbolData javaLangClass = 
1506           getQualifiedSymbolData("java.lang." + that.getName().getText(), that.getSourceInfo(), false, false, false);
1507        if (that.getName().getText().equals("TestCase") || (javaLangClass != null && ! javaLangClass.isContinuation())) {
1508          _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        return forTypeDefBaseDoFirst(that);
1513      }
1514      
1515      /** Check for problems with InterfaceDefs: specifically, top level interfaces cannot be private or final. */
1516      public Void forInterfaceDefDoFirst(InterfaceDef that) {
1517        //top level interfaces cannot be private or final.
1518        String[] mavStrings = that.getMav().getModifiers();
1519        for (int i = 0; i < mavStrings.length; i++) {
1520          if (mavStrings[i].equals("private")) {
1521            _addAndIgnoreError("Top level interfaces cannot be private", that);
1522          }
1523          if (mavStrings[i].equals("final")) {
1524            _addAndIgnoreError("Interfaces cannot be final", that);
1525          }
1526        }
1527        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      public Void forInnerInterfaceDefDoFirst(InnerInterfaceDef that) {
1534        String[] mavStrings = that.getMav().getModifiers();
1535        for (int i = 0; i < mavStrings.length; i++) {
1536          if (mavStrings[i].equals("final")) {
1537            _addAndIgnoreError("Interfaces cannot be final", that);
1538          }
1539        }
1540        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      public void anonymousClassInstantiationHelper(AnonymousClassInstantiation that, SymbolData enclosing, String superName) {
1550        that.getArguments().visit(this);
1551        SymbolData enclosingSD = enclosing.getSymbolData();
1552        String enclosingSDName = enclosingSD.getName();
1553        assert enclosingSDName.equals(_enclosingClassName);
1554        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        SymbolData anonSD = defineAnonymousSymbolData(that, anonName, superName);
1561        
1562    //    if (this instanceof IntermediateVisitor) {
1563        // These methods are no-ops in FullJavaVisitor
1564        createToString(anonSD);
1565        createHashCode(anonSD);
1566        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        that.getBody().visit(newClassBodyVisitor(anonSD, anonName));
1573      }
1574      
1575      /** Processes the class body that. */
1576      protected void identifyInnerClasses(TypeDefBase that) {
1577        String prefix = _enclosingClassName == null ? "" : _enclosingClassName + '.';
1578        String enclosingType = getQualifiedClassName(prefix + that.getName().getText());
1579    //    System.err.println("***** identifyInnerClasses called for " + enclosingType + " in file " + _file);
1580        assert enclosingType != null;
1581        // Process the members of this class
1582    //    System.err.println("Finding inner classes in " + enclosingType);
1583        SymbolData sd = getSymbolData(enclosingType, SourceInfo.NONE);
1584    //    System.err.println("SymbolData for " + enclosingType + " is " + sd);
1585        enclosingType = sd.getName(); // that may be a local class, which has a more elaborate name
1586        BracedBody body = that.getBody();
1587        for (BodyItemI bi: body.getStatements()) {
1588          if (bi instanceof TypeDefBase) {
1589            TypeDefBase type = (TypeDefBase) bi;
1590            String rawClassName = type.getName().getText();
1591    //        System.err.println("Adding " + rawClassName + " to inner classes of " + enclosingType + "\n");
1592            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            SymbolData innerSD = makeContinuation(bi.getSourceInfo(), fullClassName);
1598    //        System.err.println("***** Continuation " + innerSD + " returned");
1599    //        Utilities.show("***** Continuation " + innerSD + " returned");
1600            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      public Void forPackageStatementOnly(PackageStatement that) {
1634        CompoundWord cWord = that.getCWord();
1635        Word[] words = cWord.getWords();
1636        String newPackage;
1637        String separator = System.getProperty("file.separator");
1638        if (words.length > 0) {
1639          _package = words[0].getText();
1640          newPackage = _package;
1641          for (int i = 1; i < words.length; i++) {
1642            String temp = words[i].getText();
1643            newPackage = newPackage + separator + temp;
1644            _package = _package + '.' + temp;
1645          }    
1646          String directory = _file.getParent();
1647          if (directory == null || !directory.endsWith(newPackage)) {
1648            _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        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      public Void forClassImportStatementOnly(ClassImportStatement that) {
1665        CompoundWord cWord = that.getCWord();
1666        Word[] words = cWord.getWords();
1667        
1668        // Make sure that this specific imported class has not already been specifically imported
1669        for (int i = 0; i < _importedFiles.size(); i++) {
1670          String name = _importedFiles.get(i);
1671          int indexOfLastDot = name.lastIndexOf('.');
1672          if (indexOfLastDot != -1 && 
1673              (words[words.length-1].getText()).equals(name.substring(indexOfLastDot + 1, name.length()))) {
1674            _addAndIgnoreError("The class " + words[words.length-1].getText() + " has already been imported.", that);
1675            return null;
1676          }
1677        }
1678        
1679        StringBuilder nameBuff = new StringBuilder(words[0].getText());
1680        for (int i = 1; i < words.length; i++) {nameBuff.append('.' + words[i].getText());}
1681        
1682        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        _importedFiles.addLast(qualifiedTypeName);  
1698        
1699        // Create a continuation for imported class if one does not already exist
1700        createImportedSymbolContinuation(qualifiedTypeName, that.getSourceInfo());
1701        return forImportStatementOnly(that);
1702      }
1703      
1704      /** Create a continuation for imported class specified by qualifiedName if one does not already exist. */
1705      protected SymbolData createImportedSymbolContinuation(String qualifiedTypeName, SourceInfo si) {
1706    
1707        SymbolData sd = symbolTable.get(qualifiedTypeName);
1708        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          sd = makeContinuation(si, qualifiedTypeName);
1713        }
1714        return sd;
1715      }
1716      
1717      /**Check to make sure that this package import statement is not trying to import the current pacakge. */
1718      public Void forPackageImportStatementOnly(PackageImportStatement that) { 
1719        CompoundWord cWord = that.getCWord();
1720        Word[] words = cWord.getWords();
1721        StringBuilder tempBuff = new StringBuilder(words[0].getText());
1722        for (int i = 1; i < words.length; i++) { tempBuff.append('.' + words[i].getText()); }
1723        String temp = tempBuff.toString();
1724        
1725        
1726        //make sure this imported package does not match the current package
1727        if (_package.equals(temp)) {
1728          _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          return null;
1731        }
1732    
1733        if (! _importedPackages.contains(temp)) _importedPackages.addLast(temp);
1734        
1735        return forImportStatementOnly(that);
1736      }
1737      
1738      /** Makes sure that this concrete method def is not declared to be abstract. */
1739      public Void forConcreteMethodDefDoFirst(ConcreteMethodDef that) {
1740        ModifiersAndVisibility mav = that.getMav();
1741        String[] modifiers = mav.getModifiers();
1742        // Concrete methods can be public, private, protected, or static at the Intermediate (Functional) level.
1743        for (int i = 0; i < modifiers.length; i++) {
1744          if (modifiers[i].equals("abstract")) {
1745            _addError("Methods that have a braced body cannot be declared \"abstract\"", that);
1746            break;
1747          }
1748        }
1749        return super.forConcreteMethodDefDoFirst(that);
1750      }
1751      
1752      /** Makes sure that this abstract method def is not declared to be static. */
1753      public Void forAbstractMethodDefDoFirst(AbstractMethodDef that) {
1754        ModifiersAndVisibility mav = that.getMav();
1755        String[] modifiers = mav.getModifiers();
1756        // Concrete methods can now be public, private, protected at the Intermediate level.  They still cannot be static.
1757        if (Utilities.isStatic(modifiers)) _badModifiers("static", "abstract", that);
1758        return super.forAbstractMethodDefDoFirst(that);
1759      }
1760      
1761      /** Bitwise operators are allowed in Full Java */
1762      public Void forShiftAssignmentExpressionDoFirst(ShiftAssignmentExpression that) { return null; }
1763      public Void forBitwiseAssignmentExpressionDoFirst(BitwiseAssignmentExpression that) { return null; }
1764      public Void forBitwiseBinaryExpressionDoFirst(BitwiseBinaryExpression that) { return null; }
1765      public Void forBitwiseOrExpressionDoFirst(BitwiseOrExpression that) { return null; }
1766      public Void forBitwiseXorExpressionDoFirst(BitwiseXorExpression that) { return null; }
1767      public Void forBitwiseAndExpressionDoFirst(BitwiseAndExpression that) { return null; }
1768      public Void forBitwiseNotExpressionDoFirst(BitwiseNotExpression that) { return null; }
1769      public Void forShiftBinaryExpressionDoFirst(ShiftBinaryExpression that) { return null; }
1770      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      public Void forEmptyExpressionDoFirst(EmptyExpression that) {
1775        _addAndIgnoreError("You appear to be missing an expression here", that);
1776        return null;
1777      }
1778      
1779      /** The NoOp expression signifies a missing binary operator that was encountered when the
1780        * parser built the AST. */
1781      public Void forNoOpExpressionDoFirst(NoOpExpression that) {
1782        _addAndIgnoreError("You are missing a binary operator here", that);
1783        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      public Void forSourceFileDoFirst(SourceFile that) {
1788        
1789        for (int i = 0; i < that.getTypes().length; i++) {
1790          if (that.getTypes()[i] instanceof ClassDef) {
1791            ClassDef c = (ClassDef) that.getTypes()[i];
1792            String superName = c.getSuperclass().getName();
1793            if (superName.equals("TestCase") || superName.equals("junit.framework.TestCase")) {
1794              // TODO; add code to exclude the following test for FullJava files
1795              if (that.getTypes().length > 1) {
1796                _addAndIgnoreError("TestCases must appear in files by themselves in functional code", c);
1797              }
1798            }
1799          }
1800        }
1801        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      public Void forSourceFile(SourceFile that) {
1811    //    System.err.println("Processing source file " + that.getSourceInfo().getFile());
1812        forSourceFileDoFirst(that);  // Confirms that TestCase classes appear alone in files
1813        if (prune(that)) return null;
1814        
1815        // The parser enforces that there is either zero or one PackageStatement.
1816        for (int i = 0; i < that.getPackageStatements().length; i++) that.getPackageStatements()[i].visit(this);
1817        for (int i = 0; i < that.getImportStatements().length; i++) that.getImportStatements()[i].visit(this);
1818        if (! _importedPackages.contains("java.lang")) _importedPackages.addFirst("java.lang");
1819        
1820        TypeDefBase[] types = that.getTypes();
1821        // store the qualified names of all classes defined in this file in:
1822        _classesInThisFile = new HashSet<String>();
1823        for (int i = 0; i < types.length; i++) {
1824          // TODO: Add inner classes to this list?
1825          
1826          String qualifiedClassName = getQualifiedClassName(types[i].getName().getText());
1827          _classesInThisFile.add(qualifiedClassName);
1828    //      System.err.println("Adding " + qualifiedClassName + " to _classesInThisFile");
1829          _log.log("Adding " + qualifiedClassName + " to _classesInThisFile");
1830        }
1831        
1832        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          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          if (_classesInThisFile.contains(qualifiedClassName)) {
1838            types[i].visit(this);
1839          }
1840        }
1841        
1842        return forSourceFileOnly(that);
1843      }
1844      
1845      /** Call the ResolveNameVisitor to see if this is a reference to a Type name. */
1846      public Void forSimpleNameReference(SimpleNameReference that) {
1847        that.visit(new ResolveNameVisitor());
1848        return null;
1849      }
1850      
1851      /** Call the ResolveNameVisitor to see if this is a reference to a Type name. */
1852      public Void forComplexNameReference(ComplexNameReference that) {
1853        that.visit(new ResolveNameVisitor());
1854        return null;
1855      }
1856      
1857      /** Do nothing.  This is handled in the forVariableDeclarationOnly case.*/
1858      public Void forVariableDeclaration(VariableDeclaration that) {
1859    //    System.err.println("forVariableDeclaration in LLV called for " + that);
1860        forVariableDeclarationDoFirst(that);
1861        
1862        if (prune(that)) return null;
1863    //    System.err.println("forVariableDeclarationDoFirst(...) completed with no errors");
1864        that.getMav().visit(this);
1865    //    System.err.println("Mav visit completed in forVariableDeclaration; getClass() = "  + getClass());
1866        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      protected static void addGeneratedMethod(SymbolData sd, MethodData md) {
1873        MethodData rmd = SymbolData.repeatedSignature(sd.getMethods(), md);
1874        if (rmd == null) {
1875          sd.addMethod(md, true);
1876          md.setGenerated(true);
1877        }
1878        
1879        else if (!(getUnqualifiedClassName(sd.getName()).equals(md.getName()))) {
1880          //if it is not a constructor, it cannot be overridden--give an error
1881          _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      public void createConstructor(SymbolData sd) {
1892        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        if (sd.isContinuation()) {
1902          _addAndIgnoreError("Could not generate constructor for class " + sd + " because it has no definition", 
1903                    new NullLiteral(SourceInfo.NONE));
1904          return;
1905        }
1906        
1907        SymbolData superSd = sd.getSuperClass();
1908        if (superSd == null) {
1909          _addAndIgnoreError("Could not generate constructor for class " + sd + " because it has no superclass", 
1910                    new NullLiteral(SourceInfo.NONE));
1911          return;
1912        }
1913        
1914        else {
1915          LinkedList<MethodData> superMethods = superSd.getMethods();
1916          String superUnqualifiedName = getUnqualifiedClassName(superSd.getName());
1917          
1918          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          if (sslv != null) {
1923            sslv.createConstructor(superSd);
1924    //        System.err.println("Creating constructor for superclass " + superSd);
1925          }
1926          
1927          // Find the super's smallest constructor.
1928          MethodData superConstructor = null;
1929          for (MethodData superMd: superMethods) {
1930    //      Iterator<MethodData> iter = superMethods.iterator();
1931    //      while (iter.hasNext()) {
1932    //        MethodData superMd = iter.next();
1933            if (superMd.getName().equals(superUnqualifiedName)) {
1934              if (superConstructor == null || superMd.getParams().length < superConstructor.getParams().length) {
1935                superConstructor = superMd;
1936              }
1937            }
1938          }
1939          if (superConstructor == null) {
1940            _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            return;
1944          }
1945    //      if (superConstructor == null) {
1946    //        System.err.println("**** Error **** The superclass " + superSd + " has no constructors ");
1947    //      }
1948          String name = getUnqualifiedClassName(sd.getName());
1949          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          LinkedList<VariableData> params = new LinkedList<VariableData>();
1959    //      if (superConstructor != null) {
1960          for (VariableData superParam : superConstructor.getParams()) {
1961            String paramName = md.createUniqueName("super_" + superParam.getName());
1962            SymbolData superParamSD = superParam.getType();
1963            assert superParamSD != null;
1964            VariableData newParam = new VariableData(paramName, PACKAGE_MAV, superParamSD, true, sd);  // Note: sd was md
1965            newParam.setGenerated(true);
1966            params.add(newParam);
1967            // Next line done on each iteration so that createUniqueName handles nameless super parameters (in class files)
1968            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          boolean hasOtherConstructor = sd.hasMethod(name);
1974          
1975          for (VariableData field : sd.getVars()) {
1976            
1977            if (! field.hasInitializer() && ! field.hasModifier("static")) {
1978              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              VariableData param = field.copyWithoutVisibility();
1982              params.add(param);
1983            }
1984          }
1985          // Some fields may be declared private, but parameters cannot be; unprivatize the 
1986          
1987          md.setParams(params.toArray(new VariableData[params.size()]));
1988          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          addGeneratedMethod(sd, md);
1994        }
1995        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      protected static void createAccessors(SymbolData sd, File file) {
2004        if (LanguageLevelConverter.isAdvancedFile(file)) return;
2005        LinkedList<VariableData> fields = sd.getVars();
2006        for (final VariableData vd: fields) {     
2007          if (! vd.hasModifier("static")) { 
2008            String name = getFieldAccessorName(vd.getName());
2009            SymbolData returnTypeSD = vd.getType();
2010            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            addGeneratedMethod(sd, md);
2019            if (returnTypeSD == null) { // create a fixup to patch the return type of md; vd may have pending return type
2020              Command fixUp = new Command() {
2021                public void execute() { md.setReturnType(vd.getType()); }
2022              };
2023              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      protected void createToString(SymbolData sd) {
2033        String name = "toString";
2034        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        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      protected void createHashCode(SymbolData sd) {    
2049        String name = "hashCode";
2050        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        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      protected void createEquals(SymbolData sd) {    
2065        String name = "equals";
2066        SymbolData type = getSymbolData("java.lang.Object", SourceInfo.make("java.lang.Object"));
2067        VariableData param = new VariableData(type);
2068        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        param.setEnclosingData(md);
2077        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      public Void forMemberType(MemberType that) {
2086        forMemberTypeDoFirst(that);
2087        if (prune(that)) return null;
2088        return forMemberTypeOnly(that);
2089      }
2090      
2091      /**Return the SymbolData for java.lang.String by default*/
2092      public Void forStringLiteralOnly(StringLiteral that) {
2093        getQualifiedSymbolData("java.lang.String", that.getSourceInfo(), true);
2094        return null;
2095      }
2096      
2097      /** Try to resolve the type of the instantiation, and make sure there are no errors*/
2098      public Void forSimpleNamedClassInstantiation(SimpleNamedClassInstantiation that) {
2099        forSimpleNamedClassInstantiationDoFirst(that);
2100        if (prune(that)) return null;
2101        that.getType().visit(this);
2102        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        getSymbolData(that.getType().getName(), that.getSourceInfo());
2109        
2110        // TODO? create a fixup?
2111        
2112        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      public static boolean arrayEquals(Object[] array1, Object[] array2) {
2120    //    return Arrays.equals(array1, array2); 
2121        int n = array1.length;
2122        if (n != array2.length) return false;
2123        for (int i = 0; i < n; i++) {
2124          Object o1 = array1[i];
2125          Object o2 = array2[i];
2126          if (o1 == null && o2 != null) return false;
2127          if (! o1.equals(o2)) return false;
2128        };
2129        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        public ResolveNameVisitor() { }
2136        
2137        /** Most expressions are not relevant for this check--visit them with outer visitor. */
2138        public TypeData defaultCase(JExpressionIF that) {
2139          that.visit(LanguageLevelVisitor.this);
2140          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        public TypeData forSimpleNameReference(SimpleNameReference that) {
2148          SymbolData result = getSymbolData(that.getName().getText(), that.getSourceInfo());
2149          // it could not be resolved: return a Package Data
2150          // TODO: create a fixup !!!
2151          if (result == SymbolData.NOT_FOUND) {
2152            return new PackageData(that.getName().getText());
2153          }
2154          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        public TypeData forComplexNameReference(ComplexNameReference that) {
2162          TypeData lhs = that.getEnclosing().visit(this);
2163          SymbolData result = getSymbolData(lhs, that.getName().getText(), that.getSourceInfo(), true);
2164          
2165          // TODO: create a fixup?
2166          if (result == SymbolData.NOT_FOUND) { 
2167            if (lhs instanceof PackageData) {
2168              return new PackageData((PackageData) lhs, that.getName().getText());
2169            }
2170            return null;
2171          }
2172          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        public LanguageLevelVisitorTest() { this(""); }
2190        public LanguageLevelVisitorTest(String name) { super(name); }
2191        
2192        public void setUp() {
2193          Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>> continuations =
2194            new Hashtable<String, Triple<SourceInfo, LanguageLevelVisitor, SymbolData>>();
2195          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          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          errors = new LinkedList<Pair<String, JExpressionIF>>();
2207          _errorAdded = false;
2208          
2209          visitedFiles = new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>();      
2210    //      _hierarchy = new Hashtable<String, TypeDefBase>();
2211          testLLVisitor._classesInThisFile = new HashSet<String>();
2212          if (! testLLVisitor._importedPackages.contains("java.lang")) testLLVisitor._importedPackages.add("java.lang");
2213    
2214          _sd1 = new SymbolData("i.like.monkey");
2215          _sd2 = new SymbolData("i.like.giraffe");
2216          _sd3 = new SymbolData("zebra");
2217          _sd4 = new SymbolData("u.like.emu");
2218          _sd5 = new SymbolData("");
2219          _sd6 = new SymbolData("cebu");
2220        }
2221        
2222        /** Tests the getUnqualifiedClassName method. */
2223        public void testGetUnqualifiedClassName() {
2224          assertEquals("getUnqualifiedClassName with a qualified name with an inner class", "innermonkey", 
2225                       testLLVisitor.getUnqualifiedClassName("i.like.monkey$innermonkey"));
2226          assertEquals("getUnqualifiedClassName with a qualified name", "monkey", 
2227                       testLLVisitor.getUnqualifiedClassName("i.like.monkey"));
2228          assertEquals("getUnqualifiedClassName with an unqualified name", "monkey", 
2229                       testLLVisitor.getUnqualifiedClassName("monkey"));
2230          assertEquals("getUnqualifiedClassName with an empty string", "", testLLVisitor.getUnqualifiedClassName(""));
2231        }
2232        
2233        public void testClassFile2SymbolData() {
2234          
2235          //test a java.lang symbol data
2236          SymbolData objectSD = LanguageLevelConverter._classFile2SymbolData("java.lang.Object", "");
2237          SymbolData stringSD = LanguageLevelConverter._classFile2SymbolData("java.lang.String", "");
2238          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          assertTrue("java.lang.String should have been converted successfully", 
2242                     stringSD.getName().equals("java.lang.String"));
2243          assertEquals("java.lang.String's superSD should should be java.lang.Object", 
2244                       objectSD,
2245                       stringSD.getSuperClass());
2246          
2247          LinkedList<MethodData> methods = stringSD.getMethods();
2248          Iterator<MethodData> iter = methods.iterator();
2249          boolean found = false;
2250          
2251          while (iter.hasNext()) {
2252            MethodData currMd = iter.next();
2253            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              found = true;
2257              md.getParams()[0].setEnclosingData(currMd);
2258              break;
2259            }
2260          }
2261          
2262          assertTrue("Should have found method substring(int) in java.lang.String", found);
2263          
2264          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          SymbolData newStringSD = LanguageLevelConverter._classFile2SymbolData("java.lang.String", "");
2269          assertTrue("Second call to classFileToSymbolData should not change sd in hash table.", 
2270                     stringSD == LanguageLevelConverter.symbolTable.get("java.lang.String"));
2271          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          SymbolData bartSD = LanguageLevelConverter._classFile2SymbolData("Bart", "testFiles");
2276          assertFalse("bartSD should not be null", bartSD == null);
2277          assertFalse("bartSD should not be a continuation", bartSD.isContinuation());
2278          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          md1.getParams()[0].setEnclosingData(bartSD.getMethods().getLast());
2285          MethodData md2 = new MethodData("Bart", PUBLIC_MAV, new TypeParameter[0], bartSD,
2286                                          new VariableData[0], new String[0], bartSD, null);
2287          
2288          VariableData vd1 = new VariableData("i", PUBLIC_MAV, SymbolData.INT_TYPE, true, bartSD);
2289          
2290          LinkedList<MethodData> bartsMD = new LinkedList<MethodData>();
2291          bartsMD.addFirst(md1);
2292          bartsMD.addFirst(md2);
2293          
2294          LinkedList<VariableData> bartsVD = new LinkedList<VariableData>();
2295          bartsVD.addLast(vd1);
2296          
2297          assertEquals("Bart's super class should be java.lang.Object: errors = " + errors, objectSD, 
2298                       bartSD.getSuperClass());
2299          assertEquals("Bart's Variable Data should be a linked list containing only vd1", bartsVD, bartSD.getVars());
2300          assertEquals("The first method data of bart's should be correct", md2, bartSD.getMethods().getFirst());
2301          
2302          assertEquals("The second method data of bart's should be correct", md1, bartSD.getMethods().getLast());
2303          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        public void testGetSymbolDataForClassFile() {
2347          // Test that passing a legal class return a non-continuation.
2348          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          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        public void testGetSymbolData_Primitive() {
2360          assertEquals("should be boolean type", SymbolData.BOOLEAN_TYPE, 
2361                       LanguageLevelConverter._getPrimitiveSymbolData("boolean"));
2362          assertEquals("should be char type", SymbolData.CHAR_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("char"));
2363          assertEquals("should be byte type", SymbolData.BYTE_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("byte"));
2364          assertEquals("should be short type", SymbolData.SHORT_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("short"));
2365          assertEquals("should be int type", SymbolData.INT_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("int"));
2366          assertEquals("should be long type", SymbolData.LONG_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("long"));
2367          assertEquals("should be float type", SymbolData.FLOAT_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("float"));
2368          assertEquals("should be double type", SymbolData.DOUBLE_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("double"));
2369          assertEquals("should be void type", SymbolData.VOID_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("void"));
2370          assertEquals("should be null type", SymbolData.NULL_TYPE, LanguageLevelConverter._getPrimitiveSymbolData("null"));
2371          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        public void testGetArraySymbolData() {
2432          //Initially, force the inner sd of this array type to be null, to test that.
2433          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          SymbolData sd = new SymbolData("Iexist");
2438          LanguageLevelConverter.symbolTable.put("Iexist", sd);
2439          testLLVisitor.getArraySymbolData("Iexist", SourceInfo.NONE, false, false).getName();
2440          assertTrue("Should have created an array data and add it to symbol table.", 
2441                     LanguageLevelConverter.symbolTable.containsKey("Iexist[]"));
2442          SymbolData ad = LanguageLevelConverter.symbolTable.get("Iexist[]");
2443          
2444          //make sure that ad has the appropriate fields and super classes and interfaces and methods
2445          assertEquals("Should only have field 'length'", 1, ad.getVars().size());
2446          assertNotNull("Should contain field 'length'", ad.getVar("length"));
2447          
2448          assertEquals("Should only have one method-clone", 1, ad.getMethods().size());
2449          assertTrue("Should contain method clone", ad.hasMethod("clone"));
2450          
2451          assertEquals("Should have Object as super class", 
2452                       LanguageLevelConverter.symbolTable.get("java.lang.Object"), 
2453                       ad.getSuperClass());
2454          assertEquals("Should have 2 interfaces", 2, ad.getInterfaces().size());
2455          assertEquals("Interface 1 should be java.lang.Cloneable", "java.lang.Cloneable", 
2456                       ad.getInterfaces().get(0).getName());
2457          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          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          testLLVisitor.getArraySymbolData("Iexist[]", SourceInfo.NONE, false, false);
2467          assertTrue("Should have added a multidimensional array to the table.", 
2468                     LanguageLevelConverter.symbolTable.containsKey("Iexist[][]"));
2469          
2470          SymbolData sd2 = new SymbolData("java.lang.String");
2471          LanguageLevelConverter.symbolTable.put("java.lang.String", sd2);
2472          testLLVisitor.getArraySymbolData("String[]", SourceInfo.NONE, false, true);
2473          assertTrue("Should have added java.lang.String[] to table", 
2474                     LanguageLevelConverter.symbolTable.containsKey("java.lang.String[]"));
2475          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        public void testGetSymbolDataFromFileSystem() {
2480          _sd4.setIsContinuation(false);
2481          _sd6.setIsContinuation(true);
2482          LanguageLevelConverter.symbolTable.put("u.like.emu", _sd4);
2483          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          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          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          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          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          IntermediateVisitor bv = new IntermediateVisitor(new File(""));
2511          
2512          testLLVisitor._classesInThisFile.add("Lisa" /*, new Pair<TypeDefBase, LanguageLevelVisitor>(cd, bv)*/);
2513          assert testLLVisitor._classesInThisFile.contains("Lisa");
2514          SymbolData matchLisa = 
2515            testLLVisitor.getQualifiedSymbolData("Lisa", SourceInfo.NONE, true);
2516          assertTrue("Should return a continuation", matchLisa.isContinuation());
2517        }
2518        
2519        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          testLLVisitor._package="fully.qualified";
2524          testLLVisitor._file = new File("testFiles/fully/qualified/Fake.dj0");
2525          SymbolData sd2 = new SymbolData("fully.qualified.Woah");  // continuation
2526          testLLVisitor.symbolTable.put("fully.qualified.Woah", sd2);
2527          
2528          SymbolData result = 
2529            testLLVisitor._getSymbolDataFromFileSystem("fully.qualified.Woah", SourceInfo.NONE, false, true);
2530          
2531          assertEquals("Should return sd2, unresolved.", sd2, result);
2532          assertTrue("sd2 should still be unresolved", sd2.isContinuation());
2533          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          testLLVisitor.symbolTable.remove("fully.qualified.Woah");
2548          testLLVisitor.visitedFiles.clear();
2549          testLLVisitor._package="another.package";
2550          testLLVisitor._file = new File("testFiles/another/package/Wowsers.dj0");
2551          sd2 = new SymbolData("fully.qualified.Woah");
2552          testLLVisitor.symbolTable.put("fully.qualified.Woah", sd2);
2553          
2554          result = testLLVisitor._getSymbolDataFromFileSystem("fully.qualified.Woah", SourceInfo.NONE, false, true);
2555          
2556          assertEquals("Should return sd2, unresolved.", sd2, result);
2557          assertTrue("sd2 should still be unresolved", sd2.isContinuation());
2558          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          testLLVisitor._package = "";
2569          testLLVisitor._file = new File ("testFiles/Cool.dj0");  // non-existent file
2570          
2571          //unqualified
2572          SymbolData sd1 = new SymbolData("Wow");
2573          SymbolData obj = testLLVisitor._getSymbolDataFromFileSystem("java.lang.Object", SourceInfo.NONE, true, true);
2574          sd1.setSuperClass(obj);
2575          testLLVisitor.symbolTable.put("Wow", sd1);
2576          
2577          result = testLLVisitor._getSymbolDataFromFileSystem("Wow", SourceInfo.NONE, false, true);
2578          assertEquals("Should return sd1, unresolved.", sd1, result);
2579          assertTrue("sd1 should still be unresolved.", sd1.isContinuation());
2580          assertEquals("Should be no errors", 0, errors.size());
2581          
2582          result = testLLVisitor._getSymbolDataFromFileSystem("Wow", SourceInfo.NONE, true, true);
2583          assertEquals("Should return sd1, resolved.", sd1, result);
2584          assertFalse("sd1 should be resolved.", sd1.isContinuation());
2585          assertEquals("Should be no errors", 0, errors.size());
2586          
2587          result = testLLVisitor._getSymbolDataFromFileSystem("Wow", SourceInfo.NONE, true, true);
2588          assertEquals("Should return sd1.", sd1, result);
2589          assertFalse("sd1 should still be resolved.", sd1.isContinuation());
2590          assertEquals("Should be no errors", 0, errors.size());
2591          
2592          
2593          //finding the most recent file
2594          result = testLLVisitor._getSymbolDataFromFileSystem("James", SourceInfo.NONE, true, true);
2595          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          testLLVisitor._package = "myPackage";
2601          assertEquals("Should return NOT_FOUND-does not exist.", 
2602                       SymbolData.NOT_FOUND, 
2603                       testLLVisitor._getSymbolDataFromFileSystem("WrongPackage.className", 
2604                                                                   SourceInfo.NONE, true, false));
2605          assertEquals("Should be no errors", 0, errors.size());
2606          
2607          // Now, test case where class file still exists, but java file is gone.
2608          testLLVisitor._package = "";
2609          testLLVisitor._file = new File("testFiles/Fake.dj0");
2610          LinkedList<VariableData> vds = new LinkedList<VariableData>();
2611          result = testLLVisitor._getSymbolDataFromFileSystem("Doh", SourceInfo.NONE, true, true);
2612          vds.addLast(new VariableData("i", PACKAGE_MAV, SymbolData.INT_TYPE, true, result));
2613          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        public void testGetSymbolData() {
2623          testLLVisitor._package="";
2624          testLLVisitor._file = new File("testFiles/akdjskj");
2625          
2626          // No dot case
2627          SymbolData sd1 = new SymbolData("Wow");
2628          testLLVisitor.symbolTable.put("Wow", sd1);
2629          assertEquals("Should return an equal SymbolData", 
2630                       sd1, testLLVisitor.getQualifiedSymbolData("Wow", SourceInfo.NONE, true));
2631          assertFalse("Should not be a continuation", sd1.isContinuation());  // There is a pre-existing class file Wow!
2632          
2633          // Invalid case
2634          SymbolData result = testLLVisitor.getSymbolData("ima.invalid", SourceInfo.NONE, true, false);
2635          assertEquals("Should return null-invalid class name", null, result);
2636          assertEquals("There should not be any errors", 0, testLLVisitor.errors.size());
2637          
2638          // Fully qualified class name
2639          testLLVisitor._package="fully.qualified";
2640          testLLVisitor._file = new File("testFiles/fully/qualified/Fake.dj0");
2641          SymbolData sd2 = new SymbolData("fully.qualified.Symbol");
2642          testLLVisitor.symbolTable.put("fully.qualified.Symbol", sd2);
2643          
2644          result = testLLVisitor.getSymbolData("fully.qualified.Symbol", SourceInfo.NONE, true, false);
2645          
2646          assertEquals("Should return sd2, resolved.", sd2, result);
2647          assertTrue("sd2 should be resolved", sd2.isContinuation());
2648          
2649          // Inner class
2650          sd1.setName("fully.qualified.Woah.Wow");
2651          sd2.addInnerClass(sd1);
2652          sd1.setOuterData(sd2);
2653          testLLVisitor.symbolTable.put("fully.qualified.Woah.Wow", sd1);
2654          testLLVisitor.symbolTable.remove("Wow");
2655          sd1.setIsContinuation(false);
2656          result = testLLVisitor.getSymbolData("fully.qualified.Woah.Wow", SourceInfo.NONE, true, false);
2657          assertEquals("Should return sd1 (the inner class!)", sd1, result);
2658          
2659          // Inner inner class
2660          SymbolData sd3 = new SymbolData("fully.qualified.Woah.Wow.James");
2661          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          sd3.setOuterData(sd1);
2665    //      System.err.println("INNER CLASS LOOKUP YIELDS: " + sd1.getInnerClassOrInterface("James"));
2666          result = testLLVisitor.getSymbolData("fully.qualified.Woah.Wow.James", SourceInfo.NONE, true, false);
2667          assertEquals("Should return sd3", sd3, result);
2668        }
2669        
2670        public void testGetQualifiedSymbolData() {
2671          // Primitive types
2672          assertEquals("should return the int SymbolData", SymbolData.INT_TYPE, 
2673                       testLLVisitor.getQualifiedSymbolData("int", SourceInfo.NONE, true, true, true));
2674          assertEquals("should return the byte SymbolData", SymbolData.BYTE_TYPE, 
2675                       testLLVisitor.getQualifiedSymbolData("byte", SourceInfo.NONE, false, false, false));
2676          
2677          // Array types
2678          ArrayData ad = new ArrayData(SymbolData.INT_TYPE, testLLVisitor, SourceInfo.NONE);
2679          SymbolData result = testLLVisitor.getQualifiedSymbolData("int[]", SourceInfo.NONE, true, true, true);
2680          ad.getVars().get(0).setEnclosingData(result);  //.equals(...) on VariableData compares enclosing datas with ==.
2681          ad.getMethods().get(0).setEnclosingData(result.getMethods().get(0).getEnclosingData()); //similar hack
2682          assertEquals("should return the array type", ad, result);
2683          
2684          // Qualified types
2685          SymbolData sd = new SymbolData("java.lang.System");
2686          LanguageLevelConverter.symbolTable.put("java.lang.System", sd);
2687          assertEquals("should return the same sd", sd, 
2688                       testLLVisitor.getQualifiedSymbolData("java.lang.System", SourceInfo.NONE, false, true, true));
2689          assertTrue("should be a continuation", sd.isContinuation());
2690          assertEquals("should return the now resolved sd", sd, 
2691                       testLLVisitor.getQualifiedSymbolData("java.lang.System", SourceInfo.NONE, true, false, true));
2692          assertFalse("should not be a continuation", sd.isContinuation());
2693          
2694          // In this file
2695          sd = new SymbolData("fully.qualified.Qwerty");
2696          LanguageLevelConverter.symbolTable.put("fully.qualified.Qwerty", sd);
2697          testLLVisitor._classesInThisFile.add("fully.qualified.Qwerty");
2698          // Use a ElementaryVisitor so lookupFromClassesToBeParsed will actually visit the ClassDef.
2699          IntermediateVisitor bv = new IntermediateVisitor(new File(""), 
2700                                                           errors, 
2701                                                           continuations,
2702                                                           fixUps,
2703                                                           new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>());
2704          bv._package = "fully.qualified";
2705          bv._file = new File("testFiles/fully/qualified/Fake.dj0");
2706          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          bv._classesInThisFile.add("fully.qualified.Qwerty" /*, new Pair<TypeDefBase, LanguageLevelVisitor>(cd, bv)*/);
2714          assertEquals("should return sd the continuation", sd, 
2715                       bv.getSymbolData("Qwerty", SourceInfo.NONE, true, true));
2716          assertTrue("should be a continuation", sd.isContinuation());
2717          assertEquals("should also return a continuation", sd, 
2718                       bv.getQualifiedSymbolData("fully.qualified.Qwerty", SourceInfo.NONE, false, false, true));
2719          assertTrue("should be a continuation", sd.isContinuation());
2720          
2721          // Imported files
2722          testLLVisitor._importedFiles.addLast("a.b.c");
2723          sd = new SymbolData("a.b.c");
2724    //      System.err.println("SymbolData for 'a.b.c' is " + sd);
2725          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          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          assertTrue("should be a continuation", sd.isContinuation());
2733          
2734          testLLVisitor._package="fully.qualified";
2735          testLLVisitor._file = new File("testFiles/fully/qualified/Fake.dj0");
2736          testLLVisitor._importedFiles.addLast("fully.qualified.Woah");
2737          SymbolData sd2 = new SymbolData("fully.qualified.Woah");
2738          sd2.setIsContinuation(false);
2739          LanguageLevelConverter.symbolTable.put("fully.qualified.Woah", sd2);
2740          result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, true, false, true);
2741    //      System.err.println("result for 'fully.qualifed.Woah' is " + result);
2742          assertEquals("should find the resolved symbol data in the symbol table", sd2, result);
2743          assertFalse("should not be a continuation", sd2.isContinuation());
2744          
2745          // File System
2746          testLLVisitor._importedFiles.clear();
2747          testLLVisitor.visitedFiles.clear();
2748          LanguageLevelConverter.symbolTable.remove("fully.qualified.Woah");
2749          sd2 = new SymbolData("fully.qualified.Woah");
2750          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          result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, false, false, true);
2757          
2758          assertEquals("Should return sd2, unresolved.", sd2, result);
2759          assertTrue("sd2 should still be unresolved", sd2.isContinuation());
2760          
2761          result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, false, false, true);
2762          assertEquals("Should return sd2, now unresolved.", sd2, result);
2763          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          result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, true, false, true);
2768          assertEquals("Should return sd2, now resolved.", sd2, result);
2769          assertFalse("sd2 should now be resolved", sd2.isContinuation());
2770          
2771          // Imported Packages
2772          LanguageLevelConverter.symbolTable.remove("fully.qualified.Woah");
2773          testLLVisitor.visitedFiles.clear();
2774          testLLVisitor._file = new File("testFiles/Fake.dj0");
2775          testLLVisitor._package = "";
2776          testLLVisitor._importedPackages.addLast("fully.qualified");
2777          sd2 = new SymbolData("fully.qualified.Woah");
2778          LanguageLevelConverter.symbolTable.put("fully.qualified.Woah", sd2);
2779          assertEquals("should find the unresolved symbol data in the symbol table", sd2, 
2780                       testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, false, false, true));
2781          assertTrue("should not be a continuation", sd2.isContinuation());
2782          
2783          sd2.setIsContinuation(false);
2784          result = testLLVisitor.getQualifiedSymbolData("fully.qualified.Woah", SourceInfo.NONE, true, false, true);
2785          assertEquals("should find the resolved symbol data in the symbol table", sd2, result);
2786          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          SymbolData stringSD = new SymbolData("java.lang.String");
2791          SymbolData newsd1 = testLLVisitor.getQualifiedSymbolData("java.lang.String", SourceInfo.NONE, true, true, true);
2792          assertEquals("should have correct name.", stringSD.getName(), newsd1.getName());
2793          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          LanguageLevelConverter.symbolTable.put("random.package.String", new SymbolData("random.package.String"));
2797    //      LanguageLevelConverter.symbolTable.put("java.lang.Object", new SymbolData("java.lang.Object"));
2798          testLLVisitor._importedPackages.addLast("random.package");
2799          result = testLLVisitor.getSymbolData("String", SourceInfo.NONE);
2800          assertEquals("Result should be null", null, result);
2801          assertEquals("There should be 1 error", 1, errors.size());
2802          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          LanguageLevelConverter.symbolTable.remove("random.package.String");
2807          
2808        }
2809        
2810        public void test_forModifiersAndVisibility() {
2811          // Test access specifiers.
2812          testLLVisitor.forModifiersAndVisibility(PUBLIC_MAV);
2813          testLLVisitor.forModifiersAndVisibility(PROTECTED_MAV);
2814          testLLVisitor.forModifiersAndVisibility(PRIVATE_MAV);
2815          testLLVisitor.forModifiersAndVisibility(PACKAGE_MAV);
2816          
2817          
2818          assertEquals("There should be no errors.", 0, errors.size());
2819          
2820          // Test "public", "private"
2821          ModifiersAndVisibility testMav = 
2822            new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "private"});
2823          testLLVisitor.forModifiersAndVisibility(testMav);
2824          assertEquals("There should be one error.", 1, errors.size());
2825          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          testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public", "abstract"});
2830          testLLVisitor.forModifiersAndVisibility(testMav);
2831          assertEquals("Still only one error.", 1, errors.size());
2832          
2833          // Test "abstract", "final"
2834          testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract", "final"});
2835          testLLVisitor.forModifiersAndVisibility(testMav);
2836          assertEquals("There should be two errors.", 2, errors.size());
2837          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          testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final", "abstract"});
2842          testLLVisitor.forModifiersAndVisibility(testMav);
2843          assertEquals("There should still be two errors.", 2, errors.size());  // Generated error is duplicate
2844          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          testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"volatile", "final"});
2849          testLLVisitor.forModifiersAndVisibility(testMav);
2850          assertEquals("There should be three errors.", 3, errors.size());  // Generated one new error
2851          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          testMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static", "final", "static"});
2856          testLLVisitor.forModifiersAndVisibility(testMav);
2857          assertEquals("There should be four errors.", 4, errors.size());  // Generated one new error
2858          assertEquals("The error message should be correct.", "Duplicate modifier: static", errors.get(3).getFirst());
2859        }
2860        
2861        public void testGetQualifiedClassName() {
2862          //first test when the package is empty:
2863          testLLVisitor._package="";
2864          assertEquals("Should not change qualified name.", "simpson.Bart", 
2865                       testLLVisitor.getQualifiedClassName("simpson.Bart"));
2866          assertEquals("Should not change unqualified name.", "Lisa", testLLVisitor.getQualifiedClassName("Lisa"));
2867          
2868          //now test when package is not empty.
2869          testLLVisitor._package="myPackage";
2870          assertEquals("Should not change properly packaged qualified name.", "myPackage.Snowball", 
2871                       testLLVisitor.getQualifiedClassName("myPackage.Snowball"));
2872          assertEquals("Should append package to front of not fully packaged name", "myPackage.simpson.Snowball", 
2873                       testLLVisitor.getQualifiedClassName("simpson.Snowball"));
2874          assertEquals("Should append package to front of unqualified class name.", "myPackage.Grandpa", 
2875                       testLLVisitor.getQualifiedClassName("Grandpa"));
2876        }
2877        
2878        public void testAddSymbolData() {
2879          /**Put super class in symbol table.*/
2880          SymbolData obj = LanguageLevelConverter.symbolTable.get("java.lang.Object");
2881    //      obj.setIsContinuation(false);
2882    //      LanguageLevelConverter.symbolTable.put("java.lang.Object", obj);
2883          
2884          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          SymbolData sd = new SymbolData("Awesome"); /**Create a continuation and store it in table.*/
2892          sd.setSuperClass(LanguageLevelConverter.symbolTable.get("java.lang.Object"));
2893          LanguageLevelConverter.symbolTable.put("Awesome", sd);
2894          SymbolData result = testLLVisitor.defineSymbolData(cd, "Awesome");
2895          assertFalse("result should not be a continuation.", result.isContinuation());
2896          assertFalse("sd should also no longer be a continuation.", sd.isContinuation());
2897          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          assertEquals("Should return null, because it is already in the SymbolTable.", null, 
2904                       testLLVisitor.defineSymbolData(cd, "Awesome"));
2905          assertEquals("Length of errors should now be 1.", 1, errors.size());
2906          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        public void test_variableDeclaration2VariableData() {
2913          VariableDeclarator[] d1 = {
2914            new UninitializedVariableDeclarator(SourceInfo.NONE, 
2915                                                new PrimitiveType(SourceInfo.NONE, "int"), 
2916                                                new Word(SourceInfo.NONE, "i")) };
2917          VariableDeclaration vd1 = new VariableDeclaration(SourceInfo.NONE,PUBLIC_MAV, d1); 
2918          VariableData[] vdata1 = { new VariableData("i", PUBLIC_MAV, SymbolData.INT_TYPE, false, _sd1) };
2919          
2920          assertTrue("Should properly recognize a basic VariableDeclaration", 
2921                     arrayEquals(vdata1, testLLVisitor._variableDeclaration2VariableData(vd1, _sd1)));
2922          
2923          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          VariableDeclaration vd2 = new VariableDeclaration(SourceInfo.NONE,PRIVATE_MAV, d2); 
2932          VariableData bData = new VariableData("b", PRIVATE_MAV, SymbolData.BOOLEAN_TYPE, true, _sd1);
2933          bData.setHasInitializer(true);
2934          VariableData[] vdata2 = {new VariableData("i", PRIVATE_MAV, SymbolData.INT_TYPE, false, _sd1),
2935            bData};
2936          
2937          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          VariableDeclarator[] d3 = { 
2942            new UninitializedVariableDeclarator(SourceInfo.NONE, 
2943                                                new ClassOrInterfaceType(SourceInfo.NONE, "LinkedList", new Type[0]), 
2944                                                new Word(SourceInfo.NONE, "myList"))};
2945          VariableDeclaration vd3 = new VariableDeclaration(SourceInfo.NONE, PRIVATE_MAV, d3);
2946          testLLVisitor._variableDeclaration2VariableData(vd3, _sd1);
2947          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        public void test_addError() {
2954          LinkedList<Pair<String, JExpressionIF>> e = new LinkedList<Pair<String, JExpressionIF>>();
2955          
2956          NullLiteral nl = new NullLiteral(SourceInfo.NONE);
2957          NullLiteral nl2 = new NullLiteral(SourceInfo.NONE);
2958          
2959          e.addLast(new Pair<String,JExpressionIF>("Boy, is this an error!", nl));
2960          _addError("Boy, is this an error!", nl);
2961          
2962          assertTrue("An error should have been added.", _errorAdded);
2963          assertEquals("The errors list should be correct.", e, errors);
2964          
2965          e.addLast(new Pair<String,JExpressionIF>("Error again!", nl2));
2966          _addError("Error again!", nl2);
2967          
2968          assertTrue("Another error should have been aded.", _errorAdded);
2969          assertEquals("The new errors list should be correct.", e, errors);
2970        }
2971        
2972        public void test_addAndIgnoreError() {
2973          LinkedList<Pair<String, JExpressionIF>> e = new LinkedList<Pair<String, JExpressionIF>>();
2974          
2975          NullLiteral nl = new NullLiteral(SourceInfo.NONE);
2976          NullLiteral nl2 = new NullLiteral(SourceInfo.NONE);
2977          
2978          _errorAdded = false;
2979          
2980          e.addLast(new Pair<String,JExpressionIF>("Nobody pays attention to me!", nl));
2981          _addAndIgnoreError("Nobody pays attention to me!", nl);
2982          
2983          assertFalse("_errorAdded should be false.", _errorAdded);
2984          assertEquals("The errors list should be correct.", e, errors);
2985          
2986          e.addLast(new Pair<String,JExpressionIF>("Cellophane, I'm Mr. Cellophane", nl2));
2987          _addAndIgnoreError("Cellophane, I'm Mr. Cellophane", nl2);
2988          
2989          assertFalse("errorAdded should still be false.", _errorAdded);
2990          assertEquals("The new errors list should be correct.", e, errors);
2991          
2992          _errorAdded = true;
2993          try {
2994            _addAndIgnoreError("This should throw an exception, because _errorAdded is true.", nl);
2995            assertTrue("An error should have been thrown!", false);
2996          }
2997          catch (RuntimeException exc) {
2998            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          _errorAdded = false;
3004        }
3005        
3006        public void test_checkError() {
3007          _errorAdded = false;
3008          assertFalse("_checkError should return false", _checkError());
3009          
3010          _errorAdded = true;
3011          assertTrue("_checkError should return true", _checkError());
3012          assertFalse("_checkError should have set _errorAdded to false.", _errorAdded);
3013        }    
3014        
3015        public void testForClassDefDoFirst() {      
3016          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          testLLVisitor.forClassDefDoFirst(cd);
3024          assertEquals("There should be no errors.", 0, errors.size());
3025          testLLVisitor._importedFiles.addLast(new File("Awesome").getAbsolutePath());
3026          testLLVisitor.forClassDefDoFirst(cd);
3027          assertEquals("There should be one error.", 1, errors.size());
3028          assertEquals("The error message should be correct.", "The class Awesome was already imported.", 
3029                       errors.get(0).getFirst());
3030          
3031          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          testLLVisitor.forClassDefDoFirst(cd2);
3038          assertEquals("There should be 2 errors", 2, errors.size());
3039          assertEquals("The 2nd error message should be correct", "Top level classes cannot be private", 
3040                       errors.get(1).getFirst());
3041          
3042        }
3043        
3044        public void testForInterfaceDefDoFirst() {
3045          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          testLLVisitor.forInterfaceDefDoFirst(id);
3050          assertEquals("There should be no errors.", 0, errors.size());
3051          
3052          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          testLLVisitor.forInterfaceDefDoFirst(id2);
3057          assertEquals("There should be 1 errors", 1, errors.size());
3058          assertEquals("The error message should be correct", "Top level interfaces cannot be private", 
3059                       errors.get(0).getFirst());
3060          
3061          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          testLLVisitor.forInterfaceDefDoFirst(id3);
3066          assertEquals("There should be 2 errors", 2, errors.size());
3067          assertEquals("The error message should be correct", "Interfaces cannot be final", errors.get(1).getFirst());      
3068        }
3069        
3070        public void testForInnerInterfaceDefDoFirst() {
3071          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          id.visit(testLLVisitor);
3076          assertEquals("There should be no errors.", 0, errors.size());
3077          
3078          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          id2.visit(testLLVisitor);
3083          assertEquals("There should be 1 error", 1, errors.size());
3084          assertEquals("The error message should be correct", "Interfaces cannot be final", errors.get(0).getFirst());   
3085        }
3086        
3087        public void testForPackageStatementOnly() {
3088          Word[] words = new Word[] {new Word(SourceInfo.NONE, "alpha"),
3089            new Word(SourceInfo.NONE, "beta")};
3090          CompoundWord cw = new CompoundWord(SourceInfo.NONE, words);
3091          PackageStatement ps = new PackageStatement(SourceInfo.NONE, cw);
3092          testLLVisitor._file = new File("alpha/beta/delta");
3093          testLLVisitor.forPackageStatementOnly(ps);
3094          assertEquals("_package should be set correctly.", "alpha.beta", testLLVisitor._package);
3095          assertEquals("There should be no errors.", 0, errors.size());
3096          testLLVisitor._file = new File("alpha/beta/beta/delta");
3097          testLLVisitor.forPackageStatementOnly(ps);
3098          assertEquals("_package should be set correctly.", "alpha.beta", testLLVisitor._package);
3099          assertEquals("There should be one error.", 1, errors.size());
3100          assertEquals("The error message should be correct.", "The package name must mirror your file's directory.", 
3101                       errors.get(0).getFirst());
3102        }
3103        
3104        public void testForClassImportStatementOnly() {
3105          
3106          //Test one that works
3107          Word[] words = new Word[] { new Word(SourceInfo.NONE, "alpha"), new Word(SourceInfo.NONE, "beta")};
3108          CompoundWord cw = new CompoundWord(SourceInfo.NONE, words);
3109          ClassImportStatement cis = new ClassImportStatement(SourceInfo.NONE, cw);
3110          SymbolData sd = new SymbolData("alpha.beta");
3111          testLLVisitor.forClassImportStatementOnly(cis);
3112          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          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          Word[] words2 = new Word[] { new Word(SourceInfo.NONE, "gamma"), new Word(SourceInfo.NONE, "beta")};
3120          CompoundWord cw2 = new CompoundWord(SourceInfo.NONE, words2);
3121          ClassImportStatement cis2 = new ClassImportStatement(SourceInfo.NONE, cw2);
3122          cis2.visit(testLLVisitor);
3123          
3124          assertEquals("There should be one error", 1, errors.size());
3125          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        public void testForPackageImportStatementOnly() {
3144          //Test one that works
3145          Word[] words = new Word[] {new Word(SourceInfo.NONE, "alpha"),
3146            new Word(SourceInfo.NONE, "beta")};
3147          CompoundWord cw = new CompoundWord(SourceInfo.NONE, words);
3148          PackageImportStatement cis = new PackageImportStatement(SourceInfo.NONE, cw);
3149          SymbolData sd = new SymbolData("alpha.beta");
3150          testLLVisitor.forPackageImportStatementOnly(cis);
3151          assertEquals("There should be no errorrs", 0, errors.size());
3152          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          testLLVisitor._package = "myPackage";
3157          Word[] words3 = new Word[] {new Word(SourceInfo.NONE, "myPackage"), new Word(SourceInfo.NONE, 
3158                                                                                                  "cookie")};
3159          CompoundWord cw3 = new CompoundWord(SourceInfo.NONE, words3);
3160          PackageImportStatement pis = new PackageImportStatement(SourceInfo.NONE, cw3);
3161          pis.visit(testLLVisitor);
3162          
3163          assertEquals("There should be no errors", 0, errors.size());
3164          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          Word[] words2 = new Word[] {new Word(SourceInfo.NONE, "myPackage")};
3171          CompoundWord cw2 = new CompoundWord(SourceInfo.NONE, words2);
3172          PackageImportStatement pis2 = new PackageImportStatement(SourceInfo.NONE, cw2);
3173          pis2.visit(testLLVisitor);
3174          
3175          assertEquals("There should now be 1 errors", 1, errors.size());
3176          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        public void testForSourceFile() {
3182          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          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          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          SourceFile sf = new SourceFile(SourceInfo.NONE,
3199                                         new PackageStatement[0],
3200                                         new ImportStatement[0],
3201                                         new TypeDefBase[] {cd, cd2, id});
3202          testLLVisitor.forSourceFile(sf);
3203          
3204          assertTrue("_classesInThisFile should contain the two ClassDefs.", 
3205                     testLLVisitor._classesInThisFile.contains("Awesome"));
3206          assertTrue("_classesInThisFile should contain the two ClassDefs.", 
3207                     testLLVisitor._classesInThisFile.contains("Gnarly"));
3208          
3209          assertTrue("_classesInThisFile should contain the InterfaceDef", 
3210                     testLLVisitor._classesInThisFile.contains("NiftyWords"));
3211          assertTrue("_classesInThisFile should contain the two ClassDefs.", 
3212                     testLLVisitor._classesInThisFile.contains("Awesome"));
3213          assertTrue("_classesInThisFile should contain the two ClassDefs.", 
3214                     testLLVisitor._classesInThisFile.contains("Gnarly"));
3215          assertTrue("_classesInThisFile should contain the InterfaceDef", 
3216                     testLLVisitor._classesInThisFile.contains("NiftyWords"));
3217          
3218        }
3219        
3220        public void testReferenceType2String() {
3221          // Try a TypeVariable
3222          TypeVariable tv = new TypeVariable(SourceInfo.NONE, "T");
3223          String[] result = testLLVisitor.referenceType2String(new ReferenceType[] { tv });
3224          assertEquals("There should not be any errors.", 0, errors.size());
3225          assertEquals("Results should have one String.", 1, result.length);
3226          assertEquals("The String should be \"T\".", "T", result[0]);
3227          
3228          // Try a ClassOrInterfaceType
3229          ClassOrInterfaceType coit = new ClassOrInterfaceType(SourceInfo.NONE, 
3230                                                               "MyClass", 
3231                                                               new Type[] { new TypeVariable(SourceInfo.NONE, "T"),
3232            new TypeVariable(SourceInfo.NONE, "U")}
3233          );
3234          result = testLLVisitor.referenceType2String(new ReferenceType[] { tv, coit });
3235          assertEquals("There should not be any errors.", 0, errors.size());
3236          assertEquals("Results should have two Strings.", 2, result.length);
3237          assertEquals("The first String should be \"T\".", "T", result[0]);
3238          assertEquals("The second String should be \"MyClass\".", "MyClass", result[1]);
3239          
3240          // Try a MemberType
3241          MemberType mt = new MemberType(SourceInfo.NONE,
3242                                         "MyClass.MyClass2",
3243                                         coit,
3244                                         new ClassOrInterfaceType(SourceInfo.NONE, 
3245                                                                  "MyClass2", 
3246                                                                  new Type[0]));
3247          result = testLLVisitor.referenceType2String(new ReferenceType[] { mt });
3248          assertEquals("There should not be any errors.", 0, errors.size());
3249          assertEquals("Results should have one String.", 1, result.length);
3250          assertEquals("The first String should be \"MyClass.MyClass2\".", "MyClass.MyClass2", result[0]);
3251        }
3252        
3253        
3254        public void testExceptionsInSymbolTable() {
3255                
3256          // Make sure that exceptions are being added to symbol table 
3257          ClassOrInterfaceType exceptionType = 
3258            new ClassOrInterfaceType(SourceInfo.NONE, "java.util.prefs.BackingStoreException", new Type[0]);
3259          ParenthesizedExpressionList expList = new ParenthesizedExpressionList(SourceInfo.NONE, new Expression[0]);
3260          
3261          BracedBody bb = 
3262            new BracedBody(SourceInfo.NONE, 
3263                           new BodyItemI[] { new ThrowStatement(SourceInfo.NONE, 
3264                                                                new SimpleNamedClassInstantiation(SourceInfo.NONE, 
3265                                                                                                  exceptionType, 
3266                                                                                                  expList))});
3267          bb.visit(testLLVisitor);
3268          assertNotNull("The SymbolTable should have java.util.prefs.BackingStoreException", 
3269                      LanguageLevelConverter.symbolTable.get("java.util.prefs.BackingStoreException"));
3270          
3271        }
3272        
3273        public void testShouldBreak() {
3274          //shift assignment expressions:
3275          LeftShiftAssignmentExpression shift1 = 
3276            new LeftShiftAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3277                                              new NullLiteral(SourceInfo.NONE));
3278          RightUnsignedShiftAssignmentExpression shift2 = 
3279            new RightUnsignedShiftAssignmentExpression(SourceInfo.NONE, 
3280                                                       new NullLiteral(SourceInfo.NONE), 
3281                                                       new NullLiteral(SourceInfo.NONE));
3282          RightSignedShiftAssignmentExpression shift3 = 
3283            new RightSignedShiftAssignmentExpression(SourceInfo.NONE, 
3284                                                     new NullLiteral(SourceInfo.NONE), 
3285                                                     new NullLiteral(SourceInfo.NONE));
3286          
3287          
3288          shift1.visit(testLLVisitor);
3289          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          shift2.visit(testLLVisitor);
3295          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          shift3.visit(testLLVisitor);
3301          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          BitwiseAndAssignmentExpression bit1 = 
3308            new BitwiseAndAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3309                                               new NullLiteral(SourceInfo.NONE));
3310          BitwiseOrAssignmentExpression bit2 = 
3311            new BitwiseOrAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3312                                              new NullLiteral(SourceInfo.NONE));
3313          BitwiseXorAssignmentExpression bit3 = 
3314            new BitwiseXorAssignmentExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3315                                               new NullLiteral(SourceInfo.NONE));
3316          
3317          bit1.visit(testLLVisitor);
3318          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          bit2.visit(testLLVisitor);
3323          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          bit3.visit(testLLVisitor);
3328          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          BitwiseAndExpression bit4 = 
3334            new BitwiseAndExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3335                                     new NullLiteral(SourceInfo.NONE));
3336          BitwiseOrExpression bit5 = 
3337            new BitwiseOrExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3338                                    new NullLiteral(SourceInfo.NONE));
3339          BitwiseXorExpression bit6 = 
3340            new BitwiseXorExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3341                                     new NullLiteral(SourceInfo.NONE));
3342          BitwiseNotExpression bit7 = 
3343            new BitwiseNotExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE));
3344          
3345          
3346          bit4.visit(testLLVisitor);
3347          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          bit5.visit(testLLVisitor);
3354          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          bit6.visit(testLLVisitor);
3361          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          bit7.visit(testLLVisitor);
3366          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          LeftShiftExpression shift4 = 
3374            new LeftShiftExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3375                                    new NullLiteral(SourceInfo.NONE));
3376          RightUnsignedShiftExpression shift5 = 
3377            new RightUnsignedShiftExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3378                                             new NullLiteral(SourceInfo.NONE));
3379          RightSignedShiftExpression shift6 = 
3380            new RightSignedShiftExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3381                                           new NullLiteral(SourceInfo.NONE));
3382          
3383          shift4.visit(testLLVisitor);
3384          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          shift5.visit(testLLVisitor);
3389          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          shift6.visit(testLLVisitor);
3394          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          EmptyExpression e = new EmptyExpression(SourceInfo.NONE);
3400          e.visit(testLLVisitor);
3401          assertEquals("Should be 1 error", 1, errors.size());
3402          assertEquals("Error message should be correct", "You appear to be missing an expression here", 
3403                       errors.getLast().getFirst());
3404          
3405          //noop expression
3406          NoOpExpression noop = 
3407            new NoOpExpression(SourceInfo.NONE, new NullLiteral(SourceInfo.NONE), 
3408                               new NullLiteral(SourceInfo.NONE));
3409          noop.visit(testLLVisitor);
3410          assertEquals("Should be 2 errors", 2, errors.size());
3411          assertEquals("Error message should be correct", "You are missing a binary operator here", 
3412                       errors.getLast().getFirst());
3413        }
3414        
3415        public void testIsConstructor() {
3416          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          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          _sd2.setOuterData(_sd1);
3423          _sd1.addInnerClass(_sd2);
3424          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          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          assertTrue(testLLVisitor.isConstructor(constr));
3433          
3434          //wrong outer
3435          assertFalse(testLLVisitor.isConstructor(notRightOuter));
3436          
3437          //wrong name
3438          assertFalse(testLLVisitor.isConstructor(notRightName));
3439          
3440          //wrong return type
3441          assertFalse(testLLVisitor.isConstructor(notRightReturnType));
3442          
3443          //not a method data
3444          assertFalse(testLLVisitor.isConstructor(_sd1));
3445        } 
3446      }
3447    }