Code Search for Developers
 
 
  

Augmentor.java from DrJava at Krugle


Show Augmentor.java syntax highlighted

/*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*/

package edu.rice.cs.javalanglevels;

import edu.rice.cs.javalanglevels.parser.*;
import edu.rice.cs.javalanglevels.tree.*;
import java.io.*;
import java.util.*;
import junit.framework.TestCase;
import edu.rice.cs.plt.reflect.JavaVersion;

public class Augmentor extends JExpressionIFDepthFirstVisitor_void {
  
  private static final String newLine = System.getProperty("line.separator");
  private static final int indentWidth = 2; // TODO: get this from DrJava?

  /** The original source file to be augmented. */
  static private BufferedReader _fileIn;
  
  /** The current line number in _fileIn. */
  static private int _fileInLine;
  
  /** The current column number in _fileIn.  This is the 1 greater than the last column read. */
  static private int _fileInColumn;
  
  /** The destination file. */
  static private BufferedWriter _fileOut;
  
  /** The symbol information from this source tree. */
  static private LanguageLevelVisitor _llv;
  
  /** A string describing the target compiler.  Must include "1.5" to use 1.5 extensions in destination file. */
  static private JavaVersion _targetVersion;
  
  /** If true, generated toString, hashCode, & equals methods should correctly handle arrays & infinitely recursive structures */
  static private boolean _safeSupportCode;
  
  /** A String of variable definitions to be written at the end of the top-level class definitions */
  static private List<String> _endOfClassVarDefs;
  
  /** The Data enclosing whatever we are currently augmenting.*/
  private Data _enclosingData;
  
  /*
   * Main constructor for Augmentor: Used by the LanguageLevelConverter when converting language level files.
   * @param targetVersion  The String specifying what version the compiler is.
   * @param safeSupportCode  true if the user wants safe support code to be generated (this comes with a high overhead)
   * @param fileIn  A BufferedReader corresponding to the LanguageLevel file we should read from
   * @param fileOut  A BufferedWriter corresponding to the .java file we should write to.
   * @param llv  The LanguageLevelVisitor that was used to traverse the language level file.
   */
  public Augmentor(JavaVersion targetVersion, boolean safeSupportCode, BufferedReader fileIn, BufferedWriter fileOut, LanguageLevelVisitor llv) {
    _fileIn = fileIn;
    _fileInLine = 1;
    _fileInColumn = 1;
    _fileOut = fileOut;
    _llv = llv;
    _targetVersion = targetVersion;
    _safeSupportCode = safeSupportCode;
    _endOfClassVarDefs = new LinkedList<String>();
    
    _enclosingData = null;
  }
  
  /**
   * Create another Augmentor that shares the same static fields as the current Augmentor,
   * but has a new _enclosingData d.
   * This constructor should only be called from within another Augmentor.
   * @param d  The EnclosingData from which this Augmentor works.
   */
  protected Augmentor(Data d) { 
    _enclosingData = d;
  }
  
  
  
  /**
   * Do the augmenting appropriate for a Variable Declaration:  At the Elementary Level,
   * all class-level Variable Declarations should be augmented with "private final".  At
   * the IntermediateLevel, all Variable Declarations should be augmented with "final".
   * No augmentation is necessary at the Advanced level.
   * Always read up to the start of the VariableDeclaration before beginning augmentation.
   * @param that  The VariableDeclaration we are augmenting.
   */
  public void forVariableDeclaration(VariableDeclaration that) {
    _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
    String variableDeclarationModifiers = "";
    if (_isElementaryFile()) { variableDeclarationModifiers = "private final "; }
    else if (_isIntermediateFile()) { 
      //make static fields public final, make instance fields private final
      String[] mavs = that.getMav().getModifiers();
      variableDeclarationModifiers = "private final ";
      for (int i = 0; i<mavs.length; i++) {
        if (mavs[i].equals("static")) {variableDeclarationModifiers = "public final "; break;}
      }
    }
      
    _writeToFileOut(variableDeclarationModifiers);
    
    super.forVariableDeclaration(that);
  }
  
  /**
   * All formal parameters at the Elementary and Intermediate level (parameters to a method or in a catch clause) are augmented to be final.
   * Always read up to the start of the FormalParameter before beginning augmentation.
   * @param that  The FormalParameter we are augmenting.
   */
  public void forFormalParameter(FormalParameter that) {
    _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
    if (_isElementaryFile() || _isIntermediateFile()) {
      _writeToFileOut("final ");
    }
    // We don't bother to visit the declarator, since it does not need to be augmented.
  }
  

  
  /**
   * Do the augmentation necessary for a ConstructorDef.  Not allowed at the Elementary level, so don't worry
   * about that.  At the Intermediate Level, augment with public by default.
   * At all levels, the Formal Parameters to the MethodDef need to be visited so that
   * they can be augmented with final.   
   * Always read up to the start of the ConstructorDef before beginning augmentation.
   * @param that  The ConstructorDef we are augmenting.
   */
  public void forConstructorDef(ConstructorDef that) {
    _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
    
    if (_isIntermediateFile()) { //if this is an Intermediate level file, want to check and see if the constructor has modifiers.  If not,
                                 //make it public by default
      String[] modifiers = that.getMav().getModifiers();
      boolean hasVisibilityModifier = false;
      for (int i = 0; i<modifiers.length; i++) {
        if ((modifiers[i].equals("private")) || (modifiers[i].equals("public")) || (modifiers[i].equals("protected"))) {
          hasVisibilityModifier = true;
          break;
        }
      }
      
      if (!hasVisibilityModifier) {
        _writeToFileOut("public ");
      }
      
    }
    for (FormalParameter fp : that.getParameters()) { fp.visit(this); }
    // We don't bother visiting the rest of the method declaration
  }

  
  
  
  
  /**
   * Do the augmentation necessary for a MethodDef.  At the Elementary level, all methods are automatically
   * augmented to be "public".  At the IntermediateLevel, if the user did not specify a visibility level,
   * the method is automatically augmented to be "public".  Otherwise, the user's modifier is left unchanged.
   * At all levels, the Formal Parameters to the MethodDef need to be visited so that
   * they can be augmented with final.   
   * Always read up to the start of the MethodDef before beginning augmentation.
   * @param that  The MethodDef being visited.
   */
  public void forMethodDef(MethodDef that) {
    _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
    if (_isElementaryFile()) { 
      _writeToFileOut("public ");
    }
    
    if (_isIntermediateFile()) { //if this is an Intermediate level file, want to check and see if the method has modifiers.  If not,
                                 //make it public by default
      String[] modifiers = that.getMav().getModifiers();
      boolean hasVisibilityModifier = false;
      for (int i = 0; i<modifiers.length; i++) {
        if ((modifiers[i].equals("private")) || (modifiers[i].equals("public")) || (modifiers[i].equals("protected"))) {
          hasVisibilityModifier = true;
          break;
        }
      }
      
      if (!hasVisibilityModifier) {
        _writeToFileOut("public ");
      }
      
    }
    for (FormalParameter fp : that.getParams()) { fp.visit(this); }
    // We don't bother visiting the rest of the method declaration
  }
  
  
  /**
   * Delegate the augmentation of this AbstractMethodDef to forMethodDef.
   * @param that  The AbstractMethodDef being augmented.
   */
  public void forAbstractMethodDef(AbstractMethodDef that) {
    forMethodDef(that);
  }
  
  /**
   * Delegate the augmenetation of this method def's declaration to forMethodDef.  Then, visit the
   * body with a MethodBodyAugmentor so that each piece of the body can be correctly augmented.
   * @param that  The ConcreteMethodDef being augmented.
   */
  public void forConcreteMethodDef(ConcreteMethodDef that) {
    forMethodDef(that);
    MethodData md = _enclosingData.getSymbolData().getMethod(that.getName().getText(), formalParameters2TypeDatas(that.getParams(), _enclosingData));
    if (md == null) { throw new RuntimeException("Internal Program Error: Can't find method data for " + that.getName() + " Please report this bug."); }
    that.getBody().visit(new MethodBodyAugmentor(md));
  }
  
  /**
   * Class Defs can only appear at the top level of a source file.
   * If this ClassDef appears in an Elementary Level file and is specified to be public, then it needs to be augmented with public.
   * Visit the body of the class definition with a new Augmentor.
   * Then, (so that this appears after the rest of the class body) add any necessary augmented methods.
   * @param cd  The ClassDef we're augmenting.
   */
  public void forClassDef(ClassDef cd) {
    String className = cd.getName().getText();
    SymbolData sd = _llv.symbolTable.get(_llv.getQualifiedClassName(className));
    if (sd == null) { throw new RuntimeException("Internal Program Error: Can't find SymbolData for " + cd.getName().getText() + " Please report this bug."); }

    ModifiersAndVisibility m = cd.getMav();
    
    if (_isElementaryFile() && sd.hasModifier("public")) { //if this is an Elementary level file that we augmented with "public", then we need to
                                                           //augment the .java file with "public".  We should do this for all TestCase files.
      _readAndWriteThroughIndex(m.getSourceInfo().getStartLine(), m.getSourceInfo().getStartColumn() - 1);
      _writeToFileOut("public ");
    }

    BracedBody bb = cd.getBody();
    sd.setAnonymousInnerClassNum(0);
    bb.visit(new Augmentor(sd));
    
    int baseIndent = cd.getSourceInfo().getStartColumn() - 1;
    className = LanguageLevelVisitor.getUnqualifiedClassName(sd.getName());
    _readAndWriteThroughIndex(cd.getSourceInfo().getEndLine(), cd.getSourceInfo().getEndColumn() - 1);
    
    //Do all that crazy augmentation stuff.
    if (_isElementaryFile() || _isIntermediateFile()) {
      writeConstructor(className, sd, baseIndent);
      writeAccessors(sd, baseIndent);
      String valueToStringName = writeValueToString(sd, baseIndent);
      String valueEqualsName = writeValueEquals(sd, baseIndent);
      String valueHashCodeName = writeValueHashCode(sd, baseIndent, valueEqualsName);
      writeToString(sd, baseIndent, valueToStringName);
      writeEquals(className, sd, baseIndent, valueEqualsName);
      writeHashCode(className, sd, baseIndent, false, valueHashCodeName);
      for (String s : _endOfClassVarDefs) {
        _writeToFileOut(newLine + indentString(baseIndent, 1) + s);
      }
      if (_endOfClassVarDefs.size() > 0) {
      _writeToFileOut(newLine);
      _endOfClassVarDefs.clear();
      }
      _writeToFileOut(indentString(baseIndent, 0));

    }
    

    // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
  }

  /**
   * Look up this inner class in the enclosing data, and then visits its body.
   * InnerClassDefs can appear inside method or class or interface bodies.
   * No augmentation is done, because an InnerClass can only appear at the AdvancedLevel,
   * and we do not do augmentation at the Advanced Level.  If this were to change, we would need to
   * add the Augmentation back in.
   * @param cd  The InnerClassDef we are augmenting.
   */
  public void forInnerClassDef(InnerClassDef cd) {
    String className = cd.getName().getText();
    if (_enclosingData == null) {throw new RuntimeException("Internal Program Error: Enclosing Data is null.  Please report this bug.");}
    SymbolData sd = _enclosingData.getInnerClassOrInterface(className);
    if (sd == null) {
      throw new RuntimeException("Internal Program Error: Can't find SymbolData for " + cd.getName().getText() + ". Please report this bug.");
    }

    BracedBody bb = cd.getBody();
    sd.setAnonymousInnerClassNum(0);
    bb.visit(new Augmentor(sd));
    
//    int baseIndent = cd.getSourceInfo().getStartColumn() - 1;
//    className = LanguageLevelVisitor.getUnqualifiedClassName(sd.getName());
    _readAndWriteThroughIndex(cd.getSourceInfo().getEndLine(), cd.getSourceInfo().getEndColumn() - 1);
//    writeConstructor(className, sd, baseIndent);
//    writeAccessors(sd, baseIndent);
//    String valueToStringName = writeValueToString(sd, baseIndent);
//    String valueEqualsName = writeValueEquals(sd, baseIndent);
//    String valueHashCodeName = writeValueHashCode(sd, baseIndent, valueEqualsName);
//    writeToString(sd, baseIndent, valueToStringName);
//    writeEquals(className, sd, baseIndent, valueEqualsName);
//    writeHashCode(className, sd, baseIndent, true, valueHashCodeName);
//    _writeToFileOut(indentString(baseIndent, 0));

    // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
}

  
  /**
   * Look up this top level interface in the symbolTable, and then visit its body.
   * Write any necessary extra variable definitions at the end of the file.
   * InterfaceDefs can only appear at the top level of a source file.
   * @param cd  The InterfaceDef being augmented.
   */
  public void forInterfaceDef(InterfaceDef cd) {
    String interfaceName = cd.getName().getText();
    SymbolData sd = _llv.symbolTable.get(_llv.getQualifiedClassName(interfaceName));
    if (sd == null) { throw new RuntimeException("Internal Program Error: Can't find SymbolData for " + cd.getName().getText() + ".  Please report this bug."); }

    ModifiersAndVisibility m = cd.getMav();
    
    if (_isElementaryFile()) { 
      _readAndWriteThroughIndex(m.getSourceInfo().getStartLine(), m.getSourceInfo().getStartColumn() - 1);
      _writeToFileOut("public ");
    }

    BracedBody bb = cd.getBody();
    sd.setAnonymousInnerClassNum(0);
    bb.visit(new Augmentor(sd));
    
    int baseIndent = cd.getSourceInfo().getStartColumn() - 1;
    _readAndWriteThroughIndex(cd.getSourceInfo().getEndLine(), cd.getSourceInfo().getEndColumn() - 1);
    for (String s : _endOfClassVarDefs) {
      _writeToFileOut(newLine + indentString(baseIndent, 1) + s);
    }
    if (_endOfClassVarDefs.size() > 0) {
      _writeToFileOut(newLine);
      _endOfClassVarDefs.clear();
    }
    _writeToFileOut(indentString(baseIndent, 0));
    // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
  }

  /**
   * Look up this inner interface in the enclosing data, and then visit its body with a new Augmentor.
   * No code augmentation is done since InnerInterfaces can only appear at the Advanced Level, and
   * we are not doing code augmentation at the Advanced Level.  If we were to start doing code augmentation 
   * at the Advanced level, this might need to change.
   * InnerInterfaceDefs can appear inside method or class or interface bodies.
   */
  public void forInnerInterfaceDef(InnerInterfaceDef cd) {
    String interfaceName = cd.getName().getText();
    if (_enclosingData == null) {throw new RuntimeException("Internal Program Error: Enclosing Data is null.  Please report this bug.");}
    SymbolData sd = _enclosingData.getInnerClassOrInterface(interfaceName);
    if (sd == null) { throw new RuntimeException("Internal Program Error: Can't find SymbolData for " + cd.getName().getText() + ". Please report this bug."); }

    BracedBody bb = cd.getBody();
    sd.setAnonymousInnerClassNum(0);
    bb.visit(new Augmentor(sd));
    
    // We don't bother visiting any of the signature nodes -- parameters, type, name, etc.
  }
  
  
  /*
   * Look up this Anonymous Inner Class inside its enclosing data, and then visit its body.  Then, if it
   * is from an Elementary or Intermediate Level file, augment with the necessary automatically generated methods.
   * @param e  The AnonymousClassInstantiation we are augmenting.
   */
  public void forAnonymousClassInstantiation(AnonymousClassInstantiation e) {
    SymbolData sd = _enclosingData.getNextAnonymousInnerClass();

    if (sd == null) {
      throw new RuntimeException("Internal Program Error: Couldn't find the SymbolData for the anonymous inner class.  Please report this bug.");
    }
    BracedBody bb = e.getBody();
    sd.setAnonymousInnerClassNum(0);
    bb.visit(new Augmentor(sd));
    
    int baseIndent = e.getSourceInfo().getStartColumn() - 1;
    _readAndWriteThroughIndex(e.getSourceInfo().getEndLine(), e.getSourceInfo().getEndColumn() - 1);
    if (_isElementaryFile() || _isIntermediateFile()) {
      String className = Data.dollarSignsToDots(e.getType().getName());
      writeAccessors(sd, baseIndent);
      String valueToStringName = writeValueToString(sd, baseIndent);
      String valueEqualsName = writeValueEquals(sd, baseIndent);
      String valueHashCodeName = writeValueHashCode(sd, baseIndent, valueEqualsName);
      writeToString(sd, baseIndent, valueToStringName);
      if (!_safeSupportCode) { writeAnonEquals(baseIndent);}
      else {writeEquals(className, sd, baseIndent, valueEqualsName);}
      writeHashCode(className, sd, baseIndent, true, valueHashCodeName);
      _writeToFileOut(indentString(baseIndent, 0));

    }

  }
  
  /**Delegate to for AnonymousClassInstantiation(e).*/
  public void forSimpleAnonymousClassInstantiation(SimpleAnonymousClassInstantiation e) {
    forAnonymousClassInstantiation(e);
  }
  
  /**Visit the encosing part of this ComplexAnonymousClass name, and then delegate to forAnonymousClassInstantiation(e)*/
  public void forComplexAnonymousClassInstantiation(ComplexAnonymousClassInstantiation e) {
    e.getEnclosing().visit(this);
    forAnonymousClassInstantiation(e);
  }


 
  /**
   * Sort the Class and Interface defs based on the order they appear in the file.  Then visit each in turn.
   * Finally, write whatever remains in the file.  (If this is an ElementaryLevel file that needs to import
   * junit.framework.TestCase, make this the very first line of the augmented file.  This is okay, because at the
   * ElementaryLevel, there are no package statements we might get in trouble with.
   */
  public void forSourceFile(SourceFile sf) {
    TypeDefBase[] cds = sf.getTypes();
    
    // We intentionally neglect to visit the package and import statements
    
      
    //If importedPackages contains "junit.framework", then we had to import it while type checking this file.  Because we assumed
    //it was imported, the generated java file needs to import it as well.
    if (_isElementaryFile() && _llv._importedPackages.contains("junit.framework")) { // This assumes there are no package statements
      _writeToFileOut("import junit.framework.*;" + newLine);
    }

    //Visit each class and interface def in turn.
    for (TypeDefBase cd : cds) {
      cd.visit(this);
    }
 
    //Write out whatever is left in the file.
    _readAndWriteThroughIndex(sf.getSourceInfo().getEndLine(), sf.getSourceInfo().getEndColumn());
  }
  
  /**
   * Convert the provided FormalParameter array into an array of TypeData corresponding
   * to the types of the FormalParameters.
   */
  protected static TypeData[] formalParameters2TypeDatas(FormalParameter[] fp, Data enclosing) { 
    TypeData[] tds = new TypeData[fp.length];
    for (int j = 0; j<fp.length; j++) {
      SymbolData type = _llv.getSymbolData(fp[j].getDeclarator().getType().getName(), fp[j].getSourceInfo());
      
      if (type == null) {
        //see if this is a partially qualified field reference
        type = enclosing.getInnerClassOrInterface(fp[j].getDeclarator().getType().getName());
      }
      
      tds[j]= type;
    }
    return tds;
  }
  
  
  /**
   * Write a constructor for a previously generated (determined by MethodData.isGenerated())
   * constructor, if one exists.
   * 
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   */
  protected static void writeConstructor(String className, SymbolData sd, int baseIndent) {
    // Find the constructor.  There should be at most one that we generated, so select that one.
    MethodData constructor = null;
    for (MethodData currMd : sd.getMethods()) {
      if (currMd.getName().equals(LanguageLevelVisitor.getUnqualifiedClassName(sd.getName())) && currMd.isGenerated()) {
        constructor = currMd;
        break;
      }
    }
    if (constructor == null) { return; }
    
    
    // Write the method signature.
    VariableData[] constructorParams = constructor.getParams();
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "public " + className + "(");
    for (int q = 0; q < constructorParams.length; q++) {
      if (q>0) {
        _writeToFileOut(", ");
      }
      VariableData vd = constructorParams[q];
      _writeToFileOut(Data.dollarSignsToDots(vd.getType().getName()) + " " + vd.getName());
    }
    
    _writeToFileOut(") {" + newLine);
    

    // Generate lists of super params & local params
    LinkedList<VariableData> superParams = new LinkedList<VariableData>();
    LinkedList<VariableData> localParams = new LinkedList<VariableData>();
    LinkedList<VariableData> localFields = sd.getVars();
    
    for (VariableData param : constructorParams) {
      boolean hasLocalField = false;
      for (VariableData field : localFields) {
        hasLocalField = hasLocalField || field.getName().equals(param.getName());
        if (hasLocalField) { break; }
      }
      
      if (hasLocalField) { localParams.add(param); }
      else if (param.getName().startsWith("super_")) { superParams.add(param); }
      else { throw new RuntimeException("Internal Program Error: Unexpected parameter name in generated constructor: " + param.getName() +".  Please report this bug"); }
    }
    
    // Add the call to the super constructor here.
    _writeToFileOut(indentString(baseIndent, 2) + "super(");
    
    for (int z = 0; z < superParams.size(); z++) {
      if (z > 0) {
        _writeToFileOut(", ");
      }
      _writeToFileOut(superParams.get(z).getName());
    }
    _writeToFileOut(");" + newLine);
    
    // Instantiate local fields.
    for (int i = 0; i < localParams.size(); i++) {
      String varName = localParams.get(i).getName();
      _writeToFileOut(indentString(baseIndent, 2) + "this." + varName + " = " + varName + ";" + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);  
  }
  
  /**
   * Write an accessor method for each previously generated (determined by MethodData.isGenerated())
   * accessor.
   * 
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   */
  protected static void writeAccessors(SymbolData sd, int baseIndent) {
    // Find the accessor methods and generate them if we had to create them ourselves.
    LinkedList<MethodData> methods = sd.getMethods();
    MethodData accessor = null;
    Iterator<MethodData> iter = methods.iterator();
    VariableData[] vars = (VariableData[])sd.getVars().toArray(new VariableData[sd.getVars().size()]);
    for (int i = 0; i < vars.length; i++) {
      accessor = null;
      iter = methods.iterator();
      while (iter.hasNext()) {
        MethodData currMd = iter.next();
        if (currMd.getName().equals(vars[i].getName()) && currMd.isGenerated()) {
          accessor = currMd;
          break;
        }
      }
      if (accessor != null) {
        _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */" + newLine);
        _writeToFileOut(indentString(baseIndent, 1) + "public " + Data.dollarSignsToDots(vars[i].getType().getName()) + " " + LanguageLevelVisitor.getFieldAccessorName(vars[i].getName()) + "() {" + newLine);
        _writeToFileOut(indentString(baseIndent, 2) + "return " + vars[i].getName() + ";" + newLine + indentString(baseIndent, 1) + "}" + newLine);
      }
    }
  }
  
  /**
   * Write a toString method that prints out each field with a visible accessor.
   * 
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * @param valueToStringName  The name of the generated valueToString method
   */
  protected static void writeToString(SymbolData sd, int baseIndent, String valueToStringName) {
    LinkedList<MethodData> methods = sd.getMethods();
    MethodData toString = null;
    Iterator<MethodData> iter = methods.iterator();
    // Find the toString method and generate it if we had to create it ourselves.
    while (iter.hasNext()) {
      MethodData currMd = iter.next();
      if (currMd.getName().equals("toString") && currMd.isGenerated()) {
        toString = currMd;
        break;
      }
    }
    if (toString == null) { return; }
    
    LinkedList<MethodData> allMds = _getVariableAccessorListHelper(sd); //This builds up a list of all MethodData accessors for the VariableDatas of this class.
    MethodData[] mds = (MethodData[]) allMds.toArray(new MethodData[allMds.size()]);

    if (_safeSupportCode) { writeSafeToString(sd, baseIndent, valueToStringName, mds); }
    else { writeSimpleToString(sd, baseIndent, valueToStringName, mds); }
  }
    
  /** Helper to writeToString; writes a toString that handles infinitely-recursive data structures. */
  protected static void writeSafeToString(SymbolData sd, int baseIndent, String valueToStringName, MethodData[] accessors) {
    
    String flagName = sd.createUniqueName("__toStringFlag");
    VariableData toStringFlag = new VariableData(flagName, new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[]{ "private", "static" }),
                                 _llv.getSymbolDataHelper("java.util.LinkedList", JExprParser.NO_SOURCE_INFO, false, false, false, false),
                                 true, sd);
    toStringFlag.setGenerated(true);
    sd.addVar(toStringFlag);
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This field is automatically generated by the Language Level Converter. */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "private boolean " + flagName + " = false;" + newLine);
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "public java.lang.String toString() {" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "if (" + flagName + ") {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return getClass().getName() + \"(...)\";" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + flagName + " = true;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "String result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "try {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "result = getClass().getName() + \"(\" + " + newLine);
    for (int i = 0; i < accessors.length; i++) {
      if (LanguageLevelConverter.versionSupportsAutoboxing(_targetVersion) ||
            ! accessors[i].getReturnType().getSymbolData().isPrimitiveType()) {
        
        _writeToFileOut(indentString(baseIndent, 6) + valueToStringName + "(" + accessors[i].getName() + "()) + ");
      }
      else {
        _writeToFileOut(indentString(baseIndent, 6) + accessors[i].getName() + "() + ");
      }

      if (i < accessors.length - 1) {
        _writeToFileOut("\", \" + ");
      }
      _writeToFileOut(newLine);
    }
    _writeToFileOut(indentString(baseIndent, 6) + "\")\";" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "catch (RuntimeException e) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + flagName + " = false;" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "throw e;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + flagName + " = false;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /** Helper to writeToString; writes a short toString that does not handle infinitely-recursive data structures. */
  protected static void writeSimpleToString(SymbolData sd, int baseIndent, String valueToStringName, MethodData[] accessors) {
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "public java.lang.String toString() {" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "return getClass().getName() + \"(\" + " + newLine);
    for (int i = 0; i < accessors.length; i++) {
        _writeToFileOut(indentString(baseIndent, 4) + accessors[i].getName() + "() + ");

      if (i < accessors.length - 1) {
        _writeToFileOut("\", \" + ");
      }
      _writeToFileOut(newLine);
    }
    _writeToFileOut(indentString(baseIndent, 4) + "\")\";" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /**
   * Write an equals method that requires the Object parameter to be an instanceof this type
   * and have matching fields for each of the fields with visible accessors.
   * 
   * @param className  The unqualified name of this method's class or, in the case of anonymous inner classes, the
   *                   name of its superclass (or implemented interface).
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * @param valueEqualsName  The name of the generated valueEquals method
   */
  protected static void writeEquals(String className, SymbolData sd, int baseIndent, String valueEqualsName) {
    LinkedList<MethodData> methods = sd.getMethods();
    MethodData equals = null;
    Iterator<MethodData> iter = methods.iterator();

    // Find the equals method and generate it if we had to create it ourselves.
    while (iter.hasNext()) {
      MethodData currMd = iter.next();
      if (currMd.getName().equals("equals") && currMd.isGenerated()) {
        equals = currMd;
        break;
      }
    }
    if (equals == null) { return; }

    LinkedList<MethodData> allMds = _getVariableAccessorListHelper(sd);
    MethodData[] mds = (MethodData[]) allMds.toArray(new MethodData[allMds.size()]);

    if (_safeSupportCode) { writeSafeEquals(className, sd, baseIndent, valueEqualsName, mds); }
    else { writeSimpleEquals(className, sd, baseIndent, valueEqualsName, mds); }
  }
    
  /** Helper to writeEquals; writes an equals that handles infinitely-recursive data structures. */
  protected static void writeSafeEquals(String className, SymbolData sd, int baseIndent, String valueEqualsName, MethodData[] accessors) {
    
    String listName = sd.createUniqueName("__equalsList");
    
    VariableData equalsList = new VariableData(listName, new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[]{ "private", "static" }),
                                 _llv.getSymbolDataHelper("java.util.LinkedList", JExprParser.NO_SOURCE_INFO, false, false, false, false),
                                 true, sd);
    equalsList.setGenerated(true);
    sd.addVar(equalsList);
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This field is automatically generated by the Language Level Converter. */");
    if (LanguageLevelConverter.versionSupportsGenerics(_targetVersion))
      _writeToFileOut(newLine + indentString(baseIndent, 1) + "private java.util.LinkedList<" + className + "> " + listName + " = new java.util.LinkedList<" + className + ">();" + newLine);
    else
      _writeToFileOut(newLine + indentString(baseIndent, 1) + "private java.util.LinkedList " + listName + " = new java.util.LinkedList();" + newLine + newLine);

    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "public boolean equals(java.lang.Object o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "if (this == o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return true;" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else if ((o == null) || (! o.getClass().equals(getClass()))) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return false;" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "boolean alreadyTested = false;" + newLine);
    if (LanguageLevelConverter.versionSupportsForEach(_targetVersion)) {
      _writeToFileOut(indentString(baseIndent, 3) + "for (" + className + " element : " + listName + ")" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "alreadyTested = alreadyTested || (o == element);" + newLine + newLine);
    }
    else {
      if (LanguageLevelConverter.versionSupportsGenerics(_targetVersion)) {
        _writeToFileOut(indentString(baseIndent, 3) + "java.util.Iterator<" + className + "> i = " + listName + ".iterator();" + newLine);
      }
      else {
        _writeToFileOut(indentString(baseIndent, 3) + "java.util.Iterator i = " + listName + ".iterator();" + newLine);
      }
      _writeToFileOut(indentString(baseIndent, 3) + "while (!alreadyTested && i.hasNext())" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "alreadyTested = alreadyTested || (o == i.next());" + newLine + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 3) + "if (alreadyTested) { " + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "return true;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + className + " cast = ((" + className + ") o);" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + listName + ".addLast(cast);" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "boolean result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "try {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "result = ");
    int variablesCompared = 0;
    for (int i = 0; i < accessors.length; i++) {
      if (variablesCompared > 0) {
        _writeToFileOut(" && " + newLine + indentString(baseIndent, 7));
      }
      variablesCompared++;
      
      String varName = accessors[i].getName() + "()";
      
      if (LanguageLevelConverter.versionSupportsAutoboxing(_targetVersion) ||
            ! accessors[i].getReturnType().getSymbolData().isPrimitiveType()) {
        
        _writeToFileOut(valueEqualsName + "(" + varName + ", cast." + varName + ")");
      }
      else {
        _writeToFileOut("(" + varName + " == cast." + varName + ")");
      }
    }
  
    if (variablesCompared == 0)
      _writeToFileOut("true");
    
    _writeToFileOut(";" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "catch (RuntimeException e) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + listName + ".removeLast();" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "throw e;" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + listName + ".removeLast();" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "return result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /** Helper to writeEquals; writes a simple equals that does not handle infinitely-recursive data structures. */
  protected static void writeSimpleEquals(String className, SymbolData sd, int baseIndent, String valueEqualsName, MethodData[] accessors) {
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "public boolean equals(java.lang.Object o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "if (this == o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return true;" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else if ((o == null) || (! o.getClass().equals(getClass()))) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return false;" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + className + " cast = ((" + className + ") o);" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return ");
    int variablesCompared = 0;
    for (int i = 0; i < accessors.length; i++) {
      if (variablesCompared > 0) {
        _writeToFileOut(" && " + newLine + indentString(baseIndent, 5));
      }
      variablesCompared++;
      
      String varName = accessors[i].getName() + "()";
      
      if (! accessors[i].getReturnType().getSymbolData().isPrimitiveType()) {
        
        _writeToFileOut("(" + varName + " != null && " + varName + ".equals(cast." + varName + "))");
      }
      else {
        _writeToFileOut("(" + varName + " == cast." + varName + ")");
      }
    }
  
    if (variablesCompared == 0)
      _writeToFileOut("true");
    
    _writeToFileOut(";" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  

  /** 
   * AnonymousClasses are only equal if they are identical. 
   */
  protected static void writeAnonEquals(int baseIndent) {
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "public boolean equals(java.lang.Object o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "return (this == o);" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  
  /**
   * Write a hashCode method that is consistent with the generated equals(Object) method.
   * 
   * @param className  The unqualified name of this method's class or, in the case of anonymous inner classes, the
   *                   name of its superclass (or implemented interface).
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * @param waitForVarDef  True iff static variables cannot be defined in the current context and should be deferred
   *                       by adding them to _endOfClassVarDefs.
   * @param valueHashCodeName  The name of the generated valueHashCode method
   */
  protected static void writeHashCode(String className, SymbolData sd, int baseIndent, boolean waitForVarDef, String valueHashCodeName) {
    LinkedList<MethodData> methods = sd.getMethods();
    MethodData hashCode = null;
    Iterator<MethodData> iter = methods.iterator();

    // Find the hashCode method and generate it if we had to create it ourselves.
    while (iter.hasNext()) {
      MethodData currMd = iter.next();
      if (currMd.getName().equals("hashCode") && currMd.isGenerated()) {
        hashCode = currMd;
        break;
      }
    }
    if (hashCode == null) { return; }

    LinkedList<MethodData> allMds = _getVariableAccessorListHelper(sd);
    MethodData[] mds = (MethodData[]) allMds.toArray(new MethodData[allMds.size()]);
    
    if (_safeSupportCode) { writeSafeHashCode(className, sd, baseIndent, waitForVarDef, valueHashCodeName, mds); }
    else { writeSimpleHashCode(className, sd, baseIndent, waitForVarDef, valueHashCodeName, mds); }
  }
    
  /** Helper to writeHashCode; writes a hashCode that handles infinitely-recursive data structures.   
   * @param className  The unqualified name of this method's class or, in the case of anonymous inner classes, the
   *                   name of its superclass (or implemented interface).
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * @param waitForVarDef  True iff static variables cannot be defined in the current context and should be deferred
   *                       by adding them to _endOfClassVarDefs.
   * @param valueHashCodeName  The name of the generated valueHashCode method
   * @param accessors  An Array of the MethodDatas corresponding to the accessors for this class.
   */
  protected static void writeSafeHashCode(String className, SymbolData sd, int baseIndent, boolean waitForVarDef, 
                                          String valueHashCodeName, MethodData[] accessors) {
    
    String listName = "__hashCodeList";
    listName = sd.createUniqueName(listName);
    VariableData hashCodeList = new VariableData(listName, new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[]{ "private", "static" }),
                                 _llv.getSymbolDataHelper("java.util.LinkedList", JExprParser.NO_SOURCE_INFO, false, false, false, false),
                                 true, sd);
    hashCodeList.setGenerated(true);
    
    if (waitForVarDef) {
      SymbolData outermostData = sd;
      while (outermostData.getOuterData() != null) {
        outermostData = outermostData.getOuterData().getSymbolData();
      }
      outermostData.addVar(hashCodeList);
      _endOfClassVarDefs.add("/** This field is automatically generated by the Language Level Converter. */");
      if (LanguageLevelConverter.versionSupportsGenerics(_targetVersion)) {
        _endOfClassVarDefs.add("private static java.util.LinkedList<Object> " + listName + " = new java.util.LinkedList<Object>();");
      }
      else {
        _endOfClassVarDefs.add("private static java.util.LinkedList " + listName + " = new java.util.LinkedList();");
      }
      _endOfClassVarDefs.add("");
    }
    else {
      sd.addVar(hashCodeList);
      _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This field is automatically generated by the Language Level Converter. */");
      if (LanguageLevelConverter.versionSupportsGenerics(_targetVersion)) {
        _writeToFileOut(newLine + indentString(baseIndent, 1) + "private static java.util.LinkedList<" + className + "> " + listName + " = new java.util.LinkedList<" + className + ">();" + newLine);
      }
      else {
        _writeToFileOut(newLine + indentString(baseIndent, 1) + "private static java.util.LinkedList " + listName + " = new java.util.LinkedList();" + newLine);
      }
    }
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */");
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "public int hashCode() {" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "if (" + listName + ".contains(this)) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return -1;" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + listName + ".addLast(this);" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "int result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "try {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "result = getClass().hashCode()");
    for (int i = 0; i < accessors.length; i++) {
      _writeToFileOut(" ^ " + newLine + indentString(baseIndent, 6));
      SymbolData type = accessors[i].getReturnType().getSymbolData();
      
      if (LanguageLevelConverter.versionSupportsAutoboxing(_targetVersion) ||
          ! type.isPrimitiveType()) {
        
        _writeToFileOut(valueHashCodeName + "(" + accessors[i].getName() + "())");
      }
      else if (type == SymbolData.BOOLEAN_TYPE) {
        _writeToFileOut("(" + accessors[i].getName() + "() ? 1 : 0)");
      }
      else if (type.isAssignableTo(SymbolData.INT_TYPE, _targetVersion)) {
        _writeToFileOut(accessors[i].getName() + "()");
      }
      else {
        _writeToFileOut("(int) " + accessors[i].getName() + "()");           
      }
    }
    
    _writeToFileOut(";" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "catch (RuntimeException e) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + listName + ".removeLast();" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "throw e;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + listName + ".removeLast();" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "return result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /** Helper to writeHashCode; writes a simple hashCode that does not handle infinitely-recursive data structures. 
   * @param className  The unqualified name of this method's class or, in the case of anonymous inner classes, the
   *                   name of its superclass (or implemented interface).
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * @param waitForVarDef  True iff static variables cannot be defined in the current context and should be deferred
   *                       by adding them to _endOfClassVarDefs.
   * @param valueHashCodeName  The name of the generated valueHashCode method
   * @param accessors  An Array of the MethodDatas corresponding to the accessors for this class.
   */
  protected static void writeSimpleHashCode(String className, SymbolData sd, int baseIndent, boolean waitForVarDef, 
                                            String valueHashCodeName, MethodData[] accessors) {
    
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "/** This method is automatically generated by the Language Level Converter. */");
    _writeToFileOut(newLine + indentString(baseIndent, 1) + "public int hashCode() {" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "return getClass().hashCode()");
    for (int i = 0; i < accessors.length; i++) {
      _writeToFileOut(" ^ " + newLine + indentString(baseIndent, 4));
      SymbolData type = accessors[i].getReturnType().getSymbolData();
      
      if (! type.isPrimitiveType()) {
        _writeToFileOut("(" + accessors[i].getName() + "() == null ? 0 : " + accessors[i].getName() + "().hashCode())");
      }
      else if (type == SymbolData.BOOLEAN_TYPE) {
        _writeToFileOut("(" + accessors[i].getName() + "() ? 1 : 0)");
      }
      else if (type.isAssignableTo(SymbolData.INT_TYPE, _targetVersion)) {
        _writeToFileOut(accessors[i].getName() + "()");
      }
      else {
        _writeToFileOut("(int) " + accessors[i].getName() + "()");           
      }
    }
    
    _writeToFileOut(";" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /**
   * Write a method to generate a String for any Object, including arrays, nulls, and other reference types.
   * 
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * 
   * @return  The name of the generated valueToString method (__valueToString by default).
   */
  private static String writeValueToString(SymbolData sd, int baseIndent) {
    String methodName = sd.createUniqueMethodName("__valueToString");
    if (_safeSupportCode) { writeSafeValueToString(sd, baseIndent, methodName); }
    return methodName;
  }
  
  /** Helper to writeValueToString; writes a valueToString that correctly handles arbitrary arrays. 
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces to put at the beginning of every line).
   * @param methodName  The name of the generated valueToString method (__valueToString by default).
   */

  private static void writeSafeValueToString(SymbolData sd, int baseIndent, String methodName) {
    String[] primitiveTypes = new String[]{"byte[]", "short[]", "char[]", "int[]", "long[]", "float[]", "double[]", "boolean[]"};
    boolean useGenerics = LanguageLevelConverter.versionSupportsGenerics(_targetVersion);
    
    _writeToFileOut(newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * This method is automatically generated by the LanguageLevelConverter." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * As a helper to toString(), it recursively generates a string for any object," + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * including nulls, arrays, and standard reference types." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "private java.lang.String " + methodName + "(java.lang.Object o) {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "class ArrayToString {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "public String valueFor(java.lang.Object o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "if (o instanceof java.lang.Object[]) {" + newLine);

    if (useGenerics) {
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayToString((java.lang.Object[]) o, new java.util.HashSet<java.lang.Object[]>());" + newLine);
    }
    else {
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayToString((java.lang.Object[]) o, new java.util.HashSet());" + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    
    for (String type : primitiveTypes) {
      _writeToFileOut(indentString(baseIndent, 4) + "else if (o instanceof " + type + ") {" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayToString((" + type + ") o);" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    }
    
    _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "// o should be an array, but if not, toString() is called" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "return o.toString();" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    
    for (String type : primitiveTypes) {
      _writeToFileOut(indentString(baseIndent, 3) + "public java.lang.String arrayToString(" + type + " array) {" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "java.lang.StringBuffer result = new java.lang.StringBuffer();" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"[\");" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "if (array.length > 0) { result.append(array[0]); }" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 1; i < array.length; i++) {" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "result.append(\", \");" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "result.append(array[i]);" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"]\");" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "return result.toString();" + newLine);
      _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    }
    
    if (useGenerics) {
      _writeToFileOut(indentString(baseIndent, 3) + "public java.lang.String arrayToString(java.lang.Object[] array, java.util.HashSet<java.lang.Object[]> alreadyPrinted) {" + newLine);
    }
    else {
      _writeToFileOut(indentString(baseIndent, 3) + "public java.lang.String arrayToString(java.lang.Object[] array, java.util.HashSet alreadyPrinted) {" + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 4) + "if (alreadyPrinted.contains(array)) { return (\"[...]\"); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "else { alreadyPrinted.add(array); }" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "java.lang.StringBuffer result = new java.lang.StringBuffer();" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"[\");" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "boolean nonEmpty = false;" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 0; i < array.length; i++) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "if (nonEmpty) { result.append(\", \"); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "nonEmpty = true;" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "if (array[i] instanceof java.lang.Object[]) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "result.append(arrayToString((java.lang.Object[]) array[i], alreadyPrinted));" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "result.append(" + methodName + "(array[i]));" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "result.append(\"]\");" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "alreadyPrinted.remove(array);" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "return result.toString();" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine + newLine); // end of inner class
    _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return \"\" + null; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else if (o.getClass().isArray()) { return new ArrayToString().valueFor(o); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else { return o.toString(); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /** Helper to writeValueToString; writes a simple valueToString that does not handle arrays. 
   *  NOTE: This is currently unused.  For the simple case, no valueToString method is generated.
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   */
  private static void writeSimpleValueToString(SymbolData sd, int baseIndent, String methodName) {
    _writeToFileOut(newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * This method is automatically generated by the LanguageLevelConverter." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * As a helper to toString(), it generates a string for any object," + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * including nulls and standard reference types." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "private java.lang.String " + methodName + "(java.lang.Object o) {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return \"\" + null; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else { return o.toString(); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /**
   * Write a method to compare any two objects, including arrays, nulls, and other reference types.
   * 
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * 
   * @return  The name of the generated valueEquals method (__valueEquals by default).
   */
  private static String writeValueEquals(SymbolData sd, int baseIndent) {
    String methodName = sd.createUniqueMethodName("__valueEquals");
    if (_safeSupportCode) { writeSafeValueEquals(sd, baseIndent, methodName); }
//    else { writeSimpleValueEquals(sd, baseIndent, methodName); }
    return methodName;
  }
  
  /** Helper to writeValueEquals; writes a valueEquals that correctly handles arbitrary arrays. */
  private static void writeSafeValueEquals(SymbolData sd, int baseIndent, String methodName) {
    String[] primitiveTypes = new String[]{"byte[]", "short[]", "char[]", "int[]", "long[]", "float[]", "double[]", "boolean[]"};
    boolean useGenerics = LanguageLevelConverter.versionSupportsGenerics(_targetVersion);
    
    _writeToFileOut(newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * This method is automatically generated by the LanguageLevelConverter." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * As a helper to equals(Object), it recursively compares any two objects," + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * including nulls, arrays, and standard reference types." + newLine);
     _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "private boolean " + methodName + "(java.lang.Object o1, java.lang.Object o2) {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "class ArrayEquals {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "public boolean valueFor(java.lang.Object o1, java.lang.Object o2) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "if (o1 instanceof java.lang.Object[] && o2 instanceof java.lang.Object[]) {" + newLine);
    if (useGenerics) {
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayEquals((java.lang.Object[]) o1, (java.lang.Object[]) o2, new java.util.HashSet<java.lang.Object>());" + newLine);
    }
    else {
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayEquals((java.lang.Object[]) o1, (java.lang.Object[]) o2, new java.util.HashSet());" + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    
    for (String type : primitiveTypes) {
      _writeToFileOut(indentString(baseIndent, 4) + "else if (o1 instanceof " + type + " && o2 instanceof " + type + ") {" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayEquals((" + type + ") o1, (" + type + ") o2);" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    }
    
    _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "// o1 and o2 should be arrays, but if not, or if they have different types, equals(Object) is called" + newLine); 
    _writeToFileOut(indentString(baseIndent, 5) + "return o1.equals(o2);" + newLine); 
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    
    for (String type : primitiveTypes) {
      _writeToFileOut(indentString(baseIndent, 3) + "public boolean arrayEquals(" + type + " array1, " + type + " array2) {" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "if (array1.length != array2.length) { return false; }" + newLine + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "for (int i = 0; i < array1.length; i++) {" + newLine);
      _writeToFileOut(indentString(baseIndent, 6) + "if (array1[i] != array2[i]) { return false; }" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "return true;" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
      _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    }
    
    if (useGenerics) {
      _writeToFileOut(indentString(baseIndent, 3) + "public boolean arrayEquals(final java.lang.Object[] array1, final java.lang.Object[] array2, java.util.HashSet<java.lang.Object> alreadyCompared) {" + newLine + newLine);
    }
    else {
      _writeToFileOut(indentString(baseIndent, 3) + "public boolean arrayEquals(final java.lang.Object[] array1, final java.lang.Object[] array2, java.util.HashSet alreadyCompared) {" + newLine + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 4) + "class ArrayPair {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "public java.lang.Object[] array1() { return array1; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "public java.lang.Object[] array2() { return array2; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "public boolean equals(java.lang.Object o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "if ((o == null) || ! (o instanceof ArrayPair)) { return false; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "else { return (array1.equals(((ArrayPair) o).array1())) && (array2.equals(((ArrayPair) o).array2())); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "public int hashCode() { return array1.hashCode() ^ (array2.hashCode() << 1); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "if (array1.length != array2.length) { return false; }" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "ArrayPair currentPair = new ArrayPair();" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "if (alreadyCompared.contains(currentPair)) { return true; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "alreadyCompared.add(currentPair);" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "boolean result = true;" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "for (int i = 0; i < array1.length; i++) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "if (array1[i] instanceof java.lang.Object[] && array2[i] instanceof java.lang.Object[]) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 7) + "result = arrayEquals((java.lang.Object[]) array1[i], (java.lang.Object[]) array2[i], alreadyCompared);" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 7) + "result = " + methodName + "(array1[i], array2[i]);"+ newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "}" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "if (!result) { break; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "alreadyCompared.remove(currentPair);" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "return result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);

    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine + newLine); // end of inner class
    _writeToFileOut(indentString(baseIndent, 2) + "if (o1 == null) { return o2 == null; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else if (o2 == null) { return false; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else if (o1.getClass().isArray() && o2.getClass().isArray()) { return new ArrayEquals().valueFor(o1, o2); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else { return o1.equals(o2); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /** Helper to writeValueEquals; writes a simple valueEquals that does not handle arrays. 
   *  NOTE: This is currently unused.  For the simple case, no valueEquals method is generated.
   */
  private static void writeSimpleValueEquals(SymbolData sd, int baseIndent, String methodName) {
    _writeToFileOut(newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * This method is automatically generated by the LanguageLevelConverter." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * As a helper to equals(Object), it compares any two objects," + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * including nulls and standard reference types." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "private boolean " + methodName + "(java.lang.Object o1, java.lang.Object o2) {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "if (o1 == null) { return o2 == null; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else if (o2 == null) { return false; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else { return o1.equals(o2); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /**
   * Write a method to generate a hash code for any Object, including arrays, nulls, and other reference types.
   * 
   * @param sd  The method's enclosing class.
   * @param baseIndent  The base indent level (number of spaces).
   * @param valueEqualsName  The name of the method generated by writeValueEquals()
   * 
   * @return  The name of the generated valueHashCode method (__valueHashCode by default).
   */
  private static String writeValueHashCode(SymbolData sd, int baseIndent, String valueEqualsName) {
    String methodName = sd.createUniqueMethodName("__valueHashCode");
    if (_safeSupportCode) { writeSafeValueHashCode(sd, baseIndent, valueEqualsName, methodName); }
//    else { writeSimpleValueHashCode(sd, baseIndent, valueEqualsName, methodName); }
    return methodName;
  }
  
  /** Helper to writeValueHashCode; writes a valueHashCode that correctly handles arbitrary arrays. */
  private static void writeSafeValueHashCode(SymbolData sd, int baseIndent, String valueEqualsName, String methodName) {
    String[] primitiveTypes = new String[]{"byte[]", "short[]", "char[]", "int[]", "long[]", "float[]", "double[]", "boolean[]"};
    boolean useGenerics = LanguageLevelConverter.versionSupportsGenerics(_targetVersion);
    
    _writeToFileOut(newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * This method is automatically generated by the LanguageLevelConverter." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * As a helper to hashCode(), it recursively generates a hash code for any object," + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * including nulls, arrays, and standard reference types." + newLine);
     _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "private int " + methodName + "(java.lang.Object o) {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "class ArrayHashCode {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "public int valueFor(java.lang.Object o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "if (o instanceof java.lang.Object[]) {" + newLine);
    if (useGenerics) {
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayHashCode((java.lang.Object[]) o, new java.util.LinkedList<java.lang.Object>());" + newLine);
    }
    else {
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayHashCode((java.lang.Object[]) o, new java.util.LinkedList());" + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    
    for (String type : primitiveTypes) {
      _writeToFileOut(indentString(baseIndent, 4) + "else if (o instanceof " + type + ") {" + newLine);
      _writeToFileOut(indentString(baseIndent, 5) + "return arrayHashCode((" + type + ") o);" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    }
    
    _writeToFileOut(indentString(baseIndent, 4) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "// o should be an array, but if not, hashCode() is called" + newLine); 
    _writeToFileOut(indentString(baseIndent, 5) + "return o.hashCode();" + newLine); 
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    
    for (String type : primitiveTypes) {
      _writeToFileOut(indentString(baseIndent, 3) + "public int arrayHashCode(" + type + " array) {" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "int result = 0;" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 0; i < array.length; i++) {" + newLine);
      if (type.equals("boolean[]")) {
        _writeToFileOut(indentString(baseIndent, 5) + "result = (result << 1) ^ (array[i] ? 1 : 0);" + newLine);
      }
      else {
        _writeToFileOut(indentString(baseIndent, 5) + "result = (result << 1) ^ (int) array[i];" + newLine);
      }
      _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine);
      _writeToFileOut(indentString(baseIndent, 4) + "return result;" + newLine);
      _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    }
    
    if (useGenerics) {
      _writeToFileOut(indentString(baseIndent, 3) + "public int arrayHashCode(final java.lang.Object[] array, final java.util.LinkedList<java.lang.Object> alreadyGenerated) {" + newLine + newLine);
    }
    else {
      _writeToFileOut(indentString(baseIndent, 3) + "public int arrayHashCode(final java.lang.Object[] array, final java.util.LinkedList alreadyGenerated) {" + newLine + newLine);
    }
    _writeToFileOut(indentString(baseIndent, 4) + "class ArrayWrapper {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "public java.lang.Object[] array() { return array; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "public boolean equals(java.lang.Object o) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "return (o != null) && (o instanceof ArrayWrapper)  && " + valueEqualsName + "(array, ((ArrayWrapper) o).array());" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "public int hashCode() { return 0; } // This method should never be used -- only here for consistency." + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine + newLine);

    _writeToFileOut(indentString(baseIndent, 4) + "ArrayWrapper currentWrapper = new ArrayWrapper();" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "if (alreadyGenerated.contains(currentWrapper)) { return -1; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "alreadyGenerated.addLast(currentWrapper);" + newLine + newLine);
    
    _writeToFileOut(indentString(baseIndent, 4) + "int result = 0;" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "for (int i = 0; i < array.length; i++) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "if (array[i] instanceof java.lang.Object[]) {" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "result = (result << 1) ^ (arrayHashCode((java.lang.Object[]) array[i], alreadyGenerated) >> 1);" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "else {" + newLine);
    _writeToFileOut(indentString(baseIndent, 6) + "result = (result << 1) ^ " + methodName + "(array[i]);" + newLine);
    _writeToFileOut(indentString(baseIndent, 5) + "}" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "}" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "alreadyGenerated.removeLast();" + newLine);
    _writeToFileOut(indentString(baseIndent, 4) + "return result;" + newLine);
    _writeToFileOut(indentString(baseIndent, 3) + "}" + newLine + newLine);
    
    _writeToFileOut(indentString(baseIndent, 2) + "}" + newLine + newLine); // end of inner class
    _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return 0; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else if (o.getClass().isArray()) { return new ArrayHashCode().valueFor(o); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else { return o.hashCode(); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  /** Helper to writeValueHashCode; writes a valueHashCode that does not handle arrays. 
   *  NOTE: This is currently unused.  For the simple case, no valueHashCode method is generated.
   */
  private static void writeSimpleValueHashCode(SymbolData sd, int baseIndent, String valueEqualsName, String methodName) {
    _writeToFileOut(newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "/**" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * This method is automatically generated by the LanguageLevelConverter." + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * As a helper to hashCode(), it generates a hash code for any object," + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + " * including nulls and standard reference types." + newLine);
     _writeToFileOut(indentString(baseIndent, 1) + " */" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "private int " + methodName + "(java.lang.Object o) {" + newLine + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "if (o == null) { return 0; }" + newLine);
    _writeToFileOut(indentString(baseIndent, 2) + "else { return o.hashCode(); }" + newLine);
    _writeToFileOut(indentString(baseIndent, 1) + "}" + newLine);
  }
  
  private static String indentString(int baseIndent, int indentCount) {
    int length = indentCount * indentWidth + baseIndent;
    StringBuffer result = new StringBuffer(length);
    for (int i = 0; i < length; i++) {
      result.append(' ');
    }
    return result.toString();
  }
  
  private static boolean _isElementaryFile() {
    return LanguageLevelConverter.isElementaryFile(_llv._file);
  }
  
  private static boolean _isIntermediateFile() {
    return LanguageLevelConverter.isIntermediateFile(_llv._file);
  }
  
  private static boolean _isAdvancedFile() {
    return LanguageLevelConverter.isAdvancedFile(_llv._file);
  }
  
  private static LinkedList<MethodData> _getVariableAccessorListHelper(SymbolData currClass) {
    List<Pair<VariableData, MethodData>> accessorMappings = new Vector<Pair<VariableData, MethodData>>();
    LinkedList<SymbolData> classes = new LinkedList<SymbolData>();
    classes.add(currClass);
    
    // Gather all accessor methods that have a matching signature with their variables
    while (classes.size() > 0) {
      SymbolData tempSd = classes.removeFirst();
      if (LanguageLevelVisitor.isJavaLibraryClass(tempSd.getName())) { break; }
      
      for (int i = 0; i<tempSd.getVars().size(); i++) {
        VariableData tempVd = tempSd.getVars().get(i);
        MethodData md = tempSd.getMethod(tempVd.getName(), new TypeData[0]);
        if (md != null)
          accessorMappings.add(new Pair<VariableData, MethodData>(tempVd, md));
      }
      // Note that we don't need to check interface fields, because they are always static.
      
      SymbolData superClass = tempSd.getSuperClass();
      if (superClass != null) classes.addFirst(superClass); // Insure that we traverse the superclass hierarchy before we traverse the outer class hierarchy
      Data outerData = tempSd.getOuterData();
      if (outerData != null) { classes.addLast(outerData.getSymbolData()); }
    }
  
    // Eliminate those accessors that are inaccessible, that throw exceptions, that are static, that are shadowed, or that have a different return type
    LinkedList<MethodData> allMethods = new LinkedList<MethodData>();
    for (int i = accessorMappings.size() - 1; i >= 0; i--) {
      VariableData vd = accessorMappings.get(i).getFirst();
      MethodData md = accessorMappings.get(i).getSecond();
      boolean canSeeMethod = TypeChecker.checkAccessibility(new NullLiteral(JExprParser.NO_SOURCE_INFO), md.getMav(), md.getName(), md.getSymbolData(), currClass, "method", false);
      //TODO: it is okay to throw Runtime exceptions or Errors) {
      if (canSeeMethod && (! md.hasModifier("static")) && (md.getThrown().length == 0) && vd.getType().getSymbolData().isAssignableTo(md.getReturnType(), _targetVersion)) {
        boolean isShadowed = false;
        for (int j = i - 1; j >= 0; j--) {
          if (accessorMappings.get(j).getSecond().getName().equals(md.getName())) { isShadowed = true; break; }
        }
        if (!isShadowed) { allMethods.addFirst(md); }
      }
    }
    return allMethods;
  }

  /**
   * Read _fileIn through the given line & column and write to output.  When
   * completed, the current cursor will be one character after
   * (line, column).
   * @param line The line number to read through.
   * @param column The column to read to (or 0 to read to through the end of the previous line).
   */
  private static void _readAndWriteThroughIndex(int line, int column) {
    if (_fileInLine > line || (_fileInLine == line && _fileInColumn - 1 > column)) {
      throw new RuntimeException("Internal Program Error: Attempt to read in " + _llv._file.getName() + " through a point that is already past: line " + line + ", column " + column + "; (currently at " + _fileInLine + ", " + _fileInColumn + ").  Please report this bug.");
    }
    
    try {
      StringBuffer result = new StringBuffer();
      while (_fileInLine < line) {
        String l = _fileIn.readLine();
        if (l == null) {
          _fileOut.flush();
          throw new RuntimeException("Internal Program Error: Attempt to read in " + _llv._file.getName() + " past the end of file: line " + line + ", column " + column + "; (currently at " + _fileInLine + ", " + _fileInColumn + ").  Please report this bug.");
        }
        
        result.append(l).append(newLine);
        _fileInLine++;
        _fileInColumn = 1;
      }
      
      int lastLineLength = column - _fileInColumn + 1;
      char[] chars = new char[lastLineLength];
      int charsRead = _fileIn.read(chars, 0, lastLineLength);
      if (charsRead != lastLineLength) {
        _fileOut.flush();
        throw new RuntimeException("Internal Program Error: Attempt to read in " + _llv._file.getName() + " past the end of file: line " + line + ", column " + column + "; (currently at " + _fileInLine + ", " + _fileInColumn + ").  Please report this bug.");
      }
      result.append(chars);
      _fileInLine = line;
      _fileInColumn = column + 1;
      
      _writeToFileOut(result.toString());
    }
    catch (IOException ioe) {
      throw new Augmentor.Exception(ioe);
    }
  }
  
  private static void _writeToFileOut(String s) {
    try {
      _fileOut.write(s);
    }
    catch (IOException ioe) {
      throw new Augmentor.Exception(ioe);
    }
  }
  
//  private static boolean _targetIs15() {
//    return (_targetVersion.indexOf("1.5") != -1);
//  }
  
  public static class MethodBodyAugmentor extends Augmentor {
    
    protected MethodBodyAugmentor(Data enclosing) {
      super(enclosing);
    }
  
    public void forVariableDeclaration(VariableDeclaration that) {
      _readAndWriteThroughIndex(that.getSourceInfo().getStartLine(), that.getSourceInfo().getStartColumn() - 1);
      if (!_isAdvancedFile())
        _writeToFileOut("final ");
    }
  
  }
  
  public static class Exception extends RuntimeException {
    public Exception(java.lang.Exception nested) {
      super(nested);
    }
  }
  
  /**
   * A JUnit test case class.
   * Every method starting with the word "test" will be called when running
   * the test with JUnit.
   */
  public static class AugmentorTest extends TestCase {

    public AugmentorTest() {
      this("");
    }
    public AugmentorTest(String name) {
      super(name);
    }
    
    private Augmentor _a;
    private File _f = new File("");
    private Symboltable _s = new Symboltable();
    
    public void setUp() {
      LanguageLevelVisitor llv = new ElementaryVisitor(_f, new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      _a = new Augmentor(JavaVersion.JAVA_1_4, true, null, null, llv);
    }

    public void testFormalParameters2TypeDatas() {
      FormalParameter[] fp = new FormalParameter[0];
      TypeData[] result = formalParameters2TypeDatas(fp, _a._enclosingData);
      assertEquals("The result is empty", 0, result.length);
      
      PrimitiveType intt = new PrimitiveType(JExprParser.NO_SOURCE_INFO, "int");
      FormalParameter param = new FormalParameter(JExprParser.NO_SOURCE_INFO, new UninitializedVariableDeclarator(JExprParser.NO_SOURCE_INFO, intt, new Word(JExprParser.NO_SOURCE_INFO, "j")), false);
      SymbolData intData = SymbolData.INT_TYPE;
      _s.put("int", intData);
      
      ClassOrInterfaceType stringt = new ClassOrInterfaceType(JExprParser.NO_SOURCE_INFO, "java.lang.String", new Type[0]);
      FormalParameter param2 = new FormalParameter(JExprParser.NO_SOURCE_INFO, new UninitializedVariableDeclarator(JExprParser.NO_SOURCE_INFO, stringt, new Word(JExprParser.NO_SOURCE_INFO, "j")), false);
      SymbolData stringData = new SymbolData("java.lang.String");
      _s.put("java.lang.String", stringData);

      fp = new FormalParameter[]{ param, param2 };
      result = formalParameters2TypeDatas(fp, _a._enclosingData);
      assertTrue("Arrays should be equal", LanguageLevelVisitor.arrayEquals(result, new TypeData[]{ intData, stringData }));
      
      //test an inner class
      FormalParameter param3 = new FormalParameter(JExprParser.NO_SOURCE_INFO, new UninitializedVariableDeclarator(JExprParser.NO_SOURCE_INFO,  new ClassOrInterfaceType(JExprParser.NO_SOURCE_INFO, "Inner", new Type[0]), new Word(JExprParser.NO_SOURCE_INFO, "t")), false);
      fp = new FormalParameter[] {param3};
      SymbolData inner = new SymbolData("Inner");
      inner.setIsContinuation(false);
      _a._enclosingData = new SymbolData("me");
      _a._enclosingData.addInnerClass(inner);
      result = formalParameters2TypeDatas(fp, _a._enclosingData);
      assertTrue("Arrays should be equal", LanguageLevelVisitor.arrayEquals(result, new TypeData[] {inner}));
    }


    public void testIndentString() {
      assertEquals("Should return a string of 0 tabs", "", indentString(0, 0));
      assertEquals("Should return a string of 6 tabs", "            ", indentString(2, 5));
    }

    public void testIsElementaryFile() {
      _llv = new ElementaryVisitor(new File("elementary.dj0"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertTrue("This is an elementary file", _isElementaryFile());
      _llv = new IntermediateVisitor(new File("intermediate.dj1"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is an intermediate file", _isElementaryFile());
      _llv = new AdvancedVisitor(new File("advanced.dj2"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is an advanced file", _isElementaryFile());
      _llv = new ElementaryVisitor(new File("full.java"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is a full file", _isElementaryFile());
    }

    public void testIsIntermediateFile() {
      _llv = new ElementaryVisitor(new File("elementary.dj0"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is an elementary file", _isIntermediateFile());
      _llv = new IntermediateVisitor(new File("intermediate.dj1"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertTrue("This is an intermediate file", _isIntermediateFile());
      _llv = new AdvancedVisitor(new File("advanced.dj2"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is an advanced file", _isIntermediateFile());
      _llv = new ElementaryVisitor(new File("full.java"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is a full file", _isIntermediateFile());
    }

    public void testIsAdvancedFile() {
      _llv = new ElementaryVisitor(new File("elementary.dj0"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is an elementary file", _isAdvancedFile());
      _llv = new IntermediateVisitor(new File("intermediate.dj1"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is an intermediate file", _isAdvancedFile());
      _llv = new AdvancedVisitor(new File("advanced.dj2"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertTrue("This is an advanced file", _isAdvancedFile());
      _llv = new ElementaryVisitor(new File("full.java"), new LinkedList<Pair<String, JExpressionIF>>(), _s, new Hashtable<String, Pair<SourceInfo, LanguageLevelVisitor>>(), new LinkedList<Pair<LanguageLevelVisitor, SourceFile>>(), new Hashtable<SymbolData, LanguageLevelVisitor>(), null);
      assertFalse("This is a full file", _isAdvancedFile());
    }
    
//    public void testTargetIs15() {
//      _a._targetVersion = "1.5.0.Z.B.2";
//      assertTrue("Target is 1.5!", _targetIs15());
//      _a._targetVersion = "1.5";
//      assertTrue("Target is still 1.5!", _targetIs15());
//      _a._targetVersion = "jdk1.5";
//      assertTrue("And yes Dan, the target is still 1.5", _targetIs15());
//      
//      _a._targetVersion = "jdk1.4.2-zeta";
//      assertFalse("This is not 1.5...it is some strange version of 1.4.", _targetIs15());
//      _a._targetVersion = "definitelyNotRight";
//      assertFalse("This is not 1.5 either.", _targetIs15());
//      
//    }

    public void testGetVariableAccessorListHelper() {
      ModifiersAndVisibility _publicMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"public"});
      ModifiersAndVisibility _privateMav = new ModifiersAndVisibility(JExprParser.NO_SOURCE_INFO, new String[] {"private"});

      SymbolData houston = new SymbolData("Houston");
      SymbolData texas = new SymbolData("Texas");
      houston.setSuperClass(texas);
      
      //first, add a field to texas that has a public gettor.  This one should be returned.
      texas.addVar(new VariableData("lone_star", _publicMav, SymbolData.INT_TYPE, true, texas));
      MethodData lone_star = new MethodData("lone_star", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[0], 
                                     new String[0], texas, new NullLiteral(JExprParser.NO_SOURCE_INFO));
      texas.addMethod(lone_star); 

      //no gettor for cool, therefore, it should not be returned.
      //NOTE: gettor might be best spelled "getter", but whoever is typing believes it should be spelled this way.
      texas.addVar(new VariableData("cool", _publicMav, SymbolData.DOUBLE_TYPE, true, texas));

      //now, add a private gettor for armidillo to texas.  This should not be returned, because it is private.
      texas.addVar(new VariableData("armadillo", _publicMav, SymbolData.BOOLEAN_TYPE, true, texas));
      MethodData armadillo = new MethodData("armadillo", _privateMav, new TypeParameter[0], SymbolData.BOOLEAN_TYPE, new VariableData[0], 
                                     new String[0], texas, new NullLiteral(JExprParser.NO_SOURCE_INFO));
      texas.addMethod(armadillo);
      
      //now add a field badRoad to Houston.  Its gettor returns a supertype of its type, so it is okay to call.  Will be returned.
      houston.addVar(new VariableData("badRoad", _publicMav, SymbolData.CHAR_TYPE, true, houston));
      MethodData badRoad = new MethodData("badRoad", _publicMav, new TypeParameter[0], SymbolData.INT_TYPE, new VariableData[0], 
                                     new String[0], houston, new NullLiteral(JExprParser.NO_SOURCE_INFO));
      houston.addMethod(badRoad);
      
      LinkedList<MethodData> expected = new LinkedList<MethodData>();
      expected.add(badRoad);
      expected.add(lone_star);
      LinkedList<MethodData> actual = _getVariableAccessorListHelper(houston);
//      for(MethodData m : actual)
//        System.out.println(m.getName());
      assertEquals("Should return the right list of gettors", expected, actual);
      
      
      //if there aren't any fields or methods, that's still okay!
      SymbolData soLonely = new SymbolData("I have no fields!");
      assertEquals("Should return an empty list", 0, _getVariableAccessorListHelper(soLonely).size());
    }
    
  }
}



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