Code Search for Developers
 
 
  

SymbolData.java from DrJava at Krugle


Show SymbolData.java syntax highlighted

package edu.rice.cs.javalanglevels;

import edu.rice.cs.javalanglevels.tree.*;
import edu.rice.cs.javalanglevels.parser.JExprParser;
import java.util.*;

/*BEGIN_COPYRIGHT_BLOCK
 *
 * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software is Open Source Initiative approved Open Source Software.
 * Open Source Initative Approved is a trademark of the Open Source Initiative.
 * 
 * This file is part of DrJava.  Download the current version of this project
 * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 * 
 * END_COPYRIGHT_BLOCK*/

import junit.framework.TestCase;

import edu.rice.cs.plt.reflect.JavaVersion;

/**
 * Represents the data for a given class.  There are two states of SymbolData.  One is a continuation which
 * is created when a type is referenced, but the corresponding class has not been read for its members.  The
 * other is a complete SymbolData containing all of the member data.
 */
public class SymbolData extends TypeData {
  /***************Singleton primitive SymbolDatas********************/
  
  /**This represents the boolean primitive*/
  public static final SymbolData BOOLEAN_TYPE = new PrimitiveData("boolean") {
    
    /**
     * You can only cast a boolean primitive to a boolean primitive or a Boolean object (in 1.5).
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version);
    }
    
    /**
     * Returns true if the specified SymbolData is a boolean type
     */
    public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
      if (toCheck == null) {return false;}
      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !toCheck.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Boolean");
        return (autoBoxMe != null && autoBoxMe.isAssignableTo(toCheck, version));
      }
      return toCheck==BOOLEAN_TYPE;
    }
    
  };
  
  
  /**This represents the char primitive*/
  public static final SymbolData CHAR_TYPE = new PrimitiveData("char") {
    
    /**
     * You can cast a char primitive to a char, int, long, float, double or short or byte or Character object (in 1.5)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version) || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
    }

    /**
     * You can assign a char primitive to a char, int, long, float, double or Character object (in 1.5)
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      if (assignTo == null) {return false;}
      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Character");
        return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
      }

      return assignTo==SymbolData.INT_TYPE || 
        assignTo==SymbolData.LONG_TYPE || 
        assignTo == SymbolData.FLOAT_TYPE || 
        assignTo == SymbolData.DOUBLE_TYPE || 
        assignTo == SymbolData.CHAR_TYPE;
    }
  };
  
  /**This represents the byte primitive*/
  public static final SymbolData BYTE_TYPE = new PrimitiveData("byte"){
    
    /**
     * You can cast a byte primitive to a char, int, long, float, double or short or byte or Byte object (in 1.5)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE;
    }

    /**
     * You can assign a byte primitive to a byte, short, int, long, float, double, or Byte object(in 1.5)
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      if (assignTo == null) {return false;}

      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Byte");
        return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
      }

      return assignTo==SymbolData.BYTE_TYPE || 
        assignTo==SymbolData.SHORT_TYPE || 
        assignTo == SymbolData.INT_TYPE || 
        assignTo == SymbolData.LONG_TYPE || 
        assignTo == SymbolData.FLOAT_TYPE || 
        assignTo == SymbolData.DOUBLE_TYPE;
        
    }
  };
  
  
  
  /**This represents the short primitive*/
  public static final SymbolData SHORT_TYPE = new PrimitiveData("short"){
    
    /**
     * You can cast a short primitive to a char, int, long, float, double or short or byte or Short object (in 1.5)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.BYTE_TYPE;
    }

    /**
     * You can assign a short primitive to a short, int, long, float, double, or Short object(in 1.5)
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      if (assignTo == null) {return false;}

      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Short");
        return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
      }

      
      return assignTo==SymbolData.SHORT_TYPE || 
        assignTo == SymbolData.INT_TYPE || 
        assignTo == SymbolData.LONG_TYPE || 
        assignTo == SymbolData.FLOAT_TYPE || 
        assignTo == SymbolData.DOUBLE_TYPE; 
        
    }
  };
  
  /**This represents the int primitive*/
  public static final SymbolData INT_TYPE = new PrimitiveData("int"){
    
    /**
     * You can cast a int primitive to a char, int, long, float, double or short or byte or Short object (in 1.5)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
    }

    /**
     * You can assign a int primitive to a int, long, float, double, or Integer object(in 1.5)
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      if (assignTo == null) {return false;}

      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Integer");
        return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
      }

      return assignTo == SymbolData.INT_TYPE || 
        assignTo == SymbolData.LONG_TYPE || 
        assignTo == SymbolData.FLOAT_TYPE || 
        assignTo == SymbolData.DOUBLE_TYPE;
        
    }
  };
  
  
  /**This represents the long primitive*/
  public static final SymbolData LONG_TYPE = new PrimitiveData("long"){
    
    /**
     * You can cast a long primitive to a char, int, long, float, double or short or byte or Short object (in 1.5)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
    }

    /**
     * You can assign a long primitive to a long, float, double, or Long object(in 1.5)
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      if (assignTo == null) {return false;}

      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Long");
        return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
      }

      return assignTo == SymbolData.LONG_TYPE || 
        assignTo == SymbolData.FLOAT_TYPE || 
        assignTo == SymbolData.DOUBLE_TYPE;
        
    }
  };
  
  /**This represents the float primitive*/
  public static final SymbolData FLOAT_TYPE = new PrimitiveData("float"){
    
    /**
     * You can cast a float primitive to a char, int, long, float, double or short or byte or Short object (in 1.5)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE || castTo == SymbolData.LONG_TYPE || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
    }

    /**
     * You can assign a float primitive to a float, double, or Float object(in 1.5)
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      if (assignTo == null) {return false;}

      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Float");
        return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
      }

      return assignTo == SymbolData.FLOAT_TYPE || assignTo == SymbolData.DOUBLE_TYPE;
    }
  };
  
  /**This represents the double primitive*/
  public static final SymbolData DOUBLE_TYPE = new PrimitiveData("double"){
    
    /**
     * You can cast a double primitive to a char, int, long, float, double or short or byte or Short object (in 1.5)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version) || castTo == SymbolData.CHAR_TYPE || castTo == SymbolData.INT_TYPE || castTo == SymbolData.LONG_TYPE || castTo == SymbolData.DOUBLE_TYPE || castTo == SymbolData.SHORT_TYPE || castTo == SymbolData.BYTE_TYPE;
    }

    /**
     * You can assign a double primitive to a float, double, or Float object(in 1.5)
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      if (assignTo == null) {return false;}

      if (LanguageLevelConverter.versionSupportsAutoboxing(version) && !assignTo.isPrimitiveType()) {
        SymbolData autoBoxMe = LanguageLevelVisitor.symbolTable.get("java.lang.Double");
        return autoBoxMe != null && autoBoxMe.isAssignableTo(assignTo, version);
      }

      return assignTo == SymbolData.DOUBLE_TYPE; 

    }
  };
  
  /**Used for the void type*/
  public static final SymbolData VOID_TYPE = new PrimitiveData("void") {
  
    /** A void value cannot be cast to anything */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return false;
    }
    
    /** A void value can be assigned to itself */
    public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
      return this==toCheck;
    }
  
  };
  
  /**Used for an exception*/
  public static final SymbolData EXCEPTION = new SymbolData("exception") {
    /**
     * You cannot cast an exception to anything.
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return false;
    }
    
    /**
     * Returns true, because an exception takes the place of a return.
     * This SymbolData is only used when the user has thrown an Exception.
     */
    public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
      return true;
    }
    
  };

  /**Used when there was an error, but we want to keep going*/
  public static final SymbolData KEEP_GOING = new SymbolData("keep going") {
  
    /** A keep going value cannot be cast to anything */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return false;
    }
    
    /** A keep going value cannot be assigned to anything */
    public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
      return false;
    }
  
  };
  
 /**Used for null*/
  public static final SymbolData NULL_TYPE = new SymbolData("null") {

    /**
     * You can cast null to any reference type (i.e. something that is not a primitive)
     */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return isAssignableTo(castTo, version);
    }

    /**
     * You can assign a null to any reference (non-primitive) type
     */
    public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
      return (assignTo != null) && !(assignTo.isPrimitiveType());
    }
    
  };
  
  /**Used when 2 or more SymbolDatas could match*/
  public static final SymbolData AMBIGUOUS_REFERENCE = new SymbolData("ambiguous reference") {
    /** An ambiguous reference cannot be cast to anything */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return false;
    }
    
    /** An ambiguous reference cannot be assigned to anything */
    public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
      return false;
    }
  
  };
  
    /**Used when a this constructor invocation is seen*/
  public static final SymbolData THIS_CONSTRUCTOR = new SymbolData("this constructor") {
    /** Cannot be cast to anything */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return false;
    }
    
    /** Cannot be assigned to anything */
    public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
      return false;
    }
  
  };
  
    /**Used when a super constructor invocation is seen*/
  public static final SymbolData SUPER_CONSTRUCTOR = new SymbolData("super constructor") {
    /** Cannot be cast to anything */
    public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
      return false;
    }
    
    /** Cannot be assigned to anything */
    public boolean isAssignableTo(SymbolData toCheck, JavaVersion version) {
      return false;
    }
  
  };

  

  /**Do some initialization*/
  static {
    ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"public"});
    VOID_TYPE.setIsContinuation(false);    
    VOID_TYPE.setMav(_publicMav);
    KEEP_GOING.setIsContinuation(false);
    KEEP_GOING.setMav(_publicMav);
    EXCEPTION.setMav(_publicMav);
    EXCEPTION.setIsContinuation(false);
  }
  
  
  /********Instance fields***********/
  
  /**True if this symbol data is a continuation (i.e. hasn't been resolved)*/
  private boolean _isContinuation;

  /**The generic type information for this class.  Not used*/
  private TypeParameter[] _typeParameters;
  
  /**List of methods defined in this class*/
  private LinkedList<MethodData> _methods;
  
  /**The SymbolData corresponding to this class's super class*/
  private SymbolData _superClass;
  
  /**List of SymbolDatas corresponding to super interfaces*/
  private LinkedList<SymbolData> _interfaces;
  
  /**List of SymbolDatas corresponding to inner interfaces*/
  private LinkedList<SymbolData> _innerInterfaces;
  
  /**Flag that is true if this SymbolData is an interface*/
  private boolean _isInterface;
  
  /**Stores the package information for this symbol data*/
  private String _package;
  
  /**Represents an instance of this class--i.e. an instantiation of it.*/
  private InstanceData _instanceData;
  
  /**The current constructor count.  Incremented during first pass, decremented during second pass.*/
  private int _constructorNumber;
  
  /** The number of local classes, used in naming them.*/
  private int _localClassNum;
  
  /* The number of anonymous inner classes, used in naming them. */
  private int _anonymousInnerClassNum;  
  

  /**
   * Constructor for SymbolData
   * @param name  The name of this class or interface
   * @param modifiersAndVisibility  The modifiersAndVisibility of this class or interface
   * @param typeParameters  Generic type info, not used
   * @param superClass  The super class of this class
   * @param interfaces  The super interfaces
   * @param outerData  The enclosing data of this class, or null
   */
  public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters, 
                    SymbolData superClass, LinkedList<SymbolData> interfaces, Data outerData) {
    super(outerData);
    _name = name;
    _modifiersAndVisibility = modifiersAndVisibility;
    _typeParameters = typeParameters;
    _methods = new LinkedList<MethodData>();
    _superClass = superClass;
    _interfaces = interfaces;
    for (int i = 0; i < interfaces.size(); i++) {
      addEnclosingData(_interfaces.get(i));
    }
    /* Add first because we want to look at the super class first */
    _enclosingData.addFirst(_superClass);
    _innerClasses = new LinkedList<SymbolData>();
    _innerInterfaces = new LinkedList<SymbolData>();
    _isContinuation = false;
    _isInterface = false;
    _localClassNum = 0;
    _anonymousInnerClassNum = 0;
    _package = "";
    _constructorNumber = 0;
    _instanceData = new InstanceData(this);
  }

  /**
   * Constructor for SymbolData
   * @param name  The name of this class or interface
   * @param modifiersAndVisibility  The modifiersAndVisibility of this class or interface
   * @param typeParameters  Generic type info, not used
   * @param superClass  The super class of this class
   * @param interfaces  The super interfaces
   * @param outerData  The enclosing data of this class, or null
   */
  public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters,
                    SymbolData superClass, LinkedList<SymbolData> interfaces, Data outerData, String pakage) {
    this(name, modifiersAndVisibility, typeParameters, superClass, interfaces, outerData);
    _package = pakage;
  }
  
  /**
   * This constructor is only called by Interfaces.  Thus, there is never a super class, and _isInterface
   * is set to true.
   * @param name  The name of this class or interface
   * @param modifiersAndVisibility  The modifiersAndVisibility of this class or interface
   * @param typeParameters  Generic type info, not used
   * @param interfaces  The super interfaces
   * @param outerData  The enclosing data of this class, or null
   */
  public SymbolData(String name, ModifiersAndVisibility modifiersAndVisibility, TypeParameter[] typeParameters,
                    LinkedList<SymbolData> interfaces, Data outerData) {
    this(name, modifiersAndVisibility, typeParameters, null, interfaces, outerData);
    _isInterface = true;
  }

  /**Called to create a continuation when all you know is the name*/
  public SymbolData(String name) {
    super(null);
    _name = name;
    _modifiersAndVisibility = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[0]);
    _typeParameters = new TypeParameter[0];
    _methods = new LinkedList<MethodData>();
    _superClass = null;
    _interfaces = new LinkedList<SymbolData>();
    _innerClasses = new LinkedList<SymbolData>();
    _innerInterfaces = new LinkedList<SymbolData>();
    _isContinuation = true;
    _isInterface = false;
    _package = "";
    _instanceData = new InstanceData(this);

    
  }
  
  
  /**
   * No reference type is a Primitive type.
   */
  public boolean isPrimitiveType() {
    return false;
  }
  
  
  /**
   * See if this can be assigned to assignTo.
   * An assignment is legal:
   *   1. if this is a class type
   *      - if assignTo is a class type, then the types must be the same, or this must be a subclass of assignTo
   *      - if assignTo is an interface, then we must implement it.
   *      - if assignTo is an array, then it is not assignable.
   *  2. if this is an interface
   *      - if assignTo is a class, assignTo must be java.lang.Object.
   *      - if assignTo is an interface, then the types must be the same, or this must be a subinterface of assignTo.
   *      - if assignTo is an array, then it is not assignable
   * All of these rules are followed in isSubclassOf(), which traverses the hierarchy.
   */
   public boolean isAssignableTo(SymbolData assignTo, JavaVersion version) {
     if (assignTo != null) {
       if (assignTo.isPrimitiveType() && LanguageLevelConverter.versionSupportsAutoboxing(version)) { //You never box the left, so see if this can be unboxed to be a primitive.
         SymbolData unboxedType = this.unbox();
         if (unboxedType == null) {return false;}
         else {return unboxedType.isAssignableTo(assignTo, version);}
       }
       
       else {
         return this.isSubClassOf(assignTo);
       }
      
     }
     return false;
   }
  
   /**
    * If this SymbolData is a wrapper class for a primitive, return the primitive type.  Else return null.
    * @return the Primitive this SymbolData wraps, if there is one.  Otherwise return null.
    */
   private SymbolData unbox() {
     String name = getName();
     if (name.equals("java.lang.Integer")) {return SymbolData.INT_TYPE;}
     if (name.equals("java.lang.Character")) {return SymbolData.CHAR_TYPE;}
     if (name.equals("java.lang.Short")) {return SymbolData.SHORT_TYPE;}
     if (name.equals("java.lang.Byte")) {return SymbolData.BYTE_TYPE;}
     if (name.equals("java.lang.Float")) {return SymbolData.FLOAT_TYPE;}
     if (name.equals("java.lang.Double")) {return SymbolData.DOUBLE_TYPE;}
     if (name.equals("java.lang.Long")) {return SymbolData.LONG_TYPE;}
     if (name.equals("java.lang.Boolean")) {return SymbolData.BOOLEAN_TYPE;}
     return null;
   }
         
     
        
       

  /**
   * See if this can be cast as a castTo.
   * A cast is legal if:
   *   1. if both sides are the same type
   *   2. Both are primitives and
   *      - a widening primitive coversion is possible OR
   *      - a narrowing primitive conversion is possible
   *   3. this is a class type and
   *      - castTo is a class type and one is the super class of the other
   *      - castTo is an interface type and this is not final OR this implements castTo
   *      - castTo is an array type, and this is Object
   *   4. this is an interface type and
   *      - castTo is a class type and is not final OR this implements this
   *      - castTo is an interface type and this and castTo do not contain one or more methods with the same signature but different return types
   *      - castTo is an array type and this is either Serializable or Cloneable.
   * @param castTo  The TypeData we are trying to cast to.  (castTo) this
   * @return true  If the cast is legal, false otherwise.
   */
   public boolean isCastableTo(SymbolData castTo, JavaVersion version) {
     if (castTo != null) {
       if (castTo.isPrimitiveType()) { 
         if (LanguageLevelConverter.versionSupportsAutoboxing(version)) { //You never box the left, so see if this can be unboxed to be a primitive.
           SymbolData unboxedType = this.unbox();
           if (unboxedType == null) {return false;}
           else {return unboxedType.isCastableTo(castTo, version);}
         }
         else {return false;} //without autoboxing, cannot cast an object to a primitive
       }
       
       else if (!this.isInterface()) { //we're a class
         if (!castTo.isInterface()) {//castTo is a class or array
           return this.isSubClassOf(castTo) || castTo.isSubClassOf(this);
         }
         
         else { //castTo is an interface
           return (!castTo.hasModifier("final") || castTo.isSubClassOf(this));
         }
         
       }
       
       else { //this is an interface
         
         if (!castTo.isInterface()) {//castTo is a class or array
           return !castTo.hasModifier("final") || castTo.isSubClassOf(this);
         }
         
         else { //castTo is an interface
           //return false if this and castTo contain one or more methods with the same signature but different return types.
           if (LanguageLevelConverter.versionSupportsAutoboxing(version)) {return true;} //this check is no longer done in 1.5
           for (MethodData md: this.getMethods()) {
             if (checkDifferentReturnTypes(md, castTo, false, version)) {
               //TypeChecker._addError("Types " + this.getName() + " and " + castTo.getName() + " are incompatible.  Both implement " + md.getName() + " but have different return types", md.getSourceInfo());
               return false;
             }
           }
           return true;
         }
       }
     }
     return false;
   }

  
    /**
   * Depth-first traversal of the tree of enclosing data 
   * checking to see if sd is above this SymbolData 
   * in the class hierarchy.
   */
  public boolean isSubClassOf(SymbolData superClass) {
    if (this == superClass) {
      return true;
    }
    if (superClass.isInterface()) {
      Iterator<SymbolData> iter = _interfaces.iterator();
      while (iter.hasNext()) {
        SymbolData d = iter.next();
        if (d == null) {
          continue;
        }
        if (d == superClass) {
          return true;
        }
        if (d.isSubClassOf(superClass)) {
          return true;
        }
      }
    }

    if (_superClass != null) {
      return this._superClass.isSubClassOf(superClass);
    }
    return false;
  }
  
  /**
   * Check to see if this SymbolData is an inner class of outerClass (that is, that outerClass appears
   * somewhere in its enclosing data chain.  If stopAtStatic flag is true, stop as soon as we see a static class
   * in the chain.  This is because we are trying to resolve something, such as a "this" call, that cannot be seen outside
   * of a static inner class.
   * @param outerClass  The SymbolData we believe might be our outer class.
   * @param stopAtStatic  boolean flag, true if we want to stop at a static outer class.
   * @return  true if we are its inner class, false otherwise.
   */
  public boolean isInnerClassOf(SymbolData outerClass, boolean stopAtStatic) {
    if (this == outerClass) {return true;}
    Data outerData = this.getOuterData();
    if (outerData == null) {return false;}
    if (stopAtStatic && this.hasModifier("static")) {return false;}
    return outerData.getSymbolData().isInnerClassOf(outerClass, stopAtStatic);
  }
  
  /**@return false, since this is a SymbolData and not an InstanceData*/
  public boolean isInstanceType() {
    return false;
  }
 
 
 /**@return this SymbolData.*/
  public SymbolData getSymbolData() {
    return this;
  }
  
  /**@return the InstanceData corresponding to this class.*/
  public InstanceData getInstanceData() { 
    return _instanceData;
  }

  /**set the InstanceData for this class to the specified value*/
  public void setInstanceData(InstanceData id) {
    _instanceData = id;
  }
  
  
  /**@return the package*/
  public String getPackage() {
    return _package;
  }
  
  /**Set the package to the specified value*/
  public void setPackage(String pakage) {
    _package = pakage;
  }
  
  /**@return the generic type parameters*/
  public TypeParameter[] getTypeParameters() {
    return _typeParameters;
  }
  
  /**Set the generic type parameters to the specified value*/
  public void setTypeParameters(TypeParameter[] typeParameters) {
    _typeParameters = typeParameters;
  }
  
  /**@return true if this is an interface*/
  public boolean isInterface() {
    return _isInterface;
  }
  
  public void setInterface(boolean ii) {
    _isInterface = ii;
  }
  
  /**@return the list of inner interfaces*/
  public LinkedList<SymbolData> getInnerInterfaces() {
    return _innerInterfaces;
  }
  
  
  
  /**
   * Takes in a name and tries to match it with one of this Data's inner classes or
   * inner interfaces.  The input string 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 by '.' or '$'.
   * Checks the super class and interfaces of this SymbolData to see if the inner class or interface can be found there.
   * If no matching visibile inner classes or interfaces are found, but one or more that are not visible are found, one of the non-visibile ones will be returned.
   * @return  The SymbolData for the matching inner class or interface or null if there isn't one or SymbolData.AMBIGUOUS_REFERENCE if the reference is ambiguous.
   */
  protected SymbolData getInnerClassOrInterfaceHelper(String nameToMatch, int firstIndexOfDot) {
    Iterator<SymbolData> iter = innerClassesAndInterfacesIterator();
    while (iter.hasNext()) {
      SymbolData sd = iter.next();
      String sdName = sd.getName();

      sdName = LanguageLevelVisitor.getUnqualifiedClassName(sdName);
      if (firstIndexOfDot == -1) {
        if (sdName.equals(nameToMatch))
          return sd;
      }
      else {
        if (sdName.equals(nameToMatch.substring(0, firstIndexOfDot))) {
          return sd.getInnerClassOrInterface(nameToMatch.substring(firstIndexOfDot + 1));
        }
      }
    }
    
    SymbolData result = null;
    SymbolData newResult = null;
    SymbolData privateResult = null;
    
    //Next, look through the inner classes/interfaces of this class's super class
    //Check accessibility, because if you cannot see the super class's inner class, you can't use it.
    if (_superClass != null) {
      newResult = _superClass.getInnerClassOrInterfaceHelper(nameToMatch, firstIndexOfDot);
      if (newResult != null) {
        SymbolData outerPiece;
        if (firstIndexOfDot > 0) {
          outerPiece = _superClass.getInnerClassOrInterfaceHelper(nameToMatch.substring(0, firstIndexOfDot), -1);
        }
        else {
          outerPiece = newResult;
        }
        if (TypeChecker.checkAccessibility(outerPiece.getMav(), outerPiece, this)) {result = newResult;}
        else {privateResult = newResult;}
      }
    }
    
    //Next, look through the inner classes/interfaces of each of this class's interfaces
    //Check accessibility, because if you cannot see the super class's inner class, you can't use it.
    for (SymbolData id: _interfaces) {
      newResult = id.getInnerClassOrInterfaceHelper(nameToMatch, firstIndexOfDot);
      if (newResult != null) {
        SymbolData outerPiece;
        if (firstIndexOfDot > 0) {
          outerPiece = _superClass.getInnerClassOrInterfaceHelper(nameToMatch.substring(0, firstIndexOfDot), -1);
        }
        else { outerPiece = newResult; }        
        if (TypeChecker.checkAccessibility(outerPiece.getMav(), outerPiece, this)) {
          if (result == null) {result = newResult;}
          else {return SymbolData.AMBIGUOUS_REFERENCE;}
        }
        else {privateResult = newResult;}
      }
    }
    if (result != null) {return result;}
    return privateResult;  //this will be null if no matching inner classes/interfaces were found.  
  }
  

  /**Iterate over first the inner classes and then the inner interfaces.*/
  public Iterator<SymbolData> innerClassesAndInterfacesIterator() {
    return new Iterator<SymbolData>() {
      private Iterator<SymbolData> _first = _innerClasses.iterator();
      private Iterator<SymbolData> _second = _innerInterfaces.iterator();
      
      public boolean hasNext() {
        return _first.hasNext() || _second.hasNext();
      }
      
      public SymbolData next() {
        if (_first.hasNext())
          return _first.next();
        else
          return _second.next();
      }
      
      public void remove() {
        throw new UnsupportedOperationException();
      }
    };
    
  }
  
  
  /**Add the specified innerInterface to the list of innerInterfaces*/
  public void addInnerInterface(SymbolData innerInterface) {
    _innerInterfaces.addLast(innerInterface);
  }
  
  /**Increment the local class num and return it*/
  public int preincrementLocalClassNum() {
    return ++_localClassNum;
  }
  
  /**Set the anonymous inner class num to the specified value*/
  public void setAnonymousInnerClassNum(int i) {
    _anonymousInnerClassNum=i;
  }
  
  /**Increment the anonymous inner class num, and return it*/
  public int preincrementAnonymousInnerClassNum() {
    return ++_anonymousInnerClassNum;
  }
  
  /**@return the anonymous inner class num*/
  public int getAnonymousInnerClassNum() {
    return _anonymousInnerClassNum;
  }
  
  /**Return the local class num, and then decrement it*/
  public int postdecrementLocalClassNum() {
    return _localClassNum--;
  }
  
  /**Return the anonymous inner class num, and then decrement it*/
  public int postdecrementAnonymousInnerClassNum() {
    return _anonymousInnerClassNum--;
  }  
  
  /**
   * When you add a field to a SymbolData, it is given an initial value.
   */
  public boolean addVar(VariableData var) {
//    var.hasValue();
//    if var is not final, var.gotValue()
    return super.addVar(var);
  }
  
  /**
   * When you add fields to a SymboLData, they are given an initial value.
   */
  public boolean addVars(VariableData[] vars) {
   boolean success = true;
    for (int i = 0; i<vars.length; i++) {
      LinkedList<SymbolData> seen = new LinkedList<SymbolData>();
      if (!_repeatedNameInHierarchy(vars[i], seen)) {
        if (!vars[i].isFinal()) {
        vars[i].gotValue();
        }
        _vars.addLast(vars[i]);
      }
      else {
        success = false;
      }
    }
    return success;
 }

    /**
   * Add the array of variable datas to the list of variables defined in this scope, unless
   * a name has already been used.  Return true if all variables were added successfully, 
   * false otherwise.  Set each of the variable datas in the array to be final before
   * adding them.
   * 
   * Since this method is used to add fields at the Elementary and Intermediate levels,
   * and at these levels, we do not want the user to be able to shadow fields defined
   * in the superclass hierarchy, instead of using the normal repeatedName method,
   * check the repeated name throughout the hierarchy.
   * 
   * @param vars  The VariableData[] that we want to add.
   * @return  true if all VariableDatas were added successfully, false otherwise.
   */
  public boolean addFinalVars(VariableData[] vars) {
    boolean success = true;
    for (int i = 0; i<vars.length; i++) {
      LinkedList<SymbolData> seen = new LinkedList<SymbolData>();
      if (!_repeatedNameInHierarchy(vars[i], seen)) {
        vars[i].setFinal();
        _vars.addLast(vars[i]);
      }
      else {
        success = false;
      }
    }
    return success;
  }
  
  /**
   * Check to see if a variable with the same name as vr has already been
   * defined in the scope of this data or its super class.  If so, return true.  Otherwise, return false.
   * @param vr  The VariableData whose name we are searching for.
   * @return  true if that name has already been used in this scope, false otherwise.
   */
  private boolean _repeatedNameInHierarchy (VariableData vr, LinkedList<SymbolData> seen) {
    seen.addLast(this);
    Iterator<VariableData> iter = _vars.iterator();
    while (iter.hasNext()) {
      if (vr.getName().equals(iter.next().getName())) {
        return true;
      }
    }
    
    //Does this shadow something in the super class?
    if (_superClass != null && _superClass._repeatedNameInHierarchy(vr, seen)) {return true;}
    
    //Does this shadow something in the super interfaces?
    for (int i = 0; i<_interfaces.size(); i++) {
      if (_interfaces.get(i)._repeatedNameInHierarchy(vr, seen)) {return true;}
    }
    return false;
  }


  
  
  /**@return the list of methods defined in this symbol data*/
  public LinkedList<MethodData> getMethods() {
    return _methods;
  }
  
  /**
   * Returns true if there is a method with the given name in this SymbolData.
   * @param name  The name of the method to return
   * @return  true if a MethodData is found or false otherwise.
   */
  public boolean hasMethod(String name) {
    for (int i = 0; i < _methods.size(); i++) {
      MethodData currMd = _methods.get(i);
      if (currMd.getName().equals(name)) {
        return true;
      }
    }
    return false;
  }
  
  /**
   * Returns the method with the given name.
   * @param name  The name of the method to return
   * @param paramTypes  Array of the TypeDatas correpsonding to the parameters to the method.
   * @return  The MethodData or null if it is not found
   */
  public MethodData getMethod(String name, TypeData[] paramTypes) {
    for (int i = 0; i < _methods.size(); i++) {
      MethodData currMd = _methods.get(i);
      if (currMd.getName().equals(name)) {
        if (paramTypes.length == currMd.getParams().length) {
          boolean match = true;
          for (int j = 0; j<paramTypes.length; j++) {
            if (paramTypes[j].getSymbolData() != 
                currMd.getParams()[j].getType().getSymbolData()) {match = false; break;}
          }
          if (match) {return currMd; }
        }
      }
    }
    return null;
  }
  
  /**Set the list of methods to the specified one*/
  public void setMethods(LinkedList<MethodData> methods) {
    _methods = methods;
  }
  
  /**Call repeatedSignature with fromClassFile set to false by default.*/
  public static MethodData repeatedSignature(LinkedList<MethodData> listOfMethods, MethodData method) {
    return repeatedSignature(listOfMethods, method, false);
  }
  
  
  /**
   * Check if two methods in this SymbolData have the same name and parameters.
   * @param listOfMethods  The methods in this SymbolData
   * @param method  The MethodData for the method to be added
   * @param fromClassFile  Whether or not a class file is adding this method.
   *                       Important because bridge methods, which differ only in return type,
   *                       can be added from a class file and are legal but cannot exist in source code.
   * @return  The MethodData that was already in listOfMethods that method duplicates if there is one or null otherwise.
   */
  public static MethodData repeatedSignature(LinkedList<MethodData> listOfMethods, MethodData method, boolean fromClassFile) {
    Iterator<MethodData> iter = listOfMethods.iterator();
    VariableData[] methodParams = method.getParams();
    while (iter.hasNext()) {
      boolean match = true;
      MethodData currMd = iter.next();
      // Check that the names are the same and that if this is called from a class file that the return types are the same.
      if (currMd.getName().equals(method.getName()) && (!fromClassFile || currMd.getReturnType() == method.getReturnType())) {
        VariableData[] currMdParams = currMd.getParams();
        if (currMdParams.length == methodParams.length) {
          for (int i = 0; i < currMdParams.length; i++) {
            if (currMdParams[i].getType() != methodParams[i].getType()) {
              match = false;
              break;
            }
          }
          if (match) {
            return currMd;
          }
        }
      }
    }
    return null;
  }
  
  

  /**@return true if this is a primitive boolean or a Boolean with autoboxing enabled*/
  boolean isBooleanType(JavaVersion version) {
    return (this==BOOLEAN_TYPE) || (this.getName().equals("java.lang.Boolean") && LanguageLevelConverter.versionSupportsAutoboxing(version));//Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  

  /**@return true if this is a primitive char or a Character with autoboxing enabled*/
  boolean isCharType(JavaVersion version) {
    return (this==CHAR_TYPE) || (this.getName().equals("java.lang.Character") && LanguageLevelConverter.versionSupportsAutoboxing(version));//Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  
  
  /**@return true if this is a primitive byte or a Byte with autoboxing enabled*/
  boolean isByteType(JavaVersion version) {
    return (this==BYTE_TYPE) || (this.getName().equals("java.lang.Byte") && LanguageLevelConverter.versionSupportsAutoboxing(version));//&& Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  
  
  /**@return true if this is a primitive short or a Short with autoboxing enabled*/
  boolean isShortType(JavaVersion version) {
    return (this==SHORT_TYPE) || (this.getName().equals("java.lang.Short") && LanguageLevelConverter.versionSupportsAutoboxing(version));//&& Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  
  
  /**@return true if this is a primitive int or an Integer with autoboxing enabled*/
  boolean isIntType(JavaVersion version) {
    return (this==INT_TYPE) || (this.getName().equals("java.lang.Integer") && LanguageLevelConverter.versionSupportsAutoboxing(version));//Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  
  
  /**@return true if this is a primitive long or a Long with autoboxing enabled*/
  boolean isLongType(JavaVersion version) {
    return (this==LONG_TYPE) || (this.getName().equals("java.lang.Long") && LanguageLevelConverter.versionSupportsAutoboxing(version));//Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  
  
  /**@return true if this is a primitive char or a Character with autoboxing enabled*/
  boolean isFloatType(JavaVersion version) {
    return (this==FLOAT_TYPE) || (this.getName().equals("java.lang.Float") && LanguageLevelConverter.versionSupportsAutoboxing(version));//Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  
  
  /**@return true if this is a primitive double or a Double with autoboxing enabled*/
  boolean isDoubleType(JavaVersion version) {
    return (this==DOUBLE_TYPE) || (this.getName().equals("java.lang.Double") && LanguageLevelConverter.versionSupportsAutoboxing(version));//Double.valueOf(System.getProperty("java.specification.version")) >= 1.5);
  }
  
  
  
  /**Compare the ModifiersAndVisibility of the 2 method data to determine if overwriting can override the access priviledges of overwritten.  */
  public static boolean _isAssignable(MethodData overwritten, MethodData overwriting) {
    if (overwritten.hasModifier("public")) { //a public method can only be overwritten by a public method.
      return overwriting.hasModifier("public");
    }
    if (overwritten.hasModifier("protected")) { //a protected method can only be overwritten by a protected or public method
      return overwriting.hasModifier("protected") || overwriting.hasModifier("public");
    } 
    
    if (!overwritten.hasModifier("private")) { //only private methods can be overwritten by private methods
      return !overwriting.hasModifier("private");
    }
    return true;
      
    
  }
  
  
  
  /**Call checkDifferentReturnTypes with addError set to true by default*/
  protected static boolean checkDifferentReturnTypes(MethodData md, SymbolData sd, JavaVersion version) {
      return checkDifferentReturnTypes(md, sd, true, version);
    }
  
  /**
   * Called to make sure that no method has the same name and parameters as a method
   * it inherits while having different return types.
   * @param md  The MethodData we're currently trying to add
   * @param sd  The SymbolData of the class whose enclosingDatas we're examining for 
   *            different return types.
   * @param addError  true if errors should be added to the type checker
   * @return  Whether there exists a conflict
   */
  protected static boolean checkDifferentReturnTypes(MethodData md, SymbolData sd, boolean addError, JavaVersion version) {
    // We only want to check the super class and interfaces, not outer classes.
    LinkedList<SymbolData> interfaces = sd.getInterfaces();    
    LinkedList<SymbolData> enclosingData = new LinkedList<SymbolData>();
    enclosingData.addAll(interfaces);
    SymbolData superClass = sd.getSuperClass();
    if (superClass != null) {
      enclosingData.add(superClass);
    }
    Iterator<SymbolData> iter = enclosingData.iterator();
    while (iter.hasNext()) {
      SymbolData currSd = iter.next();
      MethodData matchingMd = repeatedSignature(currSd.getMethods(), md);
      if (matchingMd != null) {
        boolean subclass = md.getReturnType().isSubClassOf(matchingMd.getReturnType());
        if (matchingMd.getReturnType() != md.getReturnType() && !(subclass && LanguageLevelConverter.versionIs15(version))) {
          StringBuffer methodSignature = new StringBuffer(md.getName() + "(");
          VariableData[] params = md.getParams();
          for (int i = 0; i < params.length; i++) {
            if (i > 0) {
              methodSignature.append(", ");
            }
            methodSignature.append(params[i].getType().getName());
          }
          methodSignature.append(")");
          String methodSigString = methodSignature.toString();
          // This entire method is only called from the type checker, so add an error to its error list.
          if (addError) { TypeChecker.errors.addLast(new Pair<String, JExpressionIF>(methodSigString + " in " + sd.getName() + 
                             " cannot override " + methodSigString + " in " +
                             currSd.getName() + "; attempting to use different return types",
                                                                                   md.getJExpression())); }
          return true;
        }
        if (!_isAssignable(matchingMd, md)) {
          String access = "package";
          if (matchingMd.hasModifier("private")) {access = "private";}
          if (matchingMd.hasModifier("public")) {access = "public";}
          if (matchingMd.hasModifier("protected")) {access = "protected";}
          if (addError) {TypeChecker.errors.addLast(new Pair<String, JExpressionIF>(md.getName() + " in " + md.getSymbolData().getName() + " cannot override " + matchingMd.getName() + " in " + matchingMd.getSymbolData().getName() + ".  You are attempting to assign weaker access priviledges. In " + matchingMd.getSymbolData().getName() + ", "  + matchingMd.getName() + " was " + access, md.getJExpression()));} 
          return true;
        }
      }
      else {
        if (checkDifferentReturnTypes(md, currSd, version)) {
          return true;
        }
      }
    }
    return false;
  }
  
  /**
   * Check to see if methodName is used in this SymbolData's scope.  If so, find a 
   * new name for the method by appending a counter to its name until an unused method
   * name results.  Return the new name.
   * @param methodName  The initial String name of the variable we are creating.
   * @return  The new variable name which does not shadow anything in vars.
   */
  public String createUniqueMethodName(String methodName) {
    LinkedList<SymbolData> toCheck = new LinkedList<SymbolData>();
    toCheck.add(this);
    Set<String> names = new HashSet<String>();
    while(toCheck.size() > 0) {
      SymbolData sd = toCheck.removeFirst();
      LinkedList<MethodData> methods = sd.getMethods();
      for(MethodData md : methods) {
        names.add(md.getName());
      }
      if (sd.getSuperClass() != null) { toCheck.add(sd.getSuperClass()); }
      toCheck.addAll(sd.getInterfaces());
      if (sd.getOuterData() != null) { toCheck.add(sd.getOuterData().getSymbolData()); }
    }
        
    String newName = methodName;
    int counter = 0;  //note: it is possible that the counter could wrap around and this could run infinitely, but that is very unlikely.
    while (names.contains(newName) && counter != -1) {
      newName = methodName + counter; counter++;
    }
    
    if (counter == -1) {throw new RuntimeException("Internal Program Error: Unable to rename method " + methodName + ".  All possible names were taken.  Please report this bug.");}

    return newName; 
  }
  
  
  /**
   * Called to generate an error message when two methods are created with the same signature.
   */
  private String _createErrorMessage(MethodData md) {
    StringBuffer message = new StringBuffer("In the class \"" + md.getSymbolData().getName() + 
                                            "\", you cannot have two methods with the same name: \"" + md.getName() + "\"");
    VariableData[] params = md.getParams();
    if (params.length > 0) {
      message.append(" and parameter type");
      if (params.length > 1) {
        message.append("s");
      }
      message.append(":");
    }
    for (int i = 0; i < params.length; i++) {
      if (i > 0) {
        message.append(",");
      }
      message.append(" " + params[i].getType().getName());
    }
    return message.toString();
  }
  
  /**
   * When adding a method, we must check that the method's signature (name and parameters)
   * does not match that of any other method in the same class.  We also must check that
   * a method does not have the same signature but a different return type from a method 
   * in its superclass or one of its interfaces.
   */
  public void addMethod(MethodData method) {
    // Detect repeated methods
    if (repeatedSignature(_methods, method) != null) {
      LanguageLevelVisitor.errors.addLast(new Pair<String, JExpressionIF>(_createErrorMessage(method), 
                                                                        method.getJExpression()));
    }
    else {
        _methods.addLast(method);
    }
  }
  
  /**
   * This version of addMethod is called whenever the method corresponds to one that is auto-generated
   * (toString, equals, hashCode, etc.) and is necessary because we need to check if the user defined
   * a method with the same signature and, if so, highlight the user method instead of trying to highlight
   * the auto-generated method (which doesn't appear in the raw version of the source anyway).
   */
  public void addMethod(MethodData method, boolean isAugmentedCode) {
    // Detect if a method was user-defined that matches the signature of an auto-generated method.
    MethodData md = repeatedSignature(_methods, method);
    if (md != null) {
      LanguageLevelVisitor.errors.addLast(new Pair<String, JExpressionIF>("This method's signature conflicts with an automatically generated method's signature", 
                                                                        md.getJExpression()));
    }
    else {
        _methods.addLast(method);
    }
  }
  
  /**
   * Important to know if this is called from a class file since JSR14 allows methods to have the same
   * name and parameters with different return types for bridge methods.
   */
  public void addMethod(MethodData method, boolean isAugmentedCode, boolean fromClassFile) {
    // Detect if a method was user-defined that matches the signature of an auto-generated method.
    MethodData md = repeatedSignature(_methods, method, fromClassFile);
    if (md != null) {
      LanguageLevelVisitor.errors.addLast(new Pair<String, JExpressionIF>(_createErrorMessage(method), md.getJExpression()));
    }
    else {
      _methods.addLast(method);
    }
  }

  /**@return the superClass of this symbol data*/
  public SymbolData getSuperClass() {
    return _superClass;
  }
  
  /**Set the super class to the specified value*/
  public void setSuperClass(SymbolData superClass) {
    _superClass = superClass;
    addEnclosingData(superClass);
  }
  
  /**@return the interfaces of this symbol data*/
  public LinkedList<SymbolData> getInterfaces() {
    return _interfaces;
  }
  
  /**Add an interface to the list of interfaces*/
  public void addInterface(SymbolData interphace) {
    _interfaces.addLast(interphace);
    addEnclosingData(interphace);
  }
  
  /**Set the interfaces to be the specified list*/
  public void setInterfaces(LinkedList<SymbolData> interfaces) {
    _interfaces = interfaces;
    for (int i = 0; i<interfaces.size(); i++) {
      addEnclosingData(interfaces.get(i));
    }
  }
  

  /**Add one to the number of constructors for this symbol data*/
  public void incrementConstructorCount() {
    _constructorNumber ++;
  }
  
  /**Subtract one from the number of constructors for this symbol data*/
  public void decrementConstructorCount() {
    _constructorNumber --;
  }
  
  /**@return the number of constructors*/
  public int getConstructorCount() {
    return _constructorNumber;
  }
  
  /**@return true if this is a continuation*/
  public boolean isContinuation() {
    return _isContinuation;
  }
  
  /**Set the isContinuation flag to the specified value*/
  public void setIsContinuation(boolean isContinuation) {
    _isContinuation = isContinuation;
  }

  /**@return true if this Symbol Data is a primitive type that is a number type*/
  public boolean isNumberTypeWithoutAutoboxing() {
    return (this == SymbolData.INT_TYPE ||
        this == SymbolData.DOUBLE_TYPE ||
        this == SymbolData.LONG_TYPE ||
        this == SymbolData.CHAR_TYPE ||
        this == SymbolData.FLOAT_TYPE ||
        this == SymbolData.SHORT_TYPE ||
        this == SymbolData.BYTE_TYPE);
  }
  
  /**@return true if this Symbol Data is a primitive type that is a number type or is
   * a Object number type with autoboxing enabled.*/
  public boolean isNumberType(JavaVersion version) {
    if (!LanguageLevelConverter.versionSupportsAutoboxing(version)) {
      return isNumberTypeWithoutAutoboxing();
    }
    if (this.isDoubleType(version) ||
        this.isFloatType(version) ||
        this.isLongType(version) ||
        this.isIntType(version) ||        
        this.isCharType(version) ||
        this.isShortType(version) ||
        this.isByteType(version)) {
      return true;
    }
    return false;
  }


  /**@return true if this is a non float or boolean type, with autoboxing if it is allowed, or without autoboxing*/
  public boolean isNonFloatOrBooleanType(JavaVersion version) {
    if (!LanguageLevelConverter.versionSupportsAutoboxing(version)) {
      return isNonFloatOrBooleanTypeWithoutAutoboxing();
    }

    return (this.isIntType(version) ||
        this.isLongType(version) ||
        this.isCharType(version) ||
        this.isShortType(version) ||
        this.isByteType(version) ||
        this.isBooleanType(version));
  }

  /**@return true if this is a non float or boolean type, without autoboxing*/
  public boolean isNonFloatOrBooleanTypeWithoutAutoboxing() {
    return (this==SymbolData.INT_TYPE ||
        this==SymbolData.LONG_TYPE ||
        this==SymbolData.CHAR_TYPE ||
        this==SymbolData.SHORT_TYPE ||
        this==SymbolData.BYTE_TYPE ||
        this==SymbolData.BOOLEAN_TYPE);
    
  }
  
  
  /**
   * Returns true if the provided Object is equal to this symbol data.
   * SymbolDatas are equal if their fields are the same.
   * */
  public boolean equals(Object obj) {
    if (obj == null) return false;
    if ((obj.getClass() != this.getClass())) { //|| (obj.hashCode() != this.hashCode())) {
      return false;
    }
    SymbolData sd = (SymbolData) obj;    

    /*Return true if the fields are all .equals.*/
      
    return this.isContinuation() == sd.isContinuation() && 
      this.getMav().equals(sd.getMav()) &&
      LanguageLevelVisitor.arrayEquals(this.getTypeParameters(), sd.getTypeParameters()) &&
      this.getMethods().equals(sd.getMethods()) &&
      this.getSuperClass() == sd.getSuperClass() && //could be null
      this.getInterfaces().equals(sd.getInterfaces()) &&
      this.getOuterData() == sd.getOuterData() && //could be null
      this.getInnerClasses().equals(sd.getInnerClasses()) &&
      this.getName().equals(sd.getName()) &&
      this.getInnerInterfaces().equals(sd.getInnerInterfaces()) &&
      this.getPackage().equals(sd.getPackage()) &&
      this.isInterface() == sd.isInterface();
 

  }
  
  /**
   * Since SymbolDatas have unique names, in any given symboltable, hash on the name
   */
  public int hashCode() {
    return getName().hashCode();
  }
  
  
  /**
   * Check to see if this class is one of the 5 known classes that implement Runnable.
   *  Checking each class recursively to see if it extends Runnable is too time consuming, so we are hoping this short cut will work.
   * Clearly, this has some disadvantages.
   */
  public boolean implementsRunnable() {
   return this.getName().equals("java.lang.Thread") || this.getName().equals("java.util.TimerTask") || 
     this.getName().equals("javax.swing.text.AsyncBoxView$ChildState") || this.getName().equals("java.awt.image.renderable.RenderableImageProducer")
     || this.getName().equals("java.util.concurrent.FutureTask");// || this.getName().equals("java.lang.Runnable");
  }
  

  /**Check to see if the interface i appears anywhere in the hierarchy for this class/interface*/
  public boolean hasInterface(SymbolData i) {
    if (i==null) return false;

    if (getInterfaces().contains(i)) { return true; }
    
    if ((this.getSuperClass() != null) && this.getSuperClass().hasInterface(i)) { return true; }
    
    for (int j = 0; j<getInterfaces().size(); j++) {
      if (getInterfaces().get(j).hasInterface(i)) {return true;}
    }
    return false;
  }
  
  /**
   * Get all of your vars and all vars that you inherit.
   */
  public LinkedList<VariableData> getAllSuperVars() {
    LinkedList<VariableData> myVars = new LinkedList<VariableData>();
    if (this.getSuperClass() != null) {
      myVars.addAll(this.getSuperClass().getVars());
      myVars.addAll(this.getSuperClass().getAllSuperVars());
    }
    for (int i = 0; i<getInterfaces().size(); i++) {
      myVars.addAll(this.getInterfaces().get(i).getVars());
      myVars.addAll(this.getInterfaces().get(i).getAllSuperVars());
    }
    return myVars;
  }
  
  
   /**
    * Test the methods defined in the above class
    */
  public static class SymbolDataTest extends TestCase {
    
    private SymbolData _sd;
    
    private ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"public"});
    private ModifiersAndVisibility _protectedMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"protected"});
    private ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"private"});
    private ModifiersAndVisibility _packageMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[0]);
    private ModifiersAndVisibility _abstractMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"abstract"});
    private ModifiersAndVisibility _finalMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"final"});
    private ModifiersAndVisibility _publicFinalMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[]{"public", "final"});
    
    public SymbolDataTest() {
      this("");
    }
    public SymbolDataTest(String name) {
      super(name);
    }
    
    public void setUp() {
      _sd = new SymbolData("i.like.monkey");
      LanguageLevelVisitor.errors = new LinkedList<Pair<String, JExpressionIF>>();
    }
    
    public void testRepeatedSignatures() {
      MethodData md = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
                                     new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
        new VariableData(SymbolData.BOOLEAN_TYPE)}, 
                                     new String[0],
                                     _sd,
                                     null);
      md.getParams()[0].setEnclosingData(md);
      md.getParams()[1].setEnclosingData(md);
      LinkedList<MethodData> mds = new LinkedList<MethodData>();
      mds.addFirst(md);
      // Test same name, return type, and params from a source file.
      MethodData md2 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
        new VariableData(SymbolData.BOOLEAN_TYPE) }, 
                                      new String[0],
                                      _sd,
                                      null);
      md2.getParams()[0].setEnclosingData(md2);
      md2.getParams()[1].setEnclosingData(md2);
                                
      assertTrue("repeatedSignatures should return md exactly.", md == _sd.repeatedSignature(mds, md2));
      // Test same name, return type, and params from a class file.
      MethodData md3 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
        new VariableData(SymbolData.BOOLEAN_TYPE) }, 
                                      new String[0],
                                      _sd,
                                      null);
      md3.getParams()[0].setEnclosingData(md3);
      md3.getParams()[1].setEnclosingData(md3);
                                
      assertTrue("repeatedSignatures should return md exactly.", md == _sd.repeatedSignature(mds, md3, true));
      // Test same name, different return type, and params from a class file.
      MethodData md4 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE, 
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
        new VariableData(SymbolData.BOOLEAN_TYPE) }, 
                                      new String[0],
                                      _sd,
                                      null);      
      md4.getParams()[0].setEnclosingData(md4);
      md4.getParams()[1].setEnclosingData(md4);

                                      
      assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md4, true));
      // Test same name, return type, and different params from a source file.
      MethodData md5 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE, 
                                      new VariableData[] { new VariableData(SymbolData.BOOLEAN_TYPE) }, 
                                      new String[0],
                                      _sd,
                                      null);
      md5.getParams()[0].setEnclosingData(md5);
                                    
      assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md5));
      // Test same name, return type, and different order params from a source file.
      MethodData md6= new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.SHORT_TYPE, 
                                      new VariableData[] { new VariableData(SymbolData.BOOLEAN_TYPE),
        new VariableData(SymbolData.CHAR_TYPE) }, 
                                      new String[0],
                                      _sd,
                                      null);
      md6.getParams()[0].setEnclosingData(md6);
      md6.getParams()[1].setEnclosingData(md6);
                                      
      assertEquals("repeatedSignatures should return null.", null, _sd.repeatedSignature(mds, md6));
    }
    
    public void testCheckDifferentReturnTypes() {
      
      TypeChecker.errors = new LinkedList<Pair<String, JExpressionIF>>();
      
      // Create a super class and give it a method.
      SymbolData superSd = new SymbolData("superClass");
      MethodData md = new MethodData("methodName",
                                     _publicMav,
                                     new TypeParameter[0],
                                     SymbolData.INT_TYPE,
                                     new VariableData[0],
                                     new String[0],
                                     superSd,
                                     null);
      superSd.addMethod(md);
      _sd.setSuperClass(superSd);
      // Test with an exact copy of the method.
      MethodData md2 = new MethodData("methodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      SymbolData.INT_TYPE,
                                      new VariableData[0],
                                      new String[0],
                                      _sd,
                                      null);
      assertFalse("There should not be a conflict.", checkDifferentReturnTypes(md2, _sd, JavaVersion.JAVA_5));
      assertEquals("There should not be an error.", 0, TypeChecker.errors.size());
      // Test with an exact copy of the method except for differing return types.
      MethodData md3 = new MethodData("methodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      SymbolData.CHAR_TYPE,
                                      new VariableData[0],
                                      new String[0],
                                      _sd,
                                      null);
      assertTrue("There should be a conflict.", checkDifferentReturnTypes(md3, _sd, JavaVersion.JAVA_5));
      assertEquals("There should be one error.", 1, TypeChecker.errors.size());
      assertEquals("The error message should be correct.", 
                   "methodName() in i.like.monkey cannot override methodName() in superClass; attempting to use different return types",
                   TypeChecker.errors.get(0).getFirst());
      // Create a super super class and give it a method.
      SymbolData superSuperSd = new SymbolData("superSuperClass");
      MethodData md4 = new MethodData("superSuperMethodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      SymbolData.INT_TYPE,
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
                                      new String[0],
                                      superSuperSd,
                                      null);
      md4.getParams()[0].setEnclosingData(md4);
      superSuperSd.addMethod(md4);
      superSd.setSuperClass(superSuperSd);
      // Test with an exact copy except for differing parameters.
      MethodData md5 = new MethodData("superSuperMethodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      SymbolData.INT_TYPE,
                                      new VariableData[0],
                                      new String[0],
                                      null,
                                      null);
      assertFalse("There should not be a conflict.", checkDifferentReturnTypes(md5, _sd, JavaVersion.JAVA_5));
      assertEquals("There should still be one error.", 1, TypeChecker.errors.size());
      // Test with an exact copy except for diffeing return types.
      MethodData md6 = new MethodData("superSuperMethodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      SymbolData.BYTE_TYPE,
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
                                      new String[0],
                                      null,
                                      null);
      md6.getParams()[0].setEnclosingData(md6);
      assertTrue("There should be a conflict.", checkDifferentReturnTypes(md6, _sd, JavaVersion.JAVA_5));
      assertEquals("There should be two errors.", 2, TypeChecker.errors.size());
      
      //Test a method that restricts the mav of the super class's method
      MethodData md7 = new MethodData("superSuperMethodName",
                                      _privateMav,
                                      new TypeParameter[0],
                                      SymbolData.INT_TYPE,
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
                                      new String[0],
                                      new SymbolData("myData"),
                                      null);

      md7.getParams()[0].setEnclosingData(md7);
      assertTrue("There should be a conflict", checkDifferentReturnTypes(md7, _sd, JavaVersion.JAVA_5));
      assertEquals("There should be three errors", 3, TypeChecker.errors.size());
      assertEquals("The error message should be correct", "superSuperMethodName in myData cannot override superSuperMethodName in " + superSuperSd.getName() + ".  You are attempting to assign weaker access priviledges. In " + superSuperSd.getName() + ", superSuperMethodName was public", TypeChecker.errors.get(2).getFirst());
                                      
      
      //Test a method that narrows the return type of the super class's method
      SymbolData stringSd = new SymbolData("java.lang.String");
      stringSd.setIsContinuation(false);
      stringSd.setSuperClass(SymbolData.INT_TYPE);
      
      MethodData md8 = new MethodData("superSuperMethodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      stringSd,
                                      new VariableData[] {new VariableData(SymbolData.CHAR_TYPE)},
                                      new String[0],
                                      new SymbolData("myData"),
                                      null);
                                      
      assertFalse("There should be no conflict", checkDifferentReturnTypes(md8, _sd, JavaVersion.JAVA_5));
      assertEquals("There should still be 3 errors", 3, TypeChecker.errors.size());
      assertTrue("There should be a conflict in 1.4", checkDifferentReturnTypes(md8, _sd, JavaVersion.JAVA_1_4));
      assertEquals("There should now be 4 errors", 4, TypeChecker.errors.size());
      assertEquals("The error message should be correct", TypeChecker.errors.getLast().getFirst(), "superSuperMethodName(char) in superClass cannot override superSuperMethodName(char) in " + superSuperSd.getName() + "; attempting to use different return types");
    }
    
    public void test_createErrorMessage() {
      // Test with a method with no parameters.
      MethodData md = new MethodData("methodName",
                                     _publicMav,
                                     new TypeParameter[0],
                                     SymbolData.INT_TYPE,
                                     new VariableData[0],
                                     new String[0],
                                     _sd,
                                     null);
      assertEquals("The error message should be correct.", 
                   "In the class \"i.like.monkey\", you cannot have two methods with the same name: \"methodName\"", 
                   _sd._createErrorMessage(md));
      // Test with a method with one parameter.
      MethodData md2 = new MethodData("superSuperMethodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      SymbolData.INT_TYPE,
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE) },
                                      new String[0],
                                      _sd,
                                      null);
                                      assertEquals("The error message should be correct.", 
                                                   "In the class \"i.like.monkey\", you cannot have two methods with the same name: \"superSuperMethodName\" and parameter type: char", 
                                                   _sd._createErrorMessage(md2));
      md2.getParams()[0].setEnclosingData(md2);
      // Test with a method with two parameters.
      MethodData md3 = new MethodData("superSuperMethodName",
                                      _publicMav,
                                      new TypeParameter[0],
                                      SymbolData.INT_TYPE,
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
        new VariableData(SymbolData.CHAR_TYPE) },
                                      new String[0],
                                      _sd,
                                      null);
      md3.getParams()[0].setEnclosingData(md3);
      md3.getParams()[1].setEnclosingData(md3);
                                      
      assertEquals("The error message should be correct.", 
                   "In the class \"i.like.monkey\", you cannot have two methods with the same name: \"superSuperMethodName\" and parameter types: char, char", 
                   _sd._createErrorMessage(md3));
      
    }
    
    public void testAddMethod() {
      MethodData md = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
                                     new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
        new VariableData(SymbolData.BOOLEAN_TYPE)}, 
                                     new String[0],
                                     _sd,
                                     null);
                                     
      md.getParams()[0].setEnclosingData(md);
      md.getParams()[1].setEnclosingData(md);
                                     
      _sd.addMethod(md);
      assertEquals("There should be no errors.", 0, LanguageLevelVisitor.errors.size());
      // Test same name, return type, and params from a source file.
      MethodData md2 = new MethodData("methodName", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, 
                                      new VariableData[] { new VariableData(SymbolData.CHAR_TYPE),
        new VariableData(SymbolData.BOOLEAN_TYPE) }, 
                                      new String[0],
                                      _sd,
                                      null);
      md2.getParams()[0].setEnclosingData(md2);
      md2.getParams()[1].setEnclosingData(md2);
                                      
      _sd.addMethod(md2);
      assertEquals("There should be one error.", 1, LanguageLevelVisitor.errors.size());
      assertEquals("The error message should be correct.", "In the class \"" + _sd.getName() + 
                   "\", you cannot have two methods with the same name: \"" + md.getName() + "\" and parameter types: char, boolean",
                   LanguageLevelVisitor.errors.get(0).getFirst());
      MethodData md4 = new MethodData("methodName",
                                     _publicMav,
                                     new TypeParameter[0],
                                     SymbolData.INT_TYPE,
                                     new VariableData[0],
                                     new String[0],
                                     _sd,
                                     null);
      _sd.addMethod(md4);
      assertEquals("There should still be one error.", 1, LanguageLevelVisitor.errors.size());
      MethodData md5 = new MethodData("methodNamePlusStuff",
                                     _publicMav,
                                     new TypeParameter[0],
                                     SymbolData.INT_TYPE,
                                     new VariableData[0],
                                     new String[0],
                                     _sd,
                                     null);
      _sd.addMethod(md5);
      assertEquals("There should still be one error.", 1, LanguageLevelVisitor.errors.size());
      // Check that _sd only has two methods, the original md and md5.
      assertEquals("There are three methods in _sd.", 3, _sd.getMethods().size());
      assertEquals("The original method was added.", md, _sd.getMethods().get(0));
      assertEquals("md5 was added.", md5, _sd.getMethods().get(2));
      
      // Check that adding a method from augmented code produces the correct error message.
      _sd.addMethod(md2, true);
      assertEquals("There should be two errors.", 2, LanguageLevelVisitor.errors.size());
      assertEquals("The error message should be correct.",
                   "This method's signature conflicts with an automatically generated method's signature",
                   LanguageLevelVisitor.errors.get(1).getFirst());
    }
    
    public void testIsNumberType() {
      assertTrue(SymbolData.INT_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Integer").isNumberType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.DOUBLE_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Double").isNumberType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.LONG_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Long").isNumberType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.CHAR_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Character").isNumberType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.FLOAT_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Float").isNumberType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.SHORT_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Short").isNumberType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.BYTE_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Byte").isNumberType(JavaVersion.JAVA_5));     
      assertFalse(SymbolData.BOOLEAN_TYPE.isNumberType(JavaVersion.JAVA_5));
      assertFalse(new SymbolData("java.lang.Boolean").isNumberType(JavaVersion.JAVA_5));
    }

    public void testIsNumberTypeWithoutAutoboxing() {
      assertTrue(SymbolData.INT_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Integer")).isNumberTypeWithoutAutoboxing());
      assertTrue(SymbolData.DOUBLE_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Double")).isNumberTypeWithoutAutoboxing());
      assertTrue(SymbolData.LONG_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Long")).isNumberTypeWithoutAutoboxing());
      assertTrue(SymbolData.CHAR_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Character")).isNumberTypeWithoutAutoboxing());
      assertTrue(SymbolData.FLOAT_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Float")).isNumberTypeWithoutAutoboxing());
      assertTrue(SymbolData.SHORT_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Short")).isNumberTypeWithoutAutoboxing());
      assertTrue(SymbolData.BYTE_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Byte")).isNumberTypeWithoutAutoboxing());     
      assertFalse(SymbolData.BOOLEAN_TYPE.isNumberTypeWithoutAutoboxing());
      assertFalse((new SymbolData("java.lang.Boolean")).isNumberTypeWithoutAutoboxing());
    }

    
    public void testIsIntType() {
      assertTrue(SymbolData.INT_TYPE.isIntType(JavaVersion.JAVA_5));
      assertTrue((new SymbolData("java.lang.Integer")).isIntType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.DOUBLE_TYPE.isIntType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Double")).isIntType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.LONG_TYPE.isIntType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Long")).isIntType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.CHAR_TYPE.isIntType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Character")).isIntType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.FLOAT_TYPE.isIntType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Float")).isIntType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.SHORT_TYPE.isIntType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Short")).isIntType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BYTE_TYPE.isIntType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Byte")).isIntType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BOOLEAN_TYPE.isIntType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Boolean")).isIntType(JavaVersion.JAVA_5));
    }
    

    public void testIsDoubleType() {
      assertFalse(SymbolData.INT_TYPE.isDoubleType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Integer")).isDoubleType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.DOUBLE_TYPE.isDoubleType(JavaVersion.JAVA_5));
      assertTrue((new SymbolData("java.lang.Double")).isDoubleType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.CHAR_TYPE.isDoubleType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Character")).isDoubleType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.FLOAT_TYPE.isDoubleType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Float")).isDoubleType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.SHORT_TYPE.isDoubleType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Short")).isDoubleType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BYTE_TYPE.isDoubleType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Byte")).isDoubleType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BOOLEAN_TYPE.isDoubleType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Boolean")).isDoubleType(JavaVersion.JAVA_5));
    }
    
    public void testIsCharType() {
      assertFalse(SymbolData.INT_TYPE.isCharType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Integer")).isCharType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.DOUBLE_TYPE.isCharType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Double")).isCharType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.CHAR_TYPE.isCharType(JavaVersion.JAVA_5));
      assertTrue((new SymbolData("java.lang.Character")).isCharType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.FLOAT_TYPE.isCharType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Float")).isCharType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.SHORT_TYPE.isCharType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Short")).isCharType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BYTE_TYPE.isCharType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Byte")).isCharType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BOOLEAN_TYPE.isCharType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Boolean")).isCharType(JavaVersion.JAVA_5));
    }
    
    public void testIsFloatType() {
      assertFalse(SymbolData.INT_TYPE.isFloatType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Integer")).isFloatType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.DOUBLE_TYPE.isFloatType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Double")).isFloatType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.CHAR_TYPE.isFloatType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Character")).isFloatType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.FLOAT_TYPE.isFloatType(JavaVersion.JAVA_5));
      assertTrue((new SymbolData("java.lang.Float")).isFloatType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.SHORT_TYPE.isFloatType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Short")).isFloatType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BYTE_TYPE.isFloatType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Byte")).isFloatType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BOOLEAN_TYPE.isFloatType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Boolean")).isFloatType(JavaVersion.JAVA_5));
    }
    
    
    public void testIsByteType() {
      assertFalse(SymbolData.INT_TYPE.isByteType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Integer")).isByteType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.DOUBLE_TYPE.isByteType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Double")).isByteType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.CHAR_TYPE.isByteType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Character")).isByteType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.FLOAT_TYPE.isByteType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Float")).isByteType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.SHORT_TYPE.isByteType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Short")).isByteType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.BYTE_TYPE.isByteType(JavaVersion.JAVA_5));
      assertTrue((new SymbolData("java.lang.Byte")).isByteType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BOOLEAN_TYPE.isByteType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Boolean")).isByteType(JavaVersion.JAVA_5));
    }
    
    public void testIsBooleanType() {
      assertFalse(SymbolData.INT_TYPE.isBooleanType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Integer")).isBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.DOUBLE_TYPE.isBooleanType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Double")).isBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.CHAR_TYPE.isBooleanType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Character")).isBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.FLOAT_TYPE.isBooleanType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Float")).isBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.SHORT_TYPE.isBooleanType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Short")).isBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.BYTE_TYPE.isBooleanType(JavaVersion.JAVA_5));
      assertFalse((new SymbolData("java.lang.Byte")).isBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.BOOLEAN_TYPE.isBooleanType(JavaVersion.JAVA_5));
      assertTrue((new SymbolData("java.lang.Boolean")).isBooleanType(JavaVersion.JAVA_5));
    }
    
    public void testIsNonFloatOrBooleanType() {
      assertTrue(SymbolData.INT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Integer").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.DOUBLE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertFalse(new SymbolData("java.lang.Double").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.CHAR_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Character").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.FLOAT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertFalse(new SymbolData("java.lang.Float").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.SHORT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Short").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.BYTE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Byte").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.LONG_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Long").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.BOOLEAN_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(new SymbolData("java.lang.Boolean").isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      
    }
    
    public void testIsNonFloatOrBooleanTypeWithoutAutoboxing() {
      assertTrue(SymbolData.INT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.DOUBLE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.CHAR_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertFalse(SymbolData.FLOAT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.SHORT_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.BYTE_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.LONG_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
      assertTrue(SymbolData.BOOLEAN_TYPE.isNonFloatOrBooleanType(JavaVersion.JAVA_5));
    }
    
    
    public void testEquals() {
      SymbolData superSd = new SymbolData("superClass");
      _sd = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, new LinkedList<SymbolData>(), null);
      
      //check variables that are equal;
      SymbolData _sd2 = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, new LinkedList<SymbolData>(), null);
      assertTrue("Equals should return true if two SymbolDatas are equal", _sd.equals(_sd2));
      assertTrue("Equals should return true in opposite direction as well", _sd2.equals(_sd));

      //comparison to null
      assertFalse("Equals should return false if SymbolData is compared to null",_sd.equals(null));   
    
      //different names
      _sd2 = new SymbolData("q", _publicMav, new TypeParameter[0], superSd, new LinkedList<SymbolData>(), null);
      assertFalse("Equals should return false if class names are different", _sd.equals(_sd2));
      
      //different MAV
      _sd2 = new SymbolData("i.like.monkey", _protectedMav, new TypeParameter[0], superSd, new LinkedList<SymbolData>(), null);
      assertFalse("Equals should return false if class modifiers are different", _sd.equals(_sd2));
      
      //different type parameters
      _sd2 = new SymbolData("i.like.monkey", 
                            _publicMav, 
                            new TypeParameter[] { new TypeParameter(JExprParser.NO_SOURCE_INFO, new TypeVariable(JExprParser.NO_SOURCE_INFO,"tv"), 
                                                                    new TypeVariable(JExprParser.NO_SOURCE_INFO,"i")) }, 
                            superSd, 
                            new LinkedList<SymbolData>(), null);
      assertFalse("Equals should return false if class type parameters are different", _sd.equals(_sd2));
      
      //different super classes
      _sd2 = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], null, new LinkedList<SymbolData>(), null);
      assertFalse("Equals should return false if super classes are different", _sd.equals(_sd2));
      
      //different interfaces
      LinkedList<SymbolData> interfaces = new LinkedList<SymbolData>();
      interfaces.addLast(SymbolData.INT_TYPE);
      _sd2 = new SymbolData("i.like.monkey", _publicMav, new TypeParameter[0], superSd, interfaces, null);
      assertFalse("Equals should return false if the interfaces are different", _sd.equals(_sd2));
    }
     
    public void testImplementsRunnable() {
      SymbolData sd1 = new SymbolData("java.lang.Thread");
      SymbolData sd2 = new SymbolData("java.util.TimerTask");
      SymbolData sd3 = new SymbolData("javax.swing.text.AsyncBoxView$ChildState");
      SymbolData sd4 = new SymbolData("java.awt.image.renderable.RenderableImageProducer");
      SymbolData sd5 = new SymbolData("java.util.concurrent.FutureTask");
      SymbolData sd6 = new SymbolData("java.util.Vector");
      assertTrue("Should implement Runnable", sd1.implementsRunnable());
      assertTrue("Should implement Runnable", sd2.implementsRunnable());
      assertTrue("Should implement Runnable", sd3.implementsRunnable());
      assertTrue("Should implement Runnable", sd4.implementsRunnable());
      assertTrue("Should implement Runnable", sd5.implementsRunnable());
      assertFalse("Should not implement Runnable", sd6.implementsRunnable());
    }
  
    public void testHasInterface() {
      // Runnable has two subinterfacers, subRunnable and subRunnable2.  subRunnable has a subclass someSd and subRunnable2 has a subclass someOtherSd.
      
      SymbolData runnable = new SymbolData("java.lang.Runnable");
      runnable.setInterface(true);
      SymbolData subRunnable = new SymbolData("edgar");
      subRunnable.setInterface(true);
      subRunnable.addInterface(runnable);
      assertTrue(subRunnable.hasInterface(runnable));
      SymbolData subRunnable2 = new SymbolData("jones");
      subRunnable2.setInterface(true);
      subRunnable2.addInterface(runnable);
      assertTrue(subRunnable2.hasInterface(runnable));
      SymbolData someSd = new SymbolData("someSd");
      someSd.addInterface(subRunnable);      
      assertTrue(someSd.hasInterface(runnable));
      SymbolData someOtherSd = new SymbolData("someOtherSd");
      someOtherSd.addInterface(subRunnable2);
      assertTrue(someOtherSd.hasInterface(runnable));
      SymbolData notRunnable = new SymbolData("aksdf");
      assertFalse(notRunnable.hasInterface(runnable));
      someOtherSd.addInterface(notRunnable);
      assertTrue(someOtherSd.hasInterface(runnable));
      
      // Try myClass without setting a super class, then try it once it's super class is someSd.
      SymbolData myClass = new SymbolData("myClass");
      assertFalse(myClass.hasInterface(runnable));
      myClass.setSuperClass(someSd);
      assertTrue(myClass.hasInterface(runnable));
      SymbolData myClass2 = new SymbolData("myClass2");
      assertFalse(myClass2.hasInterface(runnable));
      myClass2.addInterface(someOtherSd);
      assertTrue(myClass2.hasInterface(runnable));
    }
    
    public void test_isAssignable() {
      MethodData md = new MethodData("Overwritten", _publicMav, new TypeParameter[0], _sd, new VariableData[0], new String[0], _sd, new NullLiteral(JExprParser.NO_SOURCE_INFO));
      MethodData md2 = new MethodData("Overwriting", _publicMav, new TypeParameter[0], _sd, new VariableData[0], new String[0], _sd, new NullLiteral(JExprParser.NO_SOURCE_INFO));

      //tests a wide variety of possibilities, but not all possibilities.
      assertTrue("Should be assignable", _isAssignable(md, md2));
      md.setMav(_protectedMav);
      assertTrue("Should be assignable", _isAssignable(md, md2));
      md.setMav(_privateMav);
      assertTrue("Should be assignable", _isAssignable(md, md2));
      md.setMav(_packageMav);
      assertTrue("Should be assignable", _isAssignable(md, md2));
      md2.setMav(_protectedMav);
      assertTrue("Should be assignable", _isAssignable(md, md2));
      md2.setMav(_privateMav);
      assertFalse("Should not be assignable", _isAssignable(md, md2));
      md2.setMav(_packageMav);
      assertTrue("Should be assignable", _isAssignable(md, md2));
      
    }
    
    
    public void testRepeatedNameInHierarchy() {
      SymbolData _d = new SymbolData("myname");
      
      VariableData vd = new VariableData("v1", _publicMav, SymbolData.INT_TYPE, false, _d);

      //compare a vd to an symbol data with no vars
      assertFalse("No variables to repeat name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
      
      //compare a vd to a symbol data with 1 var with a different name
      _d.addVar(new VariableData("v2", _protectedMav, SymbolData.BOOLEAN_TYPE, true, _d));
      assertFalse("No repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
      
      //compare a vd to a symbol data who has a var with the same name
      _d.addVar(vd);
      assertTrue("Should be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
      
      //what if super class has var
      _d.setVars(new LinkedList<VariableData>());
      SymbolData superC = new SymbolData("I am a super class");
      superC.addVar(new VariableData(vd.getName(), _protectedMav, SymbolData.DOUBLE_TYPE, false, superC));
      _d.setSuperClass(superC);
      assertTrue("Should be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
      
      //what if interface has var
      _d.setSuperClass(null);
      _d.addInterface(superC);
      assertTrue("Should also be repeated name", _d._repeatedNameInHierarchy(vd, new LinkedList<SymbolData>()));
    }
    
    public void testAddFinalVars() {
      SymbolData _d = new SymbolData("genius");
      VariableData vd = new VariableData("v1", _publicMav, SymbolData.INT_TYPE, true, _d);
      VariableData vd2 = new VariableData("v2", _publicMav, SymbolData.CHAR_TYPE, true, _d);
      VariableData[] toAdd = new VariableData[] {vd, vd2};
      LinkedList<VariableData> myVds = new LinkedList<VariableData>();
      
      //first adding array
      myVds.addLast(vd);
      myVds.addLast(vd2);
      assertTrue("Should be able to add new vars array", _d.addFinalVars(toAdd));
      assertEquals("Variable list should have 2 variables", myVds, _d.getVars());
      
      //trying to read array whose variables are already there.
      assertFalse("Should not be able to add same variables again", _d.addFinalVars(toAdd));
      assertEquals("Variable list should not have changed", myVds, _d.getVars());
      assertTrue("vd should now be final", _d.getVars().get(0).hasModifier("final"));
      assertTrue("vd2 should now be final", _d.getVars().get(1).hasModifier("final"));

      
      
      //trying to add a different array
      VariableData vd3 = new VariableData("v3", _publicFinalMav, SymbolData.INT_TYPE, true, _d);
      VariableData[] toAdd2 = new VariableData[] {vd3};
      myVds.addLast(vd3);
      
      assertTrue("Should be able to add new variable array", _d.addFinalVars(toAdd2));
      assertEquals("Variable list should now have 3 variables", myVds, _d.getVars());
      assertTrue("vd3 should now be final", _d.getVars().get(2).hasModifier("final"));

      
      //try adding an empty array of variable datas
      assertTrue("Should be able to add an empty array", _d.addFinalVars(new VariableData[0]));
      assertEquals("Variable list should not have changed by adding empty array", myVds, _d.getVars());
    }
    
    public void testGetAllVars() {
      SymbolData sd1 = new SymbolData("SubSub");
      SymbolData sd2 = new SymbolData("Sub");
      SymbolData sd3 = new SymbolData("Super");
      SymbolData sd4 = new SymbolData("SuperInterface");
      sd4.setInterface(true);
      SymbolData sd5 = new SymbolData("NotRelated");
      
      sd1.setSuperClass(sd2);
      sd2.setSuperClass(sd3);
      sd2.addInterface(sd4);

      VariableData vd1 = new VariableData("vd1", _finalMav, SymbolData.INT_TYPE, false, sd1);
      VariableData vd2 = new VariableData("vd2", _finalMav, SymbolData.INT_TYPE, false, sd2);
      VariableData vd3 = new VariableData("vd3", _finalMav, SymbolData.INT_TYPE, false, sd3);
      VariableData vd4 = new VariableData("vd4", _finalMav, SymbolData.INT_TYPE, false, sd4);
      VariableData vd5 = new VariableData("vd5", _finalMav, SymbolData.INT_TYPE, false, sd5);

      sd1.addVar(vd1);
      sd2.addVar(vd2);
      sd3.addVar(vd3);
      sd4.addVar(vd4);
      sd5.addVar(vd5);
      
      LinkedList<VariableData> shouldContain = new LinkedList<VariableData>();
      shouldContain.addLast(vd2);
      shouldContain.addLast(vd3);
      shouldContain.addLast(vd4);

      LinkedList<VariableData> vds = sd1.getAllSuperVars();
      assertEquals("the list should have 3 elements", 3, vds.size());
      assertEquals("The list should be correct", shouldContain, vds);
    }

    public void testIsSubclassOf() {
      _sd = new SymbolData("subClass");
      SymbolData superC = new SymbolData("superC");
      _sd._superClass = superC;
      
      //not subclass
      assertFalse("subClass, int, and boolean are not related", _sd.isSubClassOf(SymbolData.BOOLEAN_TYPE));
      
      //same class
      assertTrue("subClass is a subclass of itself", _sd.isSubClassOf(_sd));
      
      //direct subclass
      assertTrue("subClass is a subclass of its super class", _sd.isSubClassOf(superC));
      
      //subclass of subclass of provided data
      superC._superClass = SymbolData.CHAR_TYPE;
      assertTrue("subClass is a subclass of its super class's super class", _sd.isSubClassOf(SymbolData.CHAR_TYPE));
      
      //Interface
      SymbolData myData = new SymbolData("yes");
      SymbolData yourData = new SymbolData("interface");
      yourData.setInterface(true);
      myData.setIsContinuation(false);
      myData.addInterface(yourData);
      yourData.setIsContinuation(false);
      assertTrue("Should be assignable", myData.isSubClassOf(yourData));
    }
    
    
    public void testIsInnerClassOf() {
      _sd = new SymbolData("innerClass");
      SymbolData outer1 = new SymbolData("outer1");
      outer1.addInnerClass(_sd);
      _sd.setOuterData(outer1);
      SymbolData outer2 = new SymbolData("outer2");
      outer2.addInnerClass(outer1);
      outer1.setOuterData(outer2);
      outer2.setMav(new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"static"}));
      SymbolData outer3 = new SymbolData("outer3");
      outer3.addInnerClass(outer2);
      outer2.setOuterData(outer3);
      
      
      SymbolData notInChain = new SymbolData("no");
      
      assertTrue("_sd is an inner class of itself", _sd.isInnerClassOf(_sd, true));
      assertTrue("outer1 is the outer class of _sd", _sd.isInnerClassOf(outer1, true));
      assertTrue("outer2 is an outer class of _sd", _sd.isInnerClassOf(outer2, true));
      assertTrue("outer2 is an outer class of itself", outer2.isInnerClassOf(outer2, true));
      assertFalse("_sd is not related to notInChain", _sd.isInnerClassOf(notInChain, true));
      assertFalse("_sd is not an outer class of outer1", outer1.isInnerClassOf(_sd, true));
      assertFalse("outer3 cannot be seen from _sd if the static flag is true, because outer2 is static", _sd.isInnerClassOf(outer3, true));
      assertTrue("But, outer3 is an outer class of _sd", _sd.isInnerClassOf(outer3, false));
      
      
    }
    
      
      
    
    public void testCreateUniqueMethodName() {
      SymbolData george = new SymbolData("George");
      VariableData[] noVars = new VariableData[0];
      george.addMethod(new MethodData("getFriends", noVars));
      george.addMethod(new MethodData("sayHello", noVars));
      
      SymbolData iAteGeorge = new SymbolData("IAteGeorge");
      iAteGeorge.addMethod(new MethodData("sayHello", noVars));
      iAteGeorge.addMethod(new MethodData("sayHello0", noVars));
      iAteGeorge.addInnerClass(george);
      george.setOuterData(iAteGeorge);
      
      SymbolData mrsGeorge = new SymbolData("MrsGeorge");
      mrsGeorge.addMethod(new MethodData("sayHello1", noVars));
      george.setSuperClass(mrsGeorge);
      
      SymbolData grandmaGeorge = new SymbolData("GrandmaGeorge");
      grandmaGeorge.addMethod(new MethodData("sayHello2", noVars));
      grandmaGeorge.addMethod(new MethodData("sayHello5", noVars));
      george.addInterface(grandmaGeorge);
      
      SymbolData papaOfIAteGeorge = new SymbolData("PapaOfIAteGeorge");
      papaOfIAteGeorge.addMethod(new MethodData("sayHello3", noVars));
      iAteGeorge.setSuperClass(papaOfIAteGeorge);
      
      assertEquals("The generated name is correct when SymbolData has that method name",
                   "getFriends0", george.createUniqueMethodName("getFriends"));
      assertEquals("The generated name is correct when SymbolData doesn't have a method of that name",
                   "eatDinner", george.createUniqueMethodName("eatDinner"));
      assertEquals("The generated name is correct when a super class uses the name",
                   "sayHello10", george.createUniqueMethodName("sayHello1"));
      assertEquals("The generated name is correct when an outer class uses the name",
                   "sayHello00", george.createUniqueMethodName("sayHello0"));
      assertEquals("The generated name is correct when an interface uses the name",
                   "sayHello20", george.createUniqueMethodName("sayHello2"));
      assertEquals("The generated name is correct when a super class of an outer class uses the name",
                   "sayHello30", george.createUniqueMethodName("sayHello3"));
      assertEquals("The generated name is correct when a super class of an outer class uses the name",
                   "sayHello30", george.createUniqueMethodName("sayHello3"));
      assertEquals("The generated name is correct when a lot of things use the name",
                   "sayHello4", george.createUniqueMethodName("sayHello"));
      
    }
    
    
    
    
  }
      


}




See more files for this project here

DrJava

DrJava is a lightweight programming environment for Java designed to foster test-driven software development. It includes an intelligent program editor, an interactions pane for evaluating program text, a source level debugger, and a unit testing tool.

Project homepage: http://sourceforge.net/projects/drjava
Programming language(s): Java
License: other

  AdvancedLevelTest.java
  AdvancedVisitor.java
  ArrayData.java
  Augmentor.java
  BlockData.java
  Bob.java
  BodyBodyAdvancedVisitor.java
  BodyBodyElementaryVisitor.java
  BodyBodyIntermediateVisitor.java
  BodyData.java
  BodyTypeChecker.java
  CharConverter.java
  ClassBodyAdvancedVisitor.java
  ClassBodyElementaryVisitor.java
  ClassBodyIntermediateVisitor.java
  ClassBodyTypeChecker.java
  ConstructorBodyTypeChecker.java
  Data.java
  ElementaryLevelTest.java
  ElementaryVisitor.java
  ExpressionTypeChecker.java
  InstanceData.java
  InterfaceBodyAdvancedVisitor.java
  InterfaceBodyIntermediateVisitor.java
  InterfaceBodyTypeChecker.java
  IntermediateLevelTest.java
  IntermediateVisitor.java
  JExprParseException.java
  JExprParserTest.java
  JExpressionIFPrunableDepthFirstVisitor_void.java
  LValueTypeChecker.java
  LValueWithValueTypeChecker.java
  LanguageLevelConverter.java
  LanguageLevelVisitor.java
  MethodData.java
  PackageData.java
  Pair.java
  PrimitiveData.java
  SourceInfo.java
  SymbolData.java
  Symboltable.java
  TryCatchBodyTypeChecker.java
  TypeChecker.java
  TypeData.java
  VariableData.java
  VoidMethodsNotAllowedClassBodyTypeChecker.java
  jexpr.ast
  jexpr.jj