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