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    package edu.rice.cs.javalanglevels;
037    
038    import edu.rice.cs.javalanglevels.tree.*;
039    import edu.rice.cs.javalanglevels.parser.JExprParser;
040    import java.util.*;
041    
042    import junit.framework.TestCase;
043    
044    import edu.rice.cs.plt.reflect.JavaVersion;
045    
046    /** Represents the data for a given class.  There are two states of SymbolData.  One is a continuation which
047      * is created when a type is referenced, but the corresponding class has not been read for its members.  The
048      * other is a complete SymbolData containing all of the member data.
049      */
050    public class SymbolData extends TypeData {
051      
052      /***************Singleton primitive SymbolDatas********************/
053      
054      /** This anonymous class represents the boolean primitive type */
055      public static final SymbolData BOOLEAN_TYPE = new PrimitiveData("boolean") {
056        
057        /** You can only cast a boolean primitive to a boolean primitive or a Boolean object (in 1.5). */
058        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
059          return isAssignableTo(castTo, version);
060        }
061        
062        /** Returns true if the specified SymbolData is a boolean type. */
063        public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
064          if (toCheck == null) return false;
065          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !toCheck.isPrimitiveType()) {
066            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Boolean");
067            return (autoBoxMe != null && autoBoxMe.isAssignableTo(toCheck, version));
068          }
069          return toCheck == BOOLEAN_TYPE;
070        }
071      };
072      
073      /** This anonymous class represents the char primitive type. */
074      public static final SymbolData CHAR_TYPE = new PrimitiveData("char") {
075        
076        /** You can cast a char to a char, int, long, float, double or short or byte or Character object (in 1.5) */
077        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
078          return isAssignableTo(castTo, version) || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
079        }
080    
081        /** You can assign a char primitive to a char, int, long, float, double or Character object (in 1.5) */
082        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
083          if (assignTo == null) return false;
084          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
085            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Character");
086            return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
087          }
088    
089          return assignTo == SymbolData.INT_TYPE || 
090            assignTo == SymbolData.LONG_TYPE || 
091            assignTo == SymbolData.FLOAT_TYPE || 
092            assignTo == SymbolData.DOUBLE_TYPE || 
093            assignTo == SymbolData.CHAR_TYPE;
094        }
095      };
096      
097      /** This anonymous class represents the byte primitive type */
098      public static final SymbolData BYTE_TYPE = new PrimitiveData("byte") {
099        
100        /** You can cast a byte primitive to a char, int, long, float, double or short or byte or Byte object (in 1.5) */
101        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
102          return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE;
103        }
104    
105        /** You can assign a byte primitive to a byte, short, int, long, float, double, or Byte object(in 1.5). */
106        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
107          if (assignTo == null) return false;
108    
109          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
110            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Byte");
111            return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
112          }
113    
114          return assignTo == SymbolData.BYTE_TYPE || 
115            assignTo == SymbolData.SHORT_TYPE || 
116            assignTo == SymbolData.INT_TYPE || 
117            assignTo == SymbolData.LONG_TYPE || 
118            assignTo == SymbolData.FLOAT_TYPE || 
119            assignTo == SymbolData.DOUBLE_TYPE;
120        }
121      };
122    
123      /** This anonymous class represents the short primitive type. */
124      public static final SymbolData SHORT_TYPE = new PrimitiveData("short") {
125        
126        /** You can cast a short primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
127        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
128          return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.BYTE_TYPE;
129        }
130    
131        /** You can assign a short primitive to a short, int, long, float, double, or Short object(in 1.5) */
132        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
133          if (assignTo == null) return false;
134    
135          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
136            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Short");
137            return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
138          }
139          
140          return assignTo==SymbolData.SHORT_TYPE || 
141            assignTo == SymbolData.INT_TYPE || 
142            assignTo == SymbolData.LONG_TYPE || 
143            assignTo == SymbolData.FLOAT_TYPE || 
144            assignTo == SymbolData.DOUBLE_TYPE; 
145        }
146      };
147      
148      /** This anonymous class represents the int primitive type. */
149      public static final SymbolData INT_TYPE = new PrimitiveData("int") {
150        
151        /** You can cast a int primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
152        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
153          return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.SHORT_TYPE 
154            || castTo == SymbolData.BYTE_TYPE;
155        }
156    
157        /** You can assign a int primitive to a int, long, float, double, or Integer/Long/Float/Double or
158          * Number/Object type (in 1.5) */
159        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
160          if (assignTo == null) return false;
161    
162          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
163            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Integer");
164            return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
165          }
166    
167          return assignTo == SymbolData.INT_TYPE || assignTo == SymbolData.LONG_TYPE || 
168            assignTo == SymbolData.FLOAT_TYPE ||  assignTo == SymbolData.DOUBLE_TYPE;
169        }
170      };
171      
172      /** This represents the long primitive */
173      public static final SymbolData LONG_TYPE = new PrimitiveData("long"){
174        
175        /** You can cast a long primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
176        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
177          return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE || 
178            castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
179        }
180    
181        /** You can assign a long primitive to a long, float, double, or Long object(in 1.5) */
182        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
183          if (assignTo == null) {return false;}
184    
185          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
186            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Long");
187            return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
188          }
189    
190          return assignTo == SymbolData.LONG_TYPE || 
191            assignTo == SymbolData.FLOAT_TYPE || 
192            assignTo == SymbolData.DOUBLE_TYPE;
193            
194        }
195      };
196      
197      /** This represents the float primitive */
198      public static final SymbolData FLOAT_TYPE = new PrimitiveData("float"){
199        
200        /** You can cast a float primitive to a char, int, long, float, double or short or byte or Short object (in 1.5) */
201        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
202          return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE 
203            || castTo == SymbolData.LONG_TYPE || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
204        }
205    
206        /** You can assign a float primitive to a float, double, or Float object(in 1.5) */
207        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
208          if (assignTo == null) return false;
209    
210          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
211            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Float");
212            return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
213          }
214    
215          return assignTo == SymbolData.FLOAT_TYPE || assignTo == SymbolData.DOUBLE_TYPE;
216        }
217      };
218      
219      /**This represents the double primitive*/
220      public static final SymbolData DOUBLE_TYPE = new PrimitiveData("double"){
221        
222        /** A double primitive can be cast to a char, int, long, float, double, short or byte primitive or a Float
223          * or Double object,  */
224        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
225          return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE 
226            || castTo == SymbolData.LONG_TYPE || castTo == SymbolData.DOUBLE_TYPE || castTo == SymbolData.SHORT_TYPE 
227            || castTo == SymbolData.BYTE_TYPE;
228        }
229    
230        /** You can assign a double primitive to a float, double, or Float object(in 1.5) */
231        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
232          if (assignTo == null) { return false; }
233    
234          if (LanguageLevelConverter.versionSupportsAutoboxing(version) && ! assignTo.isPrimitiveType()) {
235            SymbolData autoBoxMe = LanguageLevelConverter.symbolTable.get("java.lang.Double");
236            return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
237          }
238          return assignTo == SymbolData.DOUBLE_TYPE; 
239        }
240      };
241      
242      /** Used for the void type. */
243      public static final SymbolData VOID_TYPE = new PrimitiveData("void") {
244      
245        /** A void value cannot be cast to anything */
246        public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
247        
248        /** A void value can be assigned to itself */
249        public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return this == toCheck; }
250      };
251      
252      /** Used for an exception */
253      public static final SymbolData EXCEPTION = new SymbolData("exception") {
254        /** You cannot cast an exception to anything. */
255        public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
256        
257        /** Returns true, because an exception takes the place of a return.
258          * This SymbolData is only used when the user has thrown an Exception.
259          */
260        public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return true; }
261        
262      };
263    
264      /** Used to signal a symbol table search that failed. */
265      public static final SymbolData NOT_FOUND = new SymbolData("not found") {
266      
267        /** A not-found value cannot be cast to anything */
268        public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
269        
270        /** A not-found value cannot be assigned to anything */
271        public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
272      };
273      
274     /** Singleton class representing null*/
275      public static final SymbolData NULL_TYPE = new SymbolData("null") {
276    
277        /** You can cast null to any reference type (i.e. something that is not a primitive). */
278        public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
279          return isAssignableTo(castTo, version);
280        }
281    
282        /** You can assign a null to any reference (non-primitive) type */
283        public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
284          return (assignTo != null) && ! assignTo.isPrimitiveType();
285        }
286        
287      };
288      
289      /** Used when 2 or more SymbolDatas could match*/
290      public static final SymbolData AMBIGUOUS_REFERENCE = new SymbolData("ambiguous reference") {
291        /** An ambiguous reference cannot be cast to anything */
292        public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
293        
294        /** An ambiguous reference cannot be assigned to anything */
295        public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
296      };
297      
298      /** Used when a this constructor invocation is seen. */
299      public static final SymbolData THIS_CONSTRUCTOR = new SymbolData("this constructor") {
300        /** Cannot be cast to anything */
301        public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
302        
303        /** Cannot be assigned to anything */
304        public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
305      };
306      
307      /** Used when a super constructor invocation is seen. */
308      public static final SymbolData SUPER_CONSTRUCTOR = new SymbolData("super constructor") {
309        /** Cannot be cast to anything */
310        public boolean isCastableTo(SymbolData castTo, JavaVersion version) { return false; }
311        
312        /** Cannot be assigned to anything */
313        public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) { return false; }
314      };
315    
316      /** Do some initialization*/
317      static {
318        ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
319        VOID_TYPE.setIsContinuation(false);    
320        VOID_TYPE.setMav(_publicMav);
321        NOT_FOUND.setIsContinuation(false);
322        NOT_FOUND.setMav(_publicMav);
323        EXCEPTION.setMav(_publicMav);
324        EXCEPTION.setIsContinuation(false);
325      }
326      
327      /********Instance fields***********/
328      
329      /* The inherited _name field is fully qualified. */
330      
331      /**True iff this symbol data is a continuation (i.e. hasn't been resolved)*/
332      private boolean _isContinuation;
333      
334      /* True iff this symbol corresponds to a file with an autogenerated "import junit.framework.*;" */
335      private boolean _hasAutoGeneratedJunitImport;
336    
337      /**The generic type information for this class.  Not used. */
338      private TypeParameter[] _typeParameters;
339      
340      /**List of methods defined in this class*/
341      private LinkedList<MethodData> _methods;
342      
343      /**The SymbolData corresponding to this class's super class. */
344      private SymbolData _superClass;
345      
346      /**List of SymbolDatas corresponding to super interfaces. */
347      private ArrayList<SymbolData> _interfaces;
348      
349      /**List of SymbolDatas corresponding to inner interfaces. */
350      private LinkedList<SymbolData> _innerInterfaces;
351      
352      /** Flag that is true if this SymbolData is an interface. */
353      private boolean _isInterface;
354      
355      /** Stores the package information for this symbol data.  May not be set. */
356      private String _package;
357      
358      /** Represents an instance of this class--i.e. an instantiation of it.*/
359      private InstanceData _instanceData;
360      
361      /**The current constructor count.  Incremented during first pass, decremented during second pass. */
362      private int _constructorNumber;
363      
364      /** The number of local classes, used in naming them. */
365      private int _localClassNum;
366      
367      /* The number of anonymous inner classes, used in naming them. */
368      private int _anonymousInnerClassNum;
369      
370      /** Constructors */
371      
372      /** Constructor for SymbolData
373        * @param name  The name of this class or interface
374        * @param modifiersAndVisibility  The modifiersAndVisibility of this class or interface
375        * @param typeParameters  Generic type info, not used
376        * @param superClass  The super class of this class
377        * @param interfaces  The super interfaces
378        * @param outerData  The enclosing data of this class, or null
379        */
380      public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters, 
381                        SymbolData superClass, ArrayList<SymbolData> interfaces, Data outerData) {
382        super(outerData);
383        _name = name;
384        _modifiersAndVisibility = modifiersAndVisibility;
385        _typeParameters = typeParameters;
386        _methods = new LinkedList<MethodData>();
387        _superClass = superClass;
388        _interfaces = interfaces;
389        
390        assert interfaces != null;
391        
392        for (SymbolData sd: interfaces) { addEnclosingData(sd); }
393        
394        /* Add first because we want to look at the super class first */
395        _enclosingData.addFirst(_superClass);
396        _innerClasses = new LinkedList<SymbolData>();
397        _innerInterfaces = new LinkedList<SymbolData>();
398        _isContinuation = false;
399        _hasAutoGeneratedJunitImport = false;
400        _isInterface = false;
401        _localClassNum = 0;
402        _anonymousInnerClassNum = 0;
403        _package = "";
404        _constructorNumber = 0;
405        _instanceData = new InstanceData(this);
406      }
407    
408      /** Constructor for SymbolData
409        * @param name  The name of this class or interface
410        * @param modifiersAndVisibility  The modifiersAndVisibility of this class or interface
411        * @param typeParameters  Generic type info, not used
412        * @param superClass  The super class of this class
413        * @param interfaces  The super interfaces
414        * @param outerData  The enclosing data of this class, or null
415        */
416      public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters,
417                        SymbolData superClass, ArrayList<SymbolData> interfaces, Data outerData, String pkg) {
418        this(name, modifiersAndVisibility, typeParameters, superClass, interfaces, outerData);
419        _package = pkg;
420      }
421      
422      /** This constructor is only called by Interfaces.  Thus, there is never a super class, and _isInterface
423        * is set to true.
424        * @param name  The name of this class or interface
425        * @param modifiersAndVisibility  The modifiersAndVisibility of this class or interface
426        * @param typeParameters  Generic type info, not used
427        * @param interfaces  The super interfaces
428        * @param outerData  The enclosing data of this class, or null
429        */
430      public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters,
431                        ArrayList<SymbolData> interfaces, Data outerData) {
432        this(name, modifiersAndVisibility, typeParameters, null, interfaces, outerData);
433        _isInterface = true;
434      }
435    
436      /** Creates a continuation symbol for the specified name; does not enter this name in any table. */
437      public SymbolData(String name) { this(name, SourceInfo.NONE); }
438      
439      /** Creates a continuation symbol for the specified name and source info; does not enter this name in any table. */ 
440      public SymbolData(String name, SourceInfo si) {
441        super(null);
442        _name = name;
443        _modifiersAndVisibility = new ModifiersAndVisibility(si, new String[0]);
444        _typeParameters = new TypeParameter[0];
445        _methods = new LinkedList<MethodData>();
446        _superClass = null;
447        _interfaces = new ArrayList<SymbolData>();
448        _innerClasses = new LinkedList<SymbolData>();
449        _innerInterfaces = new LinkedList<SymbolData>();
450        _isContinuation = true;
451        _isInterface = false;
452        _package = "";
453        _instanceData = new InstanceData(this);
454      }
455      
456      /** No reference type is a Primitive type. */
457      public boolean isPrimitiveType() { return false; }
458      
459      public String toString() {
460        if (_isContinuation) return "? " + _name;
461        return "!" + _name;
462      }
463    
464      /**
465       * See if this can be assigned to assignTo.
466       * An assignment is legal:
467       *   1. if this is a class type
468       *      - if assignTo is a class type, then the types must be the same, or this must be a subclass of assignTo
469       *      - if assignTo is an interface, then we must implement it.
470       *      - if assignTo is an array, then it is not assignable.
471       *  2. if this is an interface
472       *      - if assignTo is a class, assignTo must be java.lang.Object.
473       *      - if assignTo is an interface, then the types must be the same, or this must be a subinterface of assignTo.
474       *      - if assignTo is an array, then it is not assignable
475       * All of these rules are followed in isSubclassOf(), which traverses the hierarchy.
476       */
477       public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
478         if (assignTo != null) {
479           if (assignTo.isPrimitiveType() && LanguageLevelConverter.versionSupportsAutoboxing(version)) { 
480             // You never box the left, so see if this can be unboxed to be a primitive.
481             SymbolData unboxedType = this.unbox();
482             if (unboxedType == null) return false;
483             else return unboxedType.isAssignableTo(assignTo, version);
484           }
485           else return this.isSubClassOf(assignTo);
486         }
487         return false;
488       }
489      
490       /** Resolves this symbol using the visitor llv. 
491         * @return the new symbol definition. */
492       public SymbolData resolve(SourceInfo si, LanguageLevelVisitor llv) { return llv.resolveSymbol(si, this); }
493       
494       /** If this SymbolData is a wrapper class for a primitive, return the primitive type.  Else return null.
495         * @return the Primitive this SymbolData wraps, if there is one.  Otherwise return null.
496         */
497       private SymbolData unbox() {
498         String name = getName();
499         if (name.equals("java.lang.Integer")) {return SymbolData.INT_TYPE;}
500         if (name.equals("java.lang.Character")) {return SymbolData.CHAR_TYPE;}
501         if (name.equals("java.lang.Short")) {return SymbolData.SHORT_TYPE;}
502         if (name.equals("java.lang.Byte")) {return SymbolData.BYTE_TYPE;}
503         if (name.equals("java.lang.Float")) {return SymbolData.FLOAT_TYPE;}
504         if (name.equals("java.lang.Double")) {return SymbolData.DOUBLE_TYPE;}
505         if (name.equals("java.lang.Long")) {return SymbolData.LONG_TYPE;}
506         if (name.equals("java.lang.Boolean")) {return SymbolData.BOOLEAN_TYPE;}
507         return null;
508       }
509    
510      /**
511       * See if this can be cast as a castTo.
512       * A cast is legal if:
513       *   1. if both sides are the same type
514       *   2. Both are primitives and
515       *      - a widening primitive coversion is possible OR
516       *      - a narrowing primitive conversion is possible
517       *   3. this is a class type and
518       *      - castTo is a class type and one is the super class of the other
519       *      - castTo is an interface type and this is not final OR this implements castTo
520       *      - castTo is an array type, and this is Object
521       *   4. this is an interface type and
522       *      - castTo is a class type and is not final OR this implements this
523       *      - castTo is an interface type and this and castTo do not contain one or more methods with the same signature 
524       *        but different return types
525       *      - castTo is an array type and this is either Serializable or Cloneable.
526       * @param castTo  The TypeData we are trying to cast to.  (castTo) this
527       * @return true  If the cast is legal, false otherwise.
528       */
529       public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
530         if (castTo != null) {
531           if (castTo.isPrimitiveType()) { 
532             if (LanguageLevelConverter.versionSupportsAutoboxing(version)) { 
533               //You never box the left, so see if this can be unboxed to be a primitive.
534               SymbolData unboxedType = this.unbox();
535               if (unboxedType == null) {return false;}
536               else {return unboxedType.isCastableTo(castTo, version);}
537             }
538             else {return false;} //without autoboxing, cannot cast an object to a primitive
539           }
540           
541           else if (!this.isInterface()) { //we're a class
542             if (!castTo.isInterface()) {//castTo is a class or array
543               return this.isSubClassOf(castTo) || castTo.isSubClassOf(this);
544             }
545             
546             else { //castTo is an interface
547               return (!castTo.hasModifier("final") || castTo.isSubClassOf(this));
548             }
549             
550           }
551           
552           else { // this is an interface
553             
554             if (!castTo.isInterface()) {//castTo is a class or array
555               return !castTo.hasModifier("final") || castTo.isSubClassOf(this);
556             }
557             
558             else { // castTo is an interface
559               // return false if this and castTo contain methods with the same signature but different return types.
560               if (LanguageLevelConverter.versionSupportsAutoboxing(version)) return true; 
561               for (MethodData md: this.getMethods()) {
562                 if (checkDifferentReturnTypes(md, castTo, false, version)) {
563                   /* TypeChecker._addError("Types " + this.getName() + " and " + castTo.getName() + " are incompatible.  
564                      Both implement " + md.getName() + " but have different return types", md.getSourceInfo()); */
565                   return false;
566                 }
567               }
568               return true;
569             }
570           }
571         }
572         return false;
573       }
574    
575       /** Depth-first traversal of the tree of enclosing data checking to see if sd is above this SymbolData 
576         * in the class hierarchy.
577         */
578       public boolean isSubClassOf(SymbolData sd) {
579        if (sd == null) return false;
580        if (this.equals(sd)) return true;
581        if (sd.isInterface()) {
582          for (SymbolData i: _interfaces) {
583            if (i == null) continue;
584            if (i.equals(sd)) return true;
585            if (i.isSubClassOf(sd)) return true;
586          }
587        }
588    
589        if (_superClass != null) return _superClass.isSubClassOf(sd);
590        return false;
591      }
592      
593       /** Checks to see if this SymbolData is an inner class of outerClass (that is, that outerClass appears
594         * somewhere in its enclosing data chain.  If stopAtStatic flag is true, stop as soon as we see a static class
595         * in the chain.  This is because we are trying to resolve something, such as a "this" call, that cannot be seen outside
596         * of a static inner class.
597         * @param outerClass  The SymbolData we believe might be our outer class.
598         * @param stopAtStatic  boolean flag, true if we want to stop at a static outer class.
599         * @return  true if we are its inner class, false otherwise.
600         */
601      public boolean isInnerClassOf(SymbolData outerClass, boolean stopAtStatic) {
602        if (this == outerClass) return true;
603        Data outerData = this.getOuterData();
604        if (outerData == null) return false;
605        if (stopAtStatic && this.hasModifier("static")) {return false;}
606        return outerData.getSymbolData().isInnerClassOf(outerClass, stopAtStatic);
607      }
608      
609      /**@return false, since this is a SymbolData and not an InstanceData*/
610      public boolean isInstanceType() { return false; }
611    
612     /**@return this SymbolData.*/
613      public SymbolData getSymbolData() { return this; }
614      
615      /** @return the InstanceData corresponding to this class. */
616      public InstanceData getInstanceData() { return _instanceData; }
617    
618      /** Sets the InstanceData for this class to the specified value. */
619      public void setInstanceData(InstanceData id) { _instanceData = id; }
620      
621      /** @return the package */
622      public String getPackage() { return _package; }
623      
624      /** Sets the package to the specified value */
625      public void setPackage(String pkg) { _package = pkg;  }
626      
627      /** @return the generic type parameters */
628      public TypeParameter[] getTypeParameters() {
629        return _typeParameters;
630      }
631      
632      /**Set the generic type parameters to the specified value*/
633      public void setTypeParameters(TypeParameter[] typeParameters) {
634        _typeParameters = typeParameters;
635      }
636      
637      /**@return true if this is an interface*/
638      public boolean isInterface() {
639        return _isInterface;
640      }
641      
642      public void setInterface(boolean ii) {
643        _isInterface = ii;
644      }
645      
646      /**@return the list of inner interfaces*/
647      public LinkedList<SymbolData> getInnerInterfaces() {
648        return _innerInterfaces;
649      }
650      
651      /** Takes in a name and tries to match it with one of this Data's inner classes or inner interfaces.  The input string
652        * is a name relative to this SymbolData (such as B.C to request the class A.B.C from class A) and may be delimited 
653        * by '.' or '$'.  
654        * TODO; NO!!! This is broken.  '$' appears in anonymous class names and local class names, where it is NOT
655        * used as a name segment separator
656        * Checks the super class and interfaces of this SymbolData to see if the inner class or interface 
657        * can be found there.  If no matching visibile inner classes or interfaces are found, but one or more that are not 
658        * visible are found, one of the non-visibile ones will be returned.
659        * @return  The SymbolData for the matching inner class or interface or null if there isn't one or SymbolData.
660        *          AMBIGUOUS_REFERENCE if the reference is ambiguous.
661        */
662      protected SymbolData getInnerClassOrInterfaceHelper(String nameToMatch, int firstIndexOfDot) {
663        Iterator<SymbolData> iter = innerClassesAndInterfacesIterator();
664        while (iter.hasNext()) {
665          SymbolData sd = iter.next();
666          String sdName = sd.getName();
667    
668          sdName = LanguageLevelVisitor.getUnqualifiedClassName(sdName);
669          if (firstIndexOfDot == -1) {
670            if (sdName.equals(nameToMatch))
671              return sd;
672          }
673          else {
674            if (sdName.equals(nameToMatch.substring(0, firstIndexOfDot))) {
675              return sd.getInnerClassOrInterface(nameToMatch.substring(firstIndexOfDot + 1));
676            }
677          }
678        }
679        
680        SymbolData result = null;
681        SymbolData newResult = null;
682        SymbolData privateResult = null;
683        
684        // Next, look through the inner classes/interfaces of this class's super class
685        // Check accessibility, because if you cannot see the super class's inner class, you can't use it.
686        if (_superClass != null) {
687          newResult = _superClass.getInnerClassOrInterfaceHelper(nameToMatch, firstIndexOfDot);
688          if (newResult != null) {
689            SymbolData outerPiece;
690            
691            if (firstIndexOfDot > 0)
692              outerPiece = _superClass.getInnerClassOrInterfaceHelper(nameToMatch.substring(0, firstIndexOfDot), -1);
693            else outerPiece = newResult;
694            
695            if (TypeChecker.checkAccess(outerPiece.getMav(), outerPiece, this)) {result = newResult;}
696            else privateResult = newResult;
697          }
698        }
699        
700        // Next, look through the inner classes/interfaces of each of this class's interfaces
701        // Check accessibility, because if you cannot see the super class's inner class, you can't use it.
702        for (SymbolData id: _interfaces) {  // TODO: find out how null is being inserted in _interfaces
703          if (id == null) {
704    //        System.err.println("In SymbolData " + getName() + ", _interfaces contains a null entry");
705    //        assert false;
706            continue;
707          }
708           newResult = id.getInnerClassOrInterfaceHelper(nameToMatch, firstIndexOfDot);
709          if (newResult != null) {
710            SymbolData outerPiece;
711            if (firstIndexOfDot > 0) {
712              outerPiece = _superClass.getInnerClassOrInterfaceHelper(nameToMatch.substring(0, firstIndexOfDot), -1);
713            }
714            else { outerPiece = newResult; }        
715            if (TypeChecker.checkAccess(outerPiece.getMav(), outerPiece, this)) {
716              if (result == null) {result = newResult;}
717              else {return SymbolData.AMBIGUOUS_REFERENCE;}
718            }
719            else {privateResult = newResult;}
720          }
721        }
722        if (result != null) {return result;}
723        return privateResult;  //this will be null if no matching inner classes/interfaces were found.  
724      }
725      
726    
727      /**Iterate over first the inner classes and then the inner interfaces.*/
728      public Iterator<SymbolData> innerClassesAndInterfacesIterator() {
729        return new Iterator<SymbolData>() {
730          private Iterator<SymbolData> _first = _innerClasses.iterator();
731          private Iterator<SymbolData> _second = _innerInterfaces.iterator();
732          
733          public boolean hasNext() { return _first.hasNext() || _second.hasNext(); }
734          
735          public SymbolData next() {
736            if (_first.hasNext()) return _first.next();
737            else return _second.next();
738          }
739          
740          public void remove() { throw new UnsupportedOperationException(); }
741        };
742      }
743      
744      
745      /**Add the specified innerInterface to the list of innerInterfaces*/
746      public void addInnerInterface(SymbolData innerInterface) { _innerInterfaces.addLast(innerInterface); }
747      
748      /**Increment the local class num and return it*/
749      public int preincrementLocalClassNum() { return ++_localClassNum; }
750      
751      /**Set the anonymous inner class num to the specified value*/
752      public void setAnonymousInnerClassNum(int i) { _anonymousInnerClassNum=i; }
753      
754      /**Increment the anonymous inner class num, and return it*/
755      public int preincrementAnonymousInnerClassNum() { return ++_anonymousInnerClassNum; }
756      
757      /**@return the anonymous inner class num*/
758      public int getAnonymousInnerClassNum() { return _anonymousInnerClassNum; }
759      
760      /**Return the local class num, and then decrement it*/
761      public int postdecrementLocalClassNum() { return _localClassNum--; }
762      
763      /**Return the anonymous inner class num, and then decrement it*/
764      public int postdecrementAnonymousInnerClassNum() { return _anonymousInnerClassNum--; }  
765      
766      /** Adds a (perhaps mutable) variable or field to a SymbolData. */
767      public boolean addVar(VariableData var) {
768        // Next line commented out because local variables do not have a initial value
769    //    if (! var.isFinal()) var.setHasValue();
770        return super.addVar(var); 
771      }
772      
773      /** Adds fields or variables to a SymboLData.*/
774      public boolean addVars(VariableData[] vars) {
775       boolean success = true;
776        for (int i = 0; i<vars.length; i++) {
777          LinkedList<SymbolData> seen = new LinkedList<SymbolData>();
778          if (! _repeatedName(vars[i], seen)) {
779            // Next line commented out because local variables do not have a initial value
780    //        if (! vars[i].isFinal()) vars[i].setHasValue();
781            _vars.addLast(vars[i]);
782          }
783          else success = false;
784        }
785        return success;
786     }
787    
788      /** Add the array of variable datas to the list of variables defined in this scope, unless a name has already been 
789        * used.  Return true if all variables were added successfully, false otherwise.  Set each of the variable datas in 
790        * the array to be final before adding them. 
791        * Since this method is used to add fields at the Functional level,
792        * and at this level, we do not want the user to be able to shadow fields defined
793        * in the superclass hierarchy, instead of using the normal repeated Name method,
794        * check the repeated name throughout the hierarchy.
795        * 
796        * @param vars  The VariableData[] that we want to add.
797        * @return  true if all VariableDatas were added successfully, false otherwise.
798        */
799      public boolean addFinalVars(VariableData[] vars) {
800        boolean success = true;
801        for (int i = 0; i<vars.length; i++) {
802          LinkedList<SymbolData> seen = new LinkedList<SymbolData>();
803          if (!_repeatedNameInHierarchy(vars[i], seen)) {
804            if (! vars[i].isFinal()) vars[i].setFinal();
805            _vars.addLast(vars[i]);
806          }
807          else {
808            success = false;
809          }
810        }
811        return success;
812      }
813      
814      /** Checks to see if a variable with the same name as vr has already been defined in the scope of this data.  If so, 
815        * return true.  Otherwise, return false.
816        * @param vr  The VariableData whose name we are searching for.
817        * @return  true if that name has already been used in this scope, false otherwise.
818        */
819      private boolean _repeatedName(VariableData vr, LinkedList<SymbolData> seen) {
820        seen.addLast(this);
821        Iterator<VariableData> iter = _vars.iterator();
822        while (iter.hasNext()) {
823          if (vr.getName().equals(iter.next().getName())) return true;
824        }
825        return false;
826      }
827      
828      /** Checks to see if a variable with the same name as vr has already been defined in the scope of this data or its 
829        * super class/interfaces.  If so, return true.  Otherwise, return false.
830        * @param vr  The VariableData whose name we are searching for.
831        * @return  true if that name has already been used in this scope, false otherwise.
832        */
833      private boolean _repeatedNameInHierarchy (VariableData vr, LinkedList<SymbolData> seen) {
834        seen.addLast(this);
835        Iterator<VariableData> iter = _vars.iterator();
836        while (iter.hasNext()) {
837          if (vr.getName().equals(iter.next().getName())) return true;
838        }
839        
840        // Does this shadow something in the super class?
841        if (_superClass != null && _superClass._repeatedNameInHierarchy(vr, seen)) return true;
842        
843        //Does this shadow something in the super interfaces?  TODO: postpone this test until all interfaces have been identified.
844        for (SymbolData sd: _interfaces) {
845          if (sd != null && sd._repeatedNameInHierarchy(vr, seen)) return true;
846        }
847        return false;
848      }
849      
850      /** @return the list of methods defined in this symbol data*/
851      public LinkedList<MethodData> getMethods() { return _methods; }
852      
853      /** Returns true if there is a method with the given name in this SymbolData.
854        * @param name  The name of the method to return
855        * @return  true if a MethodData is found or false otherwise.
856        */
857      public boolean hasMethod(String name) {
858        for (int i = 0; i < _methods.size(); i++) {
859          MethodData currMd = _methods.get(i);
860          if (currMd.getName().equals(name)) return true;
861        }
862        return false;
863      }
864      
865      /** Returns the method with the given name and param types.
866        * @param name  The name of the method to return
867        * @param paramTypes  Array of the TypeDatas correpsonding to the parameters to the method.
868        * @return  The matched MethodData or null if it is not found
869        */
870      public MethodData getMethod(String name, TypeData[] paramTypes) {
871        for (MethodData currMd: _methods) {
872          if (currMd.getName().equals(name)) {
873            if (paramTypes.length == currMd.getParams().length) {
874              boolean match = true;
875              for (int j = 0; j < paramTypes.length; j++) {  // TODO; clean up this coding!
876                if (paramTypes[j] == null || paramTypes[j].getSymbolData() == null || currMd.getParams()[j].getType() == null)
877                  continue;  // prevents a null pointer exception
878                if (! paramTypes[j].getSymbolData().equals(currMd.getParams()[j].getType().getSymbolData())) { 
879                  match = false; 
880                  break; 
881                }
882              }
883              if (match) return currMd;
884            }
885          }
886        }
887        return null;
888      }
889      
890      /**Sets the list of methods to the specified one*/
891      public void setMethods(LinkedList<MethodData> methods) {
892        _methods = methods;
893      }
894      
895      /**Calls repeatedSignature with fromClassFile set to false by default.*/
896      public static MethodData repeatedSignature(LinkedList<MethodData> listOfMethods, MethodData method) {
897        return repeatedSignature(listOfMethods, method, false);
898      }
899      
900      /** Checks if two methods in this SymbolData have the same name and parameters.
901        * @param listOfMethods  The methods in this SymbolData
902        * @param method  The MethodData for the method to be added
903        * @param fromClassFile  Whether or not a class file is adding this method.
904        *                       Important because bridge methods, which differ only in return type,
905        *                       can be added from a class file and are legal but cannot exist in source code.
906        * @return the MethodData that was already in listOfMethods that method duplicates if there is one or null otherwise.
907        */
908      public static MethodData repeatedSignature(LinkedList<MethodData> listOfMethods, MethodData method, 
909                                                 boolean fromClassFile) {
910        Iterator<MethodData> iter = listOfMethods.iterator();
911        VariableData[] methodParams = method.getParams();
912        while (iter.hasNext()) {
913          boolean match = true;
914          MethodData currMd = iter.next();
915          // Check if names are the same and if this is called from a class file check if return types are the same.
916          if (currMd.getName().equals(method.getName()) && 
917              (! fromClassFile || currMd.getReturnType() == method.getReturnType())) {
918            VariableData[] currMdParams = currMd.getParams();
919            if (currMdParams.length == methodParams.length) {
920              for (int i = 0; i < currMdParams.length; i++) {
921                if (currMdParams[i].getType() != methodParams[i].getType()) {
922                  match = false;
923                  break;
924                }
925              }
926              if (match) return currMd;
927            }
928          }
929        }
930        return null;
931      }
932      
933      
934    
935      /** @return true if this is a primitive boolean or a Boolean with autoboxing enabled*/
936      boolean isBooleanType(JavaVersion version) {
937        return this == BOOLEAN_TYPE || 
938          (getName().equals("java.lang.Boolean") && LanguageLevelConverter.versionSupportsAutoboxing(version));
939      }
940      
941    
942      /** @return true if this is a primitive char or a Character with autoboxing enabled*/
943      boolean isCharType(JavaVersion version) {
944        return this == CHAR_TYPE || (getName().equals("java.lang.Character") && 
945                                     LanguageLevelConverter.versionSupportsAutoboxing(version));
946      }
947        
948      /** @return true if this is a primitive byte or a Byte with autoboxing enabled*/
949      boolean isByteType(JavaVersion version) {
950        return this == BYTE_TYPE || (getName().equals("java.lang.Byte") && 
951                                     LanguageLevelConverter.versionSupportsAutoboxing(version));
952      }
953      
954      /** @return true if this is a primitive short or a Short with autoboxing enabled*/
955      boolean isShortType(JavaVersion version) {
956        return this == SHORT_TYPE || (getName().equals("java.lang.Short") && 
957                                      LanguageLevelConverter.versionSupportsAutoboxing(version));
958      }
959      
960      /**@return true if this is a primitive int or an Integer with autoboxing enabled*/
961      boolean isIntType(JavaVersion version) {
962        return this==INT_TYPE || (getName().equals("java.lang.Integer") && 
963                                  LanguageLevelConverter.versionSupportsAutoboxing(version));
964      }
965      
966      /**@return true if this is a primitive long or a Long with autoboxing enabled*/
967      boolean isLongType(JavaVersion version) {
968        return this == LONG_TYPE || (this.getName().equals("java.lang.Long") && 
969                                     LanguageLevelConverter.versionSupportsAutoboxing(version));
970      }
971      
972      /**@return true if this is a primitive char or a Character with autoboxing enabled*/
973      boolean isFloatType(JavaVersion version) {
974        return this == FLOAT_TYPE || (getName().equals("java.lang.Float") && 
975                                      LanguageLevelConverter.versionSupportsAutoboxing(version));
976      }
977      
978      /**@return true if this is a primitive double or a Double with autoboxing enabled*/
979      boolean isDoubleType(JavaVersion version) {
980        return this == DOUBLE_TYPE || 
981          (getName().equals("java.lang.Double") && LanguageLevelConverter.versionSupportsAutoboxing(version));
982      }
983      
984      /** Compares the ModifiersAndVisibility of the 2 method data to determine if overwriting can override the access 
985        * priviledges of overwritten.  
986        */
987      private static boolean _isCompatible(MethodData overwritten, MethodData overwriting) {
988        if (overwritten.hasModifier("public")) { // A public method can only be overwritten by a public method.
989          return overwriting.hasModifier("public");
990        }
991        if (overwritten.hasModifier("protected")) { // A protected method can only be overwritten by protected/public method
992          return overwriting.hasModifier("protected") || overwriting.hasModifier("public");
993        } 
994        if (! overwritten.hasModifier("private")) { // default methods can be overridden by a non-private method
995          return ! overwriting.hasModifier("private");
996        }
997        return true;
998      }
999      
1000      /**Call checkDifferentReturnTypes with addError set to true by default*/
1001      protected static boolean checkDifferentReturnTypes(MethodData md, SymbolData sd, JavaVersion version) {
1002          return checkDifferentReturnTypes(md, sd, true, version);
1003        }
1004      
1005      /** Called to make sure that no method has the same name and parameters as a method it inherits while having
1006        * different return types.
1007        * @param md  The MethodData we're currently trying to add
1008        * @param sd  The SymbolData of the class whose enclosingDatas we're examining for 
1009        *            different return types.
1010        * @param addError  true if errors should be added to the type checker
1011        * @return  Whether there exists a conflict
1012        */
1013      protected static boolean checkDifferentReturnTypes(MethodData md, SymbolData sd, boolean addError, 
1014                                                         JavaVersion version) {
1015        // We only want to check the super class and interfaces, not outer classes.
1016        ArrayList<SymbolData> interfaces = sd.getInterfaces();    
1017        LinkedList<SymbolData> enclosingData = new LinkedList<SymbolData>();
1018        enclosingData.addAll(interfaces);
1019        SymbolData superClass = sd.getSuperClass();
1020        if (superClass != null) {
1021          enclosingData.add(superClass);
1022        }
1023        Iterator<SymbolData> iter = enclosingData.iterator();
1024        while (iter.hasNext()) {
1025          SymbolData currSd = iter.next();
1026          MethodData matchingMd = repeatedSignature(currSd.getMethods(), md);
1027          if (matchingMd != null) {
1028            if (matchingMd.hasModifier("private")) return false;
1029            boolean subclass = md.getReturnType().isSubClassOf(matchingMd.getReturnType());
1030            if (matchingMd.getReturnType() != md.getReturnType() && ! subclass && 
1031                LanguageLevelConverter.versionIs15(version)) {
1032              StringBuffer methodSignature = new StringBuffer(md.getName() + "(");
1033              VariableData[] params = md.getParams();
1034              for (int i = 0; i < params.length; i++) {
1035                if (i > 0) methodSignature.append(", ");
1036                methodSignature.append(params[i].getType().getName());
1037              }
1038              methodSignature.append(")");
1039              String methodSigString = methodSignature.toString();
1040              // This entire method is only called from the type checker, so add an error to its error list.
1041              if (addError) { 
1042                TypeChecker.errors.addLast(new Pair<String, JExpressionIF>(methodSigString + " in " + sd.getName() + 
1043                                                                           " cannot override " + methodSigString + " in " +
1044                                                                           currSd.getName() + 
1045                                                                           "; attempting to use different return types",
1046                                                                           md.getJExpression())); }
1047              return true;
1048            }
1049            
1050            if (! _isCompatible(matchingMd, md)) {  // check compatibility of visiblity modifiers
1051              String access = "package";
1052              if (matchingMd.hasModifier("private")) access = "private";
1053              if (matchingMd.hasModifier("public")) access = "public";
1054              if (matchingMd.hasModifier("protected")) access = "protected";
1055              if (addError) {
1056                TypeChecker.errors.
1057                  addLast(new Pair<String, JExpressionIF>(md.getName() + " in " + md.getSymbolData().getName() 
1058                                                            + " cannot override " + matchingMd.getName() + " in " 
1059                                                            + matchingMd.getSymbolData().getName() + 
1060                                                          ".  You are attempting to assign weaker access priviledges. In " 
1061                                                            + matchingMd.getSymbolData().getName() + ", "
1062                                                            + matchingMd.getName() + " was " 
1063                                                            + access, md.getJExpression())); } 
1064              return true;
1065            }
1066          }
1067          else if (checkDifferentReturnTypes(md, currSd, version)) return true;
1068        }
1069        return false;
1070      }
1071      
1072      /** Checks to see if methodName is used in this SymbolData's scope.  If so, finds a new name for the method by 
1073        * appending a counter to its name until an unused method name results.  Returns the new name.
1074        * @param methodName  The initial String name of the variable we are creating.
1075        * @return  The new variable name which does not shadow anything in vars.
1076        */
1077      public String createUniqueMethodName(String methodName) {
1078        LinkedList<SymbolData> toCheck = new LinkedList<SymbolData>();
1079        toCheck.add(this);
1080        Set<String> names = new HashSet<String>();
1081        while(toCheck.size() > 0) {
1082          SymbolData sd = toCheck.removeFirst();
1083          LinkedList<MethodData> methods = sd.getMethods();
1084          for(MethodData md : methods) { names.add(md.getName()); }
1085          if (sd.getSuperClass() != null) { toCheck.add(sd.getSuperClass()); }
1086          toCheck.addAll(sd.getInterfaces());
1087          if (sd.getOuterData() != null) { toCheck.add(sd.getOuterData().getSymbolData()); }
1088        }
1089            
1090        String newName = methodName;
1091        int counter = 0;  // Note: loop tests for counter overflow, but memory would be exhausted much earlier
1092        while (names.contains(newName) && counter != -1) {
1093          newName = methodName + counter; 
1094          counter++;
1095        }
1096        
1097        if (counter == -1) throw 
1098          new RuntimeException("Internal Program Error: Unable to rename method " + methodName 
1099                                 + ".  All possible names were taken.  Please report this bug.");
1100    
1101        return newName; 
1102      }
1103      
1104      
1105      /** Called to generate an error message when two methods are created with the same signature. */
1106      private String _createErrorMessage(MethodData md) {
1107        StringBuffer message = 
1108          new StringBuffer("In the class \"" + md.getSymbolData().getName() + 
1109                           "\", you cannot have two methods with the same name: \"" + md.getName() + "\"");
1110        VariableData[] params = md.getParams();
1111        if (params.length > 0) {
1112          message.append(" and parameter type");
1113          if (params.length > 1) {
1114            message.append("s");
1115          }
1116          message.append(":");
1117        }
1118        for (int i = 0; i < params.length; i++) {
1119          VariableData p = params[i];
1120          if (p != null && p.getType() != null) {
1121            if (i > 0) {
1122              message.append(",");
1123            }
1124            message.append(" " + p.getType().getName());
1125          }
1126        }
1127        return message.toString();
1128      }
1129      
1130      /** When adding a method, we must check that the method's signature (name and parameters)
1131        * does not match that of any other method in the same class.  We also must check that
1132        * a method does not have the same signature but a different return type from a method 
1133        * in its superclass or one of its interfaces.
1134    `    */
1135      public void addMethod(MethodData method) {
1136        // Detect repeated methods
1137        if (repeatedSignature(_methods, method) != null) {
1138          LanguageLevelVisitor.errors.addLast(new Pair<String, JExpressionIF>(_createErrorMessage(method), 
1139                                                                              method.getJExpression()));
1140        }
1141        else {
1142          _methods.addLast(method);
1143    //      System.err.println("*** Adding method " + method.getName() + " to " + this);
1144        }
1145      }
1146      
1147      /** This version of addMethod is called whenever the method corresponds to one that is auto-generated
1148        * (toString, equals, hashCode, etc.) and is necessary because we need to check if the user defined
1149        * a method with the same signature and, if so, highlight the user method instead of trying to highlight
1150        * the auto-generated method (which doesn't appear in the raw version of the source anyway).
1151        */
1152      public void addMethod(MethodData method, boolean isAugmentedCode) {
1153        // Detect if a method was user-defined that matches the signature of an auto-generated method.
1154        MethodData md = repeatedSignature(_methods, method);
1155        if (md != null) {
1156          LanguageLevelVisitor.errors.
1157            addLast(new Pair<String, JExpressionIF>("This method's signature conflicts with an automatically generated "
1158                                                      + "method's signature", 
1159                                                    md.getJExpression()));
1160        }
1161        else {
1162            _methods.addLast(method);
1163        }
1164      }
1165      
1166      /**
1167       * Important to know if this is called from a class file since JSR14 allows methods to have the same
1168       * name and parameters with different return types for bridge methods.
1169       */
1170      public void addMethod(MethodData method, boolean isAugmentedCode, boolean fromClassFile) {
1171      // This checking cannot be performed until symbolTable is complete  
1172    //    // Detect if a method was user-defined that matches the signature of an auto-generated method.
1173    //    MethodData md = repeatedSignature(_methods, method, fromClassFile);
1174    //    if (md != null) {
1175    //      LanguageLevelVisitor.errors.
1176    //        addLast(new Pair<String, JExpressionIF>(_createErrorMessage(method), md.getJExpression()));
1177    //    }
1178    //    else {
1179          _methods.addLast(method);
1180    //    }
1181      }
1182    
1183      /**@return the superClass of this symbol data*/
1184      public SymbolData getSuperClass() {
1185        return _superClass;
1186      }
1187      
1188      public void clearSuperClass() { _superClass = null; }
1189      
1190      /** Set the super class to the specified value. */
1191      public void setSuperClass(SymbolData superClass) {
1192        assert superClass != null;
1193        _superClass = superClass;
1194        addEnclosingData(superClass);
1195      }
1196      
1197      /**@return the interfaces of this symbol data*/
1198      public ArrayList<SymbolData> getInterfaces() { return _interfaces; }
1199      
1200      /** Add an interface to the list of interfaces.  TODO: find out where null is being added as an interface! */
1201      public void addInterface(SymbolData interphace) {
1202        if (interphace != null) {
1203          _interfaces.add(interphace);
1204          addEnclosingData(interphace);
1205        }
1206      }
1207      
1208      /**Set the interfaces to be the specified list*/
1209      public void setInterfaces(ArrayList<SymbolData> interfaces) {
1210        assert interfaces != null;
1211        _interfaces = interfaces;
1212        for (SymbolData sd: interfaces) { if (sd != null) addEnclosingData(sd); }
1213      }
1214      
1215      /**Add one to the number of constructors for this symbol data*/
1216      public void incrementConstructorCount() {
1217        _constructorNumber ++;
1218      }
1219      
1220      /**Subtract one from the number of constructors for this symbol data*/
1221      public void decrementConstructorCount() {
1222        _constructorNumber --;
1223      }
1224      
1225      /**@return the number of constructors*/
1226      public int getConstructorCount() {
1227        return _constructorNumber;
1228      }
1229      
1230      /**@return true if this is a continuation*/
1231      public boolean isContinuation() {
1232        return _isContinuation;
1233      }
1234      
1235      /**Set the isContinuation flag to the specified value*/
1236      public void setIsContinuation(boolean isContinuation) {
1237        _isContinuation = isContinuation;
1238      }
1239      
1240      /**@return true if this is a continuation*/
1241      public boolean hasAutoGeneratedJunitImport() {
1242        return _hasAutoGeneratedJunitImport;
1243      }
1244      
1245      /**Set the isContinuation flag to the specified value*/
1246      public void setHasAutoGeneratedJunitImport(boolean hasAutoGeneratedJunitImport) {
1247        _hasAutoGeneratedJunitImport = hasAutoGeneratedJunitImport;
1248      }
1249    
1250      /**@return true if this Symbol Data is a primitive type that is a number type*/
1251      public boolean isNumberTypeWithoutAutoboxing() {
1252        return (this == SymbolData.INT_TYPE ||
1253            this == SymbolData.DOUBLE_TYPE ||
1254            this == SymbolData.LONG_TYPE ||
1255            this == SymbolData.CHAR_TYPE ||
1256            this == SymbolData.FLOAT_TYPE ||
1257            this == SymbolData.SHORT_TYPE ||
1258            this == SymbolData.BYTE_TYPE);
1259      }
1260      
1261      /**@return true if this Symbol Data is a primitive type that is a number type or is
1262       * a Object number type with autoboxing enabled.*/
1263      public boolean isNumberType(JavaVersion version) {
1264        if (!LanguageLevelConverter.versionSupportsAutoboxing(version)) {
1265          return isNumberTypeWithoutAutoboxing();
1266        }
1267        if (this.isDoubleType(version) ||
1268            this.isFloatType(version) ||
1269            this.isLongType(version) ||
1270            this.isIntType(version) ||        
1271            this.isCharType(version) ||
1272            this.isShortType(version) ||
1273            this.isByteType(version)) {
1274          return true;
1275        }
1276        return false;
1277      }
1278    
1279    
1280      /**@return true if this is a non float or boolean type, with autoboxing if it is allowed, or without autoboxing*/
1281      public boolean isNonFloatOrBooleanType(JavaVersion version) {
1282        if (!LanguageLevelConverter.versionSupportsAutoboxing(version)) {
1283          return isNonFloatOrBooleanTypeWithoutAutoboxing();
1284        }
1285    
1286        return (this.isIntType(version) ||
1287            this.isLongType(version) ||
1288            this.isCharType(version) ||
1289            this.isShortType(version) ||
1290            this.isByteType(version) ||
1291            this.isBooleanType(version));
1292      }
1293    
1294      /** @return true if this is a non float or boolean type, without autoboxing*/
1295      public boolean isNonFloatOrBooleanTypeWithoutAutoboxing() {
1296        return (this==SymbolData.INT_TYPE ||
1297            this==SymbolData.LONG_TYPE ||
1298            this==SymbolData.CHAR_TYPE ||
1299            this==SymbolData.SHORT_TYPE ||
1300            this==SymbolData.BYTE_TYPE ||
1301            this==SymbolData.BOOLEAN_TYPE);
1302        
1303      }
1304      
1305      
1306      /**
1307       * Returns true if the provided Object is equal to this symbol data.
1308       * SymbolDatas are equal if their fields are the same.
1309       * */
1310      public boolean equals(Object obj) {
1311        if (obj == null) return false;
1312        if ((obj.getClass() != this.getClass())) { //|| (obj.hashCode() != this.hashCode())) {
1313          return false;
1314        }
1315        SymbolData sd = (SymbolData) obj;    
1316    
1317        /*Return true if the fields are all .equals.*/
1318          
1319        return this.isContinuation() == sd.isContinuation() && 
1320          this.getMav().equals(sd.getMav()) &&
1321          LanguageLevelVisitor.arrayEquals(this.getTypeParameters(), sd.getTypeParameters()) &&
1322          this.getMethods().equals(sd.getMethods()) &&
1323          this.getSuperClass() == sd.getSuperClass() && //could be null
1324          this.getInterfaces().equals(sd.getInterfaces()) &&
1325          this.getOuterData() == sd.getOuterData() && //could be null
1326          this.getInnerClasses().equals(sd.getInnerClasses()) &&
1327          this.getName().equals(sd.getName()) &&
1328          this.getInnerInterfaces().equals(sd.getInnerInterfaces()) &&
1329          this.getPackage().equals(sd.getPackage()) &&
1330          this.isInterface() == sd.isInterface();
1331     
1332    
1333      }
1334      
1335      /**
1336       * Since SymbolDatas have unique names, in any given symboltable, hash on the name
1337       */
1338      public int hashCode() {
1339        return getName().hashCode();
1340      }
1341      
1342      /** Check to see if this class is one of the 5 known classes that implement Runnable.  Checking each class recursively
1343        * to see if it extends Runnable is too time consuming, so we are hoping this short cut will work.
1344        * Clearly, this has some disadvantages.
1345        */
1346      public boolean implementsRunnable() {
1347       return this.getName().equals("java.lang.Thread") || this.getName().equals("java.util.TimerTask") 
1348         || this.getName().equals("javax.swing.text.AsyncBoxView$ChildState") 
1349         || this.getName().equals("java.awt.image.renderable.RenderableImageProducer")
1350         || this.getName().equals("java.util.concurrent.FutureTask");// || this.getName().equals("java.lang.Runnable");
1351      }
1352      
1353      /**Check to see if the interface i appears anywhere in the hierarchy for this class/interface*/
1354      public boolean hasInterface(SymbolData i) {
1355        if (i == null) return false;
1356    
1357        if (getInterfaces().contains(i)) { return true; }
1358        
1359        if ((this.getSuperClass() != null) && this.getSuperClass().hasInterface(i)) { return true; }
1360        
1361        for (int j = 0; j < getInterfaces().size(); j++) {
1362          if (getInterfaces().get(j).hasInterface(i)) return true;
1363        }
1364        return false;
1365      }
1366      
1367      /**
1368       * Get all of your vars and all vars that you inherit.
1369       */
1370      public LinkedList<VariableData> getAllSuperVars() {
1371        LinkedList<VariableData> myVars = new LinkedList<VariableData>();
1372        if (this.getSuperClass() != null) {
1373          myVars.addAll(this.getSuperClass().getVars());
1374          myVars.addAll(this.getSuperClass().getAllSuperVars());
1375        }
1376        for (int i = 0; i<getInterfaces().size(); i++) {
1377          myVars.addAll(this.getInterfaces().get(i).getVars());
1378          myVars.addAll(this.getInterfaces().get(i).getAllSuperVars());
1379        }
1380        return myVars;
1381      }
1382      
1383       /** Test the methods defined in the above class */
1384      public static class SymbolDataTest extends TestCase {
1385        
1386        private SymbolData _sd;
1387        
1388        private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"public"});
1389        private ModifiersAndVisibility _protectedMav = 
1390          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"protected"});
1391        private ModifiersAndVisibility _privateMav = 
1392          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"private"});
1393        private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[0]);
1394        private ModifiersAndVisibility _abstractMav = 
1395          new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"abstract"});
1396        private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"final"});
1397        private ModifiersAndVisibility _publicFinalMav = 
1398          new ModifiersAndVisibility(SourceInfo.NONE, new String[]{"public", "final"});
1399        
1400        public SymbolDataTest() {
1401          this("");
1402        }
1403        public SymbolDataTest(String name) {
1404          super(name);
1405        }
1406        
1407        public void setUp() {
1408          _sd = new SymbolData("i.like.monkey");
1409          LanguageLevelVisitor.errors = new LinkedList<Pair<String, JExpressionIF>>();
1410        }
1411        
1412        public void testRepeatedSignatures() {
1413          MethodData md = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
1414                                         new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1415            new VariableData(SymbolData.BOOLEAN_TYPE)}, 
1416                                         new String[0],
1417                                         _sd,
1418                                         null);
1419          md.getParams()[0].setEnclosingData(md);
1420          md.getParams()[1].setEnclosingData(md);
1421          LinkedList<MethodData> mds = new LinkedList<MethodData>();
1422          mds.addFirst(md);
1423          // Test same name, return type, and params from a source file.
1424          MethodData md2 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
1425                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1426            new VariableData(SymbolData.BOOLEAN_TYPE) }, 
1427                                          new String[0],
1428                                          _sd,
1429                                          null);
1430          md2.getParams()[0].setEnclosingData(md2);
1431          md2.getParams()[1].setEnclosingData(md2);
1432                                    
1433          assertTrue("repeatedSignatures should return md exactly.", md == _sd.repeatedSignature(mds, md2));
1434          // Test same name, return type, and params from a class file.
1435          MethodData md3 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
1436                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1437            new VariableData(SymbolData.BOOLEAN_TYPE) }, 
1438                                          new String[0],
1439                                          _sd,
1440                                          null);
1441          md3.getParams()[0].setEnclosingData(md3);
1442          md3.getParams()[1].setEnclosingData(md3);
1443                                    
1444          assertTrue("repeatedSignatures should return md exactly.", md == _sd.repeatedSignature(mds, md3, true));
1445          // Test same name, different return type, and params from a class file.
1446          MethodData md4 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE, 
1447                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1448            new VariableData(SymbolData.BOOLEAN_TYPE) }, 
1449                                          new String[0],
1450                                          _sd,
1451                                          null);      
1452          md4.getParams()[0].setEnclosingData(md4);
1453          md4.getParams()[1].setEnclosingData(md4);
1454    
1455                                          
1456          assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md4, true));
1457          // Test same name, return type, and different params from a source file.
1458          MethodData md5 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE, 
1459                                          new VariableData[] { new VariableData(SymbolData.BOOLEAN_TYPE) }, 
1460                                          new String[0],
1461                                          _sd,
1462                                          null);
1463          md5.getParams()[0].setEnclosingData(md5);
1464                                        
1465          assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md5));
1466          // Test same name, return type, and different order params from a source file.
1467          MethodData md6= new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE, 
1468                                          new VariableData[] { new VariableData(SymbolData.BOOLEAN_TYPE),
1469            new VariableData(SymbolData.CHAR_TYPE) }, 
1470                                          new String[0],
1471                                          _sd,
1472                                          null);
1473          md6.getParams()[0].setEnclosingData(md6);
1474          md6.getParams()[1].setEnclosingData(md6);
1475                                          
1476          assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md6));
1477        }
1478        
1479        public void testCheckDifferentReturnTypes() {
1480          
1481          TypeChecker.errors = new LinkedList<Pair<String, JExpressionIF>>();
1482          
1483          // Create a super class and give it a method.
1484          SymbolData superSd = new SymbolData("superClass");
1485          MethodData md = new MethodData("methodName",
1486                                         _publicMav,
1487                                         new TypeParameter[0],
1488                                         SymbolData.INT_TYPE,
1489                                         new VariableData[0],
1490                                         new String[0],
1491                                         superSd,
1492                                         null);
1493          superSd.addMethod(md);
1494          _sd.setSuperClass(superSd);
1495          // Test with an exact copy of the method.
1496          MethodData md2 = new MethodData("methodName",
1497                                          _publicMav,
1498                                          new TypeParameter[0],
1499                                          SymbolData.INT_TYPE,
1500                                          new VariableData[0],
1501                                          new String[0],
1502                                          _sd,
1503                                          null);
1504          assertFalse("There should not be a conflict.", checkDifferentReturnTypes(md2, _sd, JavaVersion.JAVA_5));
1505          assertEquals("There should not be an error.", 0, TypeChecker.errors.size());
1506          // Test with an exact copy of the method except for differing return types.
1507          MethodData md3 = new MethodData("methodName",
1508                                          _publicMav,
1509                                          new TypeParameter[0],
1510                                          SymbolData.CHAR_TYPE,
1511                                          new VariableData[0],
1512                                          new String[0],
1513                                          _sd,
1514                                          null);
1515          assertTrue("There should be a conflict.", checkDifferentReturnTypes(md3, _sd, JavaVersion.JAVA_5));
1516          assertEquals("There should be one error.", 1, TypeChecker.errors.size());
1517          assertEquals("The error message should be correct.", 
1518                       "methodName() in i.like.monkey cannot override methodName() in superClass;" + 
1519                       " attempting to use different return types",
1520                       TypeChecker.errors.get(0).getFirst());
1521          // Create a super super class and give it a method.
1522          SymbolData superSuperSd = new SymbolData("superSuperClass");
1523          MethodData md4 = new MethodData("superSuperMethodName",
1524                                          _publicMav,
1525                                          new TypeParameter[0],
1526                                          SymbolData.INT_TYPE,
1527                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1528                                          new String[0],
1529                                          superSuperSd,
1530                                          null);
1531          md4.getParams()[0].setEnclosingData(md4);
1532          superSuperSd.addMethod(md4);
1533          superSd.setSuperClass(superSuperSd);
1534          // Test with an exact copy except for differing parameters.
1535          MethodData md5 = new MethodData("superSuperMethodName",
1536                                          _publicMav,
1537                                          new TypeParameter[0],
1538                                          SymbolData.INT_TYPE,
1539                                          new VariableData[0],
1540                                          new String[0],
1541                                          null,
1542                                          null);
1543          assertFalse("There should not be a conflict.", checkDifferentReturnTypes(md5, _sd, JavaVersion.JAVA_5));
1544          assertEquals("There should still be one error.", 1, TypeChecker.errors.size());
1545          // Test with an exact copy except for diffeing return types.
1546          MethodData md6 = new MethodData("superSuperMethodName",
1547                                          _publicMav,
1548                                          new TypeParameter[0],
1549                                          SymbolData.BYTE_TYPE,
1550                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1551                                          new String[0],
1552                                          null,
1553                                          null);
1554          md6.getParams()[0].setEnclosingData(md6);
1555          assertTrue("There should be a conflict.", checkDifferentReturnTypes(md6, _sd, JavaVersion.JAVA_5));
1556          assertEquals("There should be two errors.", 2, TypeChecker.errors.size());
1557          
1558          //Test a method that restricts the mav of the super class's method
1559          MethodData md7 = new MethodData("superSuperMethodName",
1560                                          _privateMav,
1561                                          new TypeParameter[0],
1562                                          SymbolData.INT_TYPE,
1563                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1564                                          new String[0],
1565                                          new SymbolData("myData"),
1566                                          null);
1567    
1568          md7.getParams()[0].setEnclosingData(md7);
1569          assertTrue("There should be a conflict", checkDifferentReturnTypes(md7, _sd, JavaVersion.JAVA_5));
1570          assertEquals("There should be three errors", 3, TypeChecker.errors.size());
1571          assertEquals("The error message should be correct", 
1572                       "superSuperMethodName in myData cannot override superSuperMethodName in " + superSuperSd.getName() + 
1573                       ".  You are attempting to assign weaker access priviledges. In " + superSuperSd.getName() + 
1574                       ", superSuperMethodName was public", TypeChecker.errors.get(2).getFirst());
1575                                          
1576          
1577          //Test a method that narrows the return type of the super class's method
1578          SymbolData stringSd = new SymbolData("java.lang.String");
1579          stringSd.setIsContinuation(false);
1580          stringSd.setSuperClass(SymbolData.INT_TYPE);
1581          
1582          MethodData md8 = new MethodData("superSuperMethodName",
1583                                          _publicMav,
1584                                          new TypeParameter[0],
1585                                          stringSd,
1586                                          new VariableData[] {new VariableData(SymbolData.CHAR_TYPE)},
1587                                          new String[0],
1588                                          new SymbolData("myData"),
1589                                          null);
1590                                          
1591          assertFalse("There should be no conflict", checkDifferentReturnTypes(md8, _sd, JavaVersion.JAVA_5));
1592          assertEquals("There should still be 3 errors", 3, TypeChecker.errors.size());
1593          /* Java 1.4 is not supported. */
1594    //      assertTrue("There should be a conflict in 1.4", checkDifferentReturnTypes(md8, _sd, JavaVersion.JAVA_1_4));
1595    //      assertEquals("There should now be 4 errors", 4, TypeChecker.errors.size());
1596    //      assertEquals("The error message should be correct", TypeChecker.errors.getLast().getFirst(), 
1597    //                   "superSuperMethodName(char) in superClass cannot override superSuperMethodName(char) in " + 
1598    //                   superSuperSd.getName() + "; attempting to use different return types");
1599        }
1600        
1601        public void test_createErrorMessage() {
1602          // Test with a method with no parameters.
1603          MethodData md = new MethodData("methodName",
1604                                         _publicMav,
1605                                         new TypeParameter[0],
1606                                         SymbolData.INT_TYPE,
1607                                         new VariableData[0],
1608                                         new String[0],
1609                                         _sd,
1610                                         null);
1611          assertEquals("The error message should be correct.", 
1612                       "In the class \"i.like.monkey\", you cannot have two methods with the same name: \"methodName\"", 
1613                       _sd._createErrorMessage(md));
1614          // Test with a method with one parameter.
1615          MethodData md2 = new MethodData("superSuperMethodName",
1616                                          _publicMav,
1617                                          new TypeParameter[0],
1618                                          SymbolData.INT_TYPE,
1619                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
1620                                          new String[0],
1621                                          _sd,
1622                                          null);
1623          assertEquals("The error message should be correct.", 
1624                       "In the class \"i.like.monkey\", you cannot have two methods with the same name: "
1625                         + "\"superSuperMethodName\" and parameter type: char", 
1626                       _sd._createErrorMessage(md2));
1627          md2.getParams()[0].setEnclosingData(md2);
1628          // Test with a method with two parameters.
1629          MethodData md3 = new MethodData("superSuperMethodName",
1630                                          _publicMav,
1631                                          new TypeParameter[0],
1632                                          SymbolData.INT_TYPE,
1633                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1634            new VariableData(SymbolData.CHAR_TYPE) },
1635                                          new String[0],
1636                                          _sd,
1637                                          null);
1638          md3.getParams()[0].setEnclosingData(md3);
1639          md3.getParams()[1].setEnclosingData(md3);
1640                                          
1641          assertEquals("The error message should be correct.", 
1642                       "In the class \"i.like.monkey\", you cannot have two methods with the same name: "
1643                         + "\"superSuperMethodName\" and parameter types: char, char", 
1644                       _sd._createErrorMessage(md3));
1645          
1646        }
1647        
1648        public void testAddMethod() {
1649          MethodData md = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
1650                                         new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1651            new VariableData(SymbolData.BOOLEAN_TYPE)}, 
1652                                         new String[0],
1653                                         _sd,
1654                                         null);
1655                                         
1656          md.getParams()[0].setEnclosingData(md);
1657          md.getParams()[1].setEnclosingData(md);
1658                                         
1659          _sd.addMethod(md);
1660          assertEquals("There should be no errors.", 0, LanguageLevelVisitor.errors.size());
1661          // Test same name, return type, and params from a source file.
1662          MethodData md2 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
1663                                          new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
1664            new VariableData(SymbolData.BOOLEAN_TYPE) }, 
1665                                          new String[0],
1666                                          _sd,
1667                                          null);
1668          md2.getParams()[0].setEnclosingData(md2);
1669          md2.getParams()[1].setEnclosingData(md2);
1670                                          
1671          _sd.addMethod(md2);
1672          assertEquals("There should be one error.", 1, LanguageLevelVisitor.errors.size());
1673          assertEquals("The error message should be correct.", "In the class \"" + _sd.getName() + 
1674                       "\", you cannot have two methods with the same name: \"" + md.getName() 
1675                         + "\" and parameter types: char, boolean",
1676                       LanguageLevelVisitor.errors.get(0).getFirst());
1677          MethodData md4 = new MethodData("methodName",
1678                                         _publicMav,
1679                                         new TypeParameter[0],
1680                                         SymbolData.INT_TYPE,
1681                                         new VariableData[0],
1682                                         new String[0],
1683                                         _sd,
1684                                         null);
1685          _sd.addMethod(md4);
1686          assertEquals("There should still be one error.", 1, LanguageLevelVisitor.errors.size());
1687          MethodData md5 = new MethodData("methodNamePlusStuff",
1688                                         _publicMav,
1689                                         new TypeParameter[0],
1690                                         SymbolData.INT_TYPE,
1691                                         new VariableData[0],
1692                                         new String[0],
1693                                         _sd,
1694                                         null);
1695          _sd.addMethod(md5);
1696          assertEquals("There should still be one error.", 1, LanguageLevelVisitor.errors.size());
1697          // Check that _sd only has two methods, the original md and md5.
1698          assertEquals("There are three methods in _sd.", 3, _sd.getMethods().size());
1699          assertEquals("The original method was added.", md, _sd.getMethods().get(0));
1700          assertEquals("md5 was added.", md5, _sd.getMethods().get(2));
1701          
1702          // Check that adding a method from augmented code produces the correct error message.
1703          _sd.addMethod(md2, true);
1704          assertEquals("There should be two errors.", 2, LanguageLevelVisitor.errors.size());
1705          assertEquals("The error message should be correct.",
1706                       "This method's signature conflicts with an automatically generated method's signature",
1707                       LanguageLevelVisitor.errors.get(1).getFirst());
1708        }
1709        
1710        public void testIsNumberType() {
1711          assertTrue(SymbolData.INT_TYPE.isNumberType(JavaVersion.JAVA_5));
1712          assertTrue(new SymbolData("java.lang.Integer").isNumberType(JavaVersion.JAVA_5));
1713          assertTrue(SymbolData.DOUBLE_TYPE.isNumberType(JavaVersion.JAVA_5));
1714          assertTrue(new SymbolData("java.lang.Double").isNumberType(JavaVersion.JAVA_5));
1715          assertTrue(SymbolData.LONG_TYPE.isNumberType(JavaVersion.JAVA_5));
1716          assertTrue(new SymbolData("java.lang.Long").isNumberType(JavaVersion.JAVA_5));
1717          assertTrue(SymbolData.CHAR_TYPE.isNumberType(JavaVersion.JAVA_5));
1718          assertTrue(new SymbolData("java.lang.Character").isNumberType(JavaVersion.JAVA_5));
1719          assertTrue(SymbolData.FLOAT_TYPE.isNumberType(JavaVersion.JAVA_5));
1720          assertTrue(new SymbolData("java.lang.Float").isNumberType(JavaVersion.JAVA_5));
1721          assertTrue(SymbolData.SHORT_TYPE.isNumberType(JavaVersion.JAVA_5));
1722          assertTrue(new SymbolData("java.lang.Short").isNumberType(JavaVersion.JAVA_5));
1723          assertTrue(SymbolData.BYTE_TYPE.isNumberType(JavaVersion.JAVA_5));
1724          assertTrue(new SymbolData("java.lang.Byte").isNumberType(JavaVersion.JAVA_5));     
1725          assertFalse(SymbolData.BOOLEAN_TYPE.isNumberType(JavaVersion.JAVA_5));
1726          assertFalse(new SymbolData("java.lang.Boolean").isNumberType(JavaVersion.JAVA_5));
1727        }
1728    
1729        public void testIsNumberTypeWithoutAutoboxing() {
1730          assertTrue(SymbolData.INT_TYPE.isNumberTypeWithoutAutoboxing());
1731          assertFalse((new SymbolData("java.lang.Integer")).isNumberTypeWithoutAutoboxing());
1732          assertTrue(SymbolData.DOUBLE_TYPE.isNumberTypeWithoutAutoboxing());
1733          assertFalse((new SymbolData("java.lang.Double")).isNumberTypeWithoutAutoboxing());
1734          assertTrue(SymbolData.LONG_TYPE.isNumberTypeWithoutAutoboxing());
1735          assertFalse((new SymbolData("java.lang.Long")).isNumberTypeWithoutAutoboxing());
1736          assertTrue(SymbolData.CHAR_TYPE.isNumberTypeWithoutAutoboxing());
1737          assertFalse((new SymbolData("java.lang.Character")).isNumberTypeWithoutAutoboxing());
1738          assertTrue(SymbolData.FLOAT_TYPE.isNumberTypeWithoutAutoboxing());
1739          assertFalse((new SymbolData("java.lang.Float")).isNumberTypeWithoutAutoboxing());
1740          assertTrue(SymbolData.SHORT_TYPE.isNumberTypeWithoutAutoboxing());
1741          assertFalse((new SymbolData("java.lang.Short")).isNumberTypeWithoutAutoboxing());
1742          assertTrue(SymbolData.BYTE_TYPE.isNumberTypeWithoutAutoboxing());
1743          assertFalse((new SymbolData("java.lang.Byte")).isNumberTypeWithoutAutoboxing());     
1744          assertFalse(SymbolData.BOOLEAN_TYPE.isNumberTypeWithoutAutoboxing());
1745          assertFalse((new SymbolData("java.lang.Boolean")).isNumberTypeWithoutAutoboxing());
1746        }
1747    
1748        
1749        public void testIsIntType() {
1750          assertTrue(SymbolData.INT_TYPE.isIntType(JavaVersion.JAVA_5));
1751          assertTrue((new SymbolData("java.lang.Integer")).isIntType(JavaVersion.JAVA_5));
1752          assertFalse(SymbolData.DOUBLE_TYPE.isIntType(JavaVersion.JAVA_5));
1753          assertFalse((new SymbolData("java.lang.Double")).isIntType(JavaVersion.JAVA_5));
1754          assertFalse(SymbolData.LONG_TYPE.isIntType(JavaVersion.JAVA_5));
1755          assertFalse((new SymbolData("java.lang.Long")).isIntType(JavaVersion.JAVA_5));
1756          assertFalse(SymbolData.CHAR_TYPE.isIntType(JavaVersion.JAVA_5));
1757          assertFalse((new SymbolData("java.lang.Character")).isIntType(JavaVersion.JAVA_5));
1758          assertFalse(SymbolData.FLOAT_TYPE.isIntType(JavaVersion.JAVA_5));
1759          assertFalse((new SymbolData("java.lang.Float")).isIntType(JavaVersion.JAVA_5));
1760          assertFalse(SymbolData.SHORT_TYPE.isIntType(JavaVersion.JAVA_5));
1761          assertFalse((new SymbolData("java.lang.Short")).isIntType(JavaVersion.JAVA_5));
1762          assertFalse(SymbolData.BYTE_TYPE.isIntType(JavaVersion.JAVA_5));
1763          assertFalse((new SymbolData("java.lang.Byte")).isIntType(JavaVersion.JAVA_5));
1764          assertFalse(SymbolData.BOOLEAN_TYPE.isIntType(JavaVersion.JAVA_5));
1765          assertFalse((new SymbolData("java.lang.Boolean")).isIntType(JavaVersion.JAVA_5));
1766        }
1767        
1768    
1769        public void testIsDoubleType() {
1770          assertFalse(SymbolData.INT_TYPE.isDoubleType(JavaVersion.JAVA_5));
1771          assertFalse((new SymbolData("java.lang.Integer")).isDoubleType(JavaVersion.JAVA_5));
1772          assertTrue(SymbolData.DOUBLE_TYPE.isDoubleType(JavaVersion.JAVA_5));
1773          assertTrue((new SymbolData("java.lang.Double")).isDoubleType(JavaVersion.JAVA_5));
1774          assertFalse(SymbolData.CHAR_TYPE.isDoubleType(JavaVersion.JAVA_5));
1775          assertFalse((new SymbolData("java.lang.Character")).isDoubleType(JavaVersion.JAVA_5));
1776          assertFalse(SymbolData.FLOAT_TYPE.isDoubleType(JavaVersion.JAVA_5));
1777          assertFalse((new SymbolData("java.lang.Float")).isDoubleType(JavaVersion.JAVA_5));
1778          assertFalse(SymbolData.SHORT_TYPE.isDoubleType(JavaVersion.JAVA_5));
1779          assertFalse((new SymbolData("java.lang.Short")).isDoubleType(JavaVersion.JAVA_5));
1780          assertFalse(SymbolData.BYTE_TYPE.isDoubleType(JavaVersion.JAVA_5));
1781          assertFalse((new SymbolData("java.lang.Byte")).isDoubleType(JavaVersion.JAVA_5));
1782          assertFalse(SymbolData.BOOLEAN_TYPE.isDoubleType(JavaVersion.JAVA_5));
1783          assertFalse((new SymbolData("java.lang.Boolean")).isDoubleType(JavaVersion.JAVA_5));
1784        }
1785        
1786        public void testIsCharType() {
1787          assertFalse(SymbolData.INT_TYPE.isCharType(JavaVersion.JAVA_5));
1788          assertFalse((new SymbolData("java.lang.Integer")).isCharType(JavaVersion.JAVA_5));
1789          assertFalse(SymbolData.DOUBLE_TYPE.isCharType(JavaVersion.JAVA_5));
1790          assertFalse((new SymbolData("java.lang.Double")).isCharType(JavaVersion.JAVA_5));
1791          assertTrue(SymbolData.CHAR_TYPE.isCharType(JavaVersion.JAVA_5));
1792          assertTrue((new SymbolData("java.lang.Character")).isCharType(JavaVersion.JAVA_5));
1793          assertFalse(SymbolData.FLOAT_TYPE.isCharType(JavaVersion.JAVA_5));
1794          assertFalse((new SymbolData("java.lang.Float")).isCharType(JavaVersion.JAVA_5));
1795          assertFalse(SymbolData.SHORT_TYPE.isCharType(JavaVersion.JAVA_5));
1796          assertFalse((new SymbolData("java.lang.Short")).isCharType(JavaVersion.JAVA_5));
1797          assertFalse(SymbolData.BYTE_TYPE.isCharType(JavaVersion.JAVA_5));
1798          assertFalse((new SymbolData("java.lang.Byte")).isCharType(JavaVersion.JAVA_5));
1799          assertFalse(SymbolData.BOOLEAN_TYPE.isCharType(JavaVersion.JAVA_5));
1800          assertFalse((new SymbolData("java.lang.Boolean")).isCharType(JavaVersion.JAVA_5));
1801        }
1802        
1803        public void testIsFloatType() {
1804          assertFalse(SymbolData.INT_TYPE.isFloatType(JavaVersion.JAVA_5));
1805          assertFalse((new SymbolData("java.lang.Integer")).isFloatType(JavaVersion.JAVA_5));
1806          assertFalse(SymbolData.DOUBLE_TYPE.isFloatType(JavaVersion.JAVA_5));
1807          assertFalse((new SymbolData("java.lang.Double")).isFloatType(JavaVersion.JAVA_5));
1808          assertFalse(SymbolData.CHAR_TYPE.isFloatType(JavaVersion.JAVA_5));
1809          assertFalse((new SymbolData("java.lang.Character")).isFloatType(JavaVersion.JAVA_5));
1810          assertTrue(SymbolData.FLOAT_TYPE.isFloatType(JavaVersion.JAVA_5));
1811          assertTrue((new SymbolData("java.lang.Float")).isFloatType(JavaVersion.JAVA_5));
1812          assertFalse(SymbolData.SHORT_TYPE.isFloatType(JavaVersion.JAVA_5));
1813          assertFalse((new SymbolData("java.lang.Short")).isFloatType(JavaVersion.JAVA_5));
1814          assertFalse(SymbolData.BYTE_TYPE.isFloatType(JavaVersion.JAVA_5));
1815          assertFalse((new SymbolData("java.lang.Byte")).isFloatType(JavaVersion.JAVA_5));
1816          assertFalse(SymbolData.BOOLEAN_TYPE.isFloatType(JavaVersion.JAVA_5));
1817          assertFalse((new SymbolData("java.lang.Boolean")).isFloatType(JavaVersion.JAVA_5));
1818        }
1819        
1820        
1821        public void testIsByteType() {
1822          assertFalse(SymbolData.INT_TYPE.isByteType(JavaVersion.JAVA_5));
1823          assertFalse((new SymbolData("java.lang.Integer")).isByteType(JavaVersion.JAVA_5));
1824          assertFalse(SymbolData.DOUBLE_TYPE.isByteType(JavaVersion.JAVA_5));
1825          assertFalse((new SymbolData("java.lang.Double")).isByteType(JavaVersion.JAVA_5));
1826          assertFalse(SymbolData.CHAR_TYPE.isByteType(JavaVersion.JAVA_5));
1827          assertFalse((new SymbolData("java.lang.Character")).isByteType(JavaVersion.JAVA_5));
1828          assertFalse(SymbolData.FLOAT_TYPE.isByteType(JavaVersion.JAVA_5));
1829          assertFalse((new SymbolData("java.lang.Float")).isByteType(JavaVersion.JAVA_5));
1830          assertFalse(SymbolData.SHORT_TYPE.isByteType(JavaVersion.JAVA_5));
1831          assertFalse((new SymbolData("java.lang.Short")).isByteType(JavaVersion.JAVA_5));
1832          assertTrue(SymbolData.BYTE_TYPE.isByteType(JavaVersion.JAVA_5));
1833          assertTrue((new SymbolData("java.lang.Byte")).isByteType(JavaVersion.JAVA_5));
1834          assertFalse(SymbolData.BOOLEAN_TYPE.isByteType(JavaVersion.JAVA_5));
1835          assertFalse((new SymbolData("java.lang.Boolean")).isByteType(JavaVersion.JAVA_5));
1836        }
1837        
1838        public void testIsBooleanType() {
1839          assertFalse(SymbolData.INT_TYPE.isBooleanType(JavaVersion.JAVA_5));
1840          assertFalse((new SymbolData("java.lang.Integer")).isBooleanType(JavaVersion.JAVA_5));
1841          assertFalse(SymbolData.DOUBLE_TYPE.isBooleanType(JavaVersion.JAVA_5));
1842          assertFalse((new SymbolData("java.lang.Double")).isBooleanType(JavaVersion.JAVA_5));
1843          assertFalse(SymbolData.CHAR_TYPE.isBooleanType(JavaVersion.JAVA_5));
1844          assertFalse((new SymbolData("java.lang.Character")).isBooleanType(JavaVersion.JAVA_5));
1845          assertFalse(SymbolData.FLOAT_TYPE.isBooleanType(JavaVersion.JAVA_5));
1846          assertFalse((new SymbolData("java.lang.Float")).isBooleanType(JavaVersion.JAVA_5));
1847          assertFalse(SymbolData.SHORT_TYPE.isBooleanType(JavaVersion.JAVA_5));
1848          assertFalse((new SymbolData("java.lang.Short")).isBooleanType(JavaVersion.JAVA_5));
1849          assertFalse(SymbolData.BYTE_TYPE.isBooleanType(JavaVersion.JAVA_5));
1850          assertFalse((new SymbolData("java.lang.Byte")).isBooleanType(JavaVersion.JAVA_5));
1851          assertTrue(SymbolData.BOOLEAN_TYPE.isBooleanType(JavaVersion.JAVA_5));
1852          assertTrue((new SymbolData("java.lang.Boolean")).isBooleanType(JavaVersion.JAVA_5));
1853        }
1854        
1855        public void testIsNonFloatOrBooleanType() {
1856          assertTrue(SymbolData.INT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1857          assertTrue(new SymbolData("java.lang.Integer").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1858          assertFalse(SymbolData.DOUBLE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1859          assertFalse(new SymbolData("java.lang.Double").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1860          assertTrue(SymbolData.CHAR_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1861          assertTrue(new SymbolData("java.lang.Character").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1862          assertFalse(SymbolData.FLOAT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1863          assertFalse(new SymbolData("java.lang.Float").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1864          assertTrue(SymbolData.SHORT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1865          assertTrue(new SymbolData("java.lang.Short").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1866          assertTrue(SymbolData.BYTE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1867          assertTrue(new SymbolData("java.lang.Byte").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1868          assertTrue(SymbolData.LONG_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1869          assertTrue(new SymbolData("java.lang.Long").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1870          assertTrue(SymbolData.BOOLEAN_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1871          assertTrue(new SymbolData("java.lang.Boolean").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1872          
1873        }
1874        
1875        public void testIsNonFloatOrBooleanTypeWithoutAutoboxing() {
1876          assertTrue(SymbolData.INT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1877          assertFalse(SymbolData.DOUBLE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1878          assertTrue(SymbolData.CHAR_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1879          assertFalse(SymbolData.FLOAT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1880          assertTrue(SymbolData.SHORT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1881          assertTrue(SymbolData.BYTE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1882          assertTrue(SymbolData.LONG_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1883          assertTrue(SymbolData.BOOLEAN_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
1884        }
1885        
1886        
1887        public void testEquals() {
1888          SymbolData superSd = new SymbolData("superClass");
1889          _sd = 
1890            new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1891          
1892          //check variables that are equal;
1893          SymbolData _sd2 = 
1894            new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1895          assertTrue("Equals should return true if two SymbolDatas are equal", _sd.equals(_sd2));
1896          assertTrue("Equals should return true in opposite direction as well", _sd2.equals(_sd));
1897    
1898          //comparison to null
1899          assertFalse("Equals should return false if SymbolData is compared to null",_sd.equals(null));   
1900        
1901          //different names
1902          _sd2 = new SymbolData("q", _publicMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1903          assertFalse("Equals should return false if class names are different", _sd.equals(_sd2));
1904          
1905          //different MAV
1906          _sd2 = 
1907            new SymbolData("i.like.monkey", _protectedMav, new TypeParameter[0], superSd, new ArrayList<SymbolData>(), null);
1908          assertFalse("Equals should return false if class modifiers are different", _sd.equals(_sd2));
1909          
1910          //different type parameters
1911          _sd2 = 
1912            new SymbolData("i.like.monkey", 
1913                           _publicMav, 
1914                           new TypeParameter[] { new TypeParameter(SourceInfo.NONE, 
1915                                                                   new TypeVariable(SourceInfo.NONE,"tv"), 
1916                                                                   new TypeVariable(SourceInfo.NONE,"i")) }, 
1917                           superSd, 
1918                           new ArrayList<SymbolData>(), null);
1919          assertFalse("Equals should return false if class type parameters are different", _sd.equals(_sd2));
1920          
1921          //different super classes
1922          _sd2 = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], null, new ArrayList<SymbolData>(), null);
1923          assertFalse("Equals should return false if super classes are different", _sd.equals(_sd2));
1924          
1925          //different interfaces
1926          ArrayList<SymbolData> interfaces = new ArrayList<SymbolData>();
1927          interfaces.add(SymbolData.INT_TYPE);
1928          _sd2 = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, interfaces, null);
1929          assertFalse("Equals should return false if the interfaces are different", _sd.equals(_sd2));
1930        }
1931         
1932        public void testImplementsRunnable() {
1933          SymbolData sd1 = new SymbolData("java.lang.Thread");
1934          SymbolData sd2 = new SymbolData("java.util.TimerTask");
1935          SymbolData sd3 = new SymbolData("javax.swing.text.AsyncBoxView$ChildState");
1936          SymbolData sd4 = new SymbolData("java.awt.image.renderable.RenderableImageProducer");
1937          SymbolData sd5 = new SymbolData("java.util.concurrent.FutureTask");
1938          SymbolData sd6 = new SymbolData("java.util.Vector");
1939          assertTrue("Should implement Runnable", sd1.implementsRunnable());
1940          assertTrue("Should implement Runnable", sd2.implementsRunnable());
1941          assertTrue("Should implement Runnable", sd3.implementsRunnable());
1942          assertTrue("Should implement Runnable", sd4.implementsRunnable());
1943          assertTrue("Should implement Runnable", sd5.implementsRunnable());
1944          assertFalse("Should not implement Runnable", sd6.implementsRunnable());
1945        }
1946      
1947        public void testHasInterface() {
1948          /* Runnable has two subinterfacers, subRunnable and subRunnable2.  subRunnable has a subclass someSd and
1949             subRunnable2 has a subclass someOtherSd. */
1950          
1951          SymbolData runnable = new SymbolData("java.lang.Runnable");
1952          runnable.setInterface(true);
1953          SymbolData subRunnable = new SymbolData("edgar");
1954          subRunnable.setInterface(true);
1955          subRunnable.addInterface(runnable);
1956          assertTrue(subRunnable.hasInterface(runnable));
1957          SymbolData subRunnable2 = new SymbolData("jones");
1958          subRunnable2.setInterface(true);
1959          subRunnable2.addInterface(runnable);
1960          assertTrue(subRunnable2.hasInterface(runnable));
1961          SymbolData someSd = new SymbolData("someSd");
1962          someSd.addInterface(subRunnable);      
1963          assertTrue(someSd.hasInterface(runnable));
1964          SymbolData someOtherSd = new SymbolData("someOtherSd");
1965          someOtherSd.addInterface(subRunnable2);
1966          assertTrue(someOtherSd.hasInterface(runnable));
1967          SymbolData notRunnable = new SymbolData("aksdf");
1968          assertFalse(notRunnable.hasInterface(runnable));
1969          someOtherSd.addInterface(notRunnable);
1970          assertTrue(someOtherSd.hasInterface(runnable));
1971          
1972          // Try myClass without setting a super class, then try it once it's super class is someSd.
1973          SymbolData myClass = new SymbolData("myClass");
1974          assertFalse(myClass.hasInterface(runnable));
1975          myClass.setSuperClass(someSd);
1976          assertTrue(myClass.hasInterface(runnable));
1977          SymbolData myClass2 = new SymbolData("myClass2");
1978          assertFalse(myClass2.hasInterface(runnable));
1979          myClass2.addInterface(someOtherSd);
1980          assertTrue(myClass2.hasInterface(runnable));
1981        }
1982        
1983        public void test_isAssignable() {
1984          MethodData md = 
1985            new MethodData("Overwritten", _publicMav, new TypeParameter[0], _sd, new VariableData[0], new String[0], _sd, 
1986                           new NullLiteral(SourceInfo.NONE));
1987          MethodData md2 = 
1988            new MethodData("Overwriting", _publicMav, new TypeParameter[0], _sd, new VariableData[0], new String[0], _sd, 
1989                           new NullLiteral(SourceInfo.NONE));
1990    
1991          //tests a wide variety of possibilities, but not all possibilities.
1992          assertTrue("Should be assignable", _isCompatible(md, md2));
1993          md.setMav(_protectedMav);
1994          assertTrue("Should be assignable", _isCompatible(md, md2));
1995          md.setMav(_privateMav);
1996          assertTrue("Should be assignable", _isCompatible(md, md2));
1997          md.setMav(_packageMav);
1998          assertTrue("Should be assignable", _isCompatible(md, md2));
1999          md2.setMav(_protectedMav);
2000          assertTrue("Should be assignable", _isCompatible(md, md2));
2001          md2.setMav(_privateMav);
2002          assertFalse("Should not be assignable", _isCompatible(md, md2));
2003          md2.setMav(_packageMav);
2004          assertTrue("Should be assignable", _isCompatible(md, md2));
2005          
2006        }
2007        
2008        
2009        public void testRepeatedNameInHierarchy() {
2010          SymbolData _d = new SymbolData("myname");
2011          
2012          VariableData vd = new VariableData("v1", _publicMav, SymbolData.INT_TYPE, false, _d);
2013    
2014          //compare a vd to an symbol data with no vars
2015          assertFalse("No variables to repeat name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2016          
2017          //compare a vd to a symbol data with 1 var with a different name
2018          _d.addVar(new VariableData("v2", _protectedMav, SymbolData.BOOLEAN_TYPE, true, _d));
2019          assertFalse("No repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2020          
2021          //compare a vd to a symbol data who has a var with the same name
2022          _d.addVar(vd);
2023          assertTrue("Should be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2024          
2025          //what if super class has var
2026          _d.setVars(new LinkedList<VariableData>());
2027          SymbolData superC = new SymbolData("I am a super class");
2028          superC.addVar(new VariableData(vd.getName(), _protectedMav, SymbolData.DOUBLE_TYPE, false, superC));
2029          _d.setSuperClass(superC);
2030          assertTrue("Should be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2031          
2032          //what if interface has var
2033          _d.clearSuperClass();
2034          _d.addInterface(superC);
2035          assertTrue("Should also be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
2036        }
2037        
2038        public void testAddFinalVars() {
2039          SymbolData _d = new SymbolData("genius");
2040          VariableData vd = new VariableData("v1", _publicMav, SymbolData.INT_TYPE, true, _d);
2041          VariableData vd2 = new VariableData("v2", _publicMav, SymbolData.CHAR_TYPE, true, _d);
2042          VariableData[] toAdd = new VariableData[] {vd, vd2};
2043          LinkedList<VariableData> myVds = new LinkedList<VariableData>();
2044          
2045          //first adding array
2046          myVds.addLast(vd);
2047          myVds.addLast(vd2);
2048          assertTrue("Should be able to add new vars array", _d.addFinalVars(toAdd));
2049          assertEquals("Variable list should have 2 variables", myVds, _d.getVars());
2050          
2051          //trying to read array whose variables are already there.
2052          assertFalse("Should not be able to add same variables again", _d.addFinalVars(toAdd));
2053          assertEquals("Variable list should not have changed", myVds, _d.getVars());
2054          assertTrue("vd should now be final", _d.getVars().get(0).hasModifier("final"));
2055          assertTrue("vd2 should now be final", _d.getVars().get(1).hasModifier("final"));
2056    
2057          
2058          
2059          //trying to add a different array
2060          VariableData vd3 = new VariableData("v3", _publicFinalMav, SymbolData.INT_TYPE, true, _d);
2061          VariableData[] toAdd2 = new VariableData[] {vd3};
2062          myVds.addLast(vd3);
2063          
2064          assertTrue("Should be able to add new variable array", _d.addFinalVars(toAdd2));
2065          assertEquals("Variable list should now have 3 variables", myVds, _d.getVars());
2066          assertTrue("vd3 should now be final", _d.getVars().get(2).hasModifier("final"));
2067    
2068          
2069          //try adding an empty array of variable datas
2070          assertTrue("Should be able to add an empty array", _d.addFinalVars(new VariableData[0]));
2071          assertEquals("Variable list should not have changed by adding empty array", myVds, _d.getVars());
2072        }
2073        
2074        public void testGetAllVars() {
2075          SymbolData sd1 = new SymbolData("SubSub");
2076          SymbolData sd2 = new SymbolData("Sub");
2077          SymbolData sd3 = new SymbolData("Super");
2078          SymbolData sd4 = new SymbolData("SuperInterface");
2079          sd4.setInterface(true);
2080          SymbolData sd5 = new SymbolData("NotRelated");
2081          
2082          sd1.setSuperClass(sd2);
2083          sd2.setSuperClass(sd3);
2084          sd2.addInterface(sd4);
2085    
2086          VariableData vd1 = new VariableData("vd1", _finalMav, SymbolData.INT_TYPE, false, sd1);
2087          VariableData vd2 = new VariableData("vd2", _finalMav, SymbolData.INT_TYPE, false, sd2);
2088          VariableData vd3 = new VariableData("vd3", _finalMav, SymbolData.INT_TYPE, false, sd3);
2089          VariableData vd4 = new VariableData("vd4", _finalMav, SymbolData.INT_TYPE, false, sd4);
2090          VariableData vd5 = new VariableData("vd5", _finalMav, SymbolData.INT_TYPE, false, sd5);
2091    
2092          sd1.addVar(vd1);
2093          sd2.addVar(vd2);
2094          sd3.addVar(vd3);
2095          sd4.addVar(vd4);
2096          sd5.addVar(vd5);
2097          
2098          LinkedList<VariableData> shouldContain = new LinkedList<VariableData>();
2099          shouldContain.addLast(vd2);
2100          shouldContain.addLast(vd3);
2101          shouldContain.addLast(vd4);
2102    
2103          LinkedList<VariableData> vds = sd1.getAllSuperVars();
2104          assertEquals("the list should have 3 elements", 3, vds.size());
2105          assertEquals("The list should be correct", shouldContain, vds);
2106        }
2107    
2108        public void testIsSubclassOf() {
2109          _sd = new SymbolData("subClass");
2110          SymbolData superC = new SymbolData("superC");
2111          _sd._superClass = superC;
2112          
2113          //not subclass
2114          assertFalse("subClass, int, and boolean are not related", _sd.isSubClassOf(SymbolData.BOOLEAN_TYPE));
2115          
2116          //same class
2117          assertTrue("subClass is a subclass of itself", _sd.isSubClassOf(_sd));
2118          
2119          //direct subclass
2120          assertTrue("subClass is a subclass of its super class", _sd.isSubClassOf(superC));
2121          
2122          //subclass of subclass of provided data
2123          superC._superClass = SymbolData.CHAR_TYPE;
2124          assertTrue("subClass is a subclass of its super class's super class", _sd.isSubClassOf(SymbolData.CHAR_TYPE));
2125          
2126          //Interface
2127          SymbolData myData = new SymbolData("yes");
2128          SymbolData yourData = new SymbolData("interface");
2129          yourData.setInterface(true);
2130          myData.setIsContinuation(false);
2131          myData.addInterface(yourData);
2132          yourData.setIsContinuation(false);
2133          assertTrue("Should be assignable", myData.isSubClassOf(yourData));
2134        }
2135    
2136        public void testIsInnerClassOf() {
2137          _sd = new SymbolData("innerClass");
2138          SymbolData outer1 = new SymbolData("outer1");
2139          outer1.addInnerClass(_sd);
2140          _sd.setOuterData(outer1);
2141          SymbolData outer2 = new SymbolData("outer2");
2142          outer2.addInnerClass(outer1);
2143          outer1.setOuterData(outer2);
2144          outer2.setMav(new ModifiersAndVisibility(SourceInfo.NONE, new String[] {"static"}));
2145          SymbolData outer3 = new SymbolData("outer3");
2146          outer3.addInnerClass(outer2);
2147          outer2.setOuterData(outer3);
2148          
2149          
2150          SymbolData notInChain = new SymbolData("no");
2151          
2152          assertTrue("_sd is an inner class of itself", _sd.isInnerClassOf(_sd, true));
2153          assertTrue("outer1 is the outer class of _sd", _sd.isInnerClassOf(outer1, true));
2154          assertTrue("outer2 is an outer class of _sd", _sd.isInnerClassOf(outer2, true));
2155          assertTrue("outer2 is an outer class of itself", outer2.isInnerClassOf(outer2, true));
2156          assertFalse("_sd is not related to notInChain", _sd.isInnerClassOf(notInChain, true));
2157          assertFalse("_sd is not an outer class of outer1", outer1.isInnerClassOf(_sd, true));
2158          assertFalse("outer3 cannot be seen from _sd if the static flag is true, because outer2 is static", 
2159                      _sd.isInnerClassOf(outer3, true));
2160          assertTrue("But, outer3 is an outer class of _sd", _sd.isInnerClassOf(outer3, false));
2161        }
2162        
2163        public void testCreateUniqueMethodName() {
2164          SymbolData george = new SymbolData("George");
2165          VariableData[] noVars = new VariableData[0];
2166          george.addMethod(new MethodData("getFriends", noVars));
2167          george.addMethod(new MethodData("sayHello", noVars));
2168          
2169          SymbolData iAteGeorge = new SymbolData("IAteGeorge");
2170          iAteGeorge.addMethod(new MethodData("sayHello", noVars));
2171          iAteGeorge.addMethod(new MethodData("sayHello0", noVars));
2172          iAteGeorge.addInnerClass(george);
2173          george.setOuterData(iAteGeorge);
2174          
2175          SymbolData mrsGeorge = new SymbolData("MrsGeorge");
2176          mrsGeorge.addMethod(new MethodData("sayHello1", noVars));
2177          george.setSuperClass(mrsGeorge);
2178          
2179          SymbolData grandmaGeorge = new SymbolData("GrandmaGeorge");
2180          grandmaGeorge.addMethod(new MethodData("sayHello2", noVars));
2181          grandmaGeorge.addMethod(new MethodData("sayHello5", noVars));
2182          george.addInterface(grandmaGeorge);
2183          
2184          SymbolData papaOfIAteGeorge = new SymbolData("PapaOfIAteGeorge");
2185          papaOfIAteGeorge.addMethod(new MethodData("sayHello3", noVars));
2186          iAteGeorge.setSuperClass(papaOfIAteGeorge);
2187          
2188          assertEquals("The generated name is correct when SymbolData has that method name",
2189                       "getFriends0", george.createUniqueMethodName("getFriends"));
2190          assertEquals("The generated name is correct when SymbolData doesn't have a method of that name",
2191                       "eatDinner", george.createUniqueMethodName("eatDinner"));
2192          assertEquals("The generated name is correct when a super class uses the name",
2193                       "sayHello10", george.createUniqueMethodName("sayHello1"));
2194          assertEquals("The generated name is correct when an outer class uses the name",
2195                       "sayHello00", george.createUniqueMethodName("sayHello0"));
2196          assertEquals("The generated name is correct when an interface uses the name",
2197                       "sayHello20", george.createUniqueMethodName("sayHello2"));
2198          assertEquals("The generated name is correct when a super class of an outer class uses the name",
2199                       "sayHello30", george.createUniqueMethodName("sayHello3"));
2200          assertEquals("The generated name is correct when a super class of an outer class uses the name",
2201                       "sayHello30", george.createUniqueMethodName("sayHello3"));
2202          assertEquals("The generated name is correct when a lot of things use the name",
2203                       "sayHello4", george.createUniqueMethodName("sayHello"));
2204          
2205        }
2206      }
2207    }