]> source.dussan.org Git - javassist.git/commitdiff
methodinfos are not equal for some reason.
authorpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 9 Dec 2004 22:37:15 +0000 (22:37 +0000)
committerpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 9 Dec 2004 22:37:15 +0000 (22:37 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@149 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

src/main/javassist/bytecode/MethodInfo.java
src/main/javassist/expr/Expr.java

index 2e1e4fed1e5f91364fb01db98cba6530ebda539f..9d434e16f0f263d7f8752ec1ccfb36dd7c9ddd15 100644 (file)
@@ -28,364 +28,400 @@ import java.util.Map;
  * @see javassist.CtMethod#getMethodInfo()
  * @see javassist.CtConstructor#getMethodInfo()
  */
-public final class MethodInfo {
-    ConstPool constPool;
-    int accessFlags;
-    int name;
-    int descriptor;
-    LinkedList attribute;       // may be null
-
-    /**
-     * The name of constructors: <code>&lt;init&gt</code>.
-     */
-    public static final String nameInit = "<init>";
-
-    /**
-     * The name of class initializer (static initializer):
-     * <code>&lt;clinit&gt</code>.
-     */
-    public static final String nameClinit = "<clinit>";
-
-    private MethodInfo(ConstPool cp) {
-        constPool = cp;
-        attribute = null;
-    }
-
-    /**
-     * Constructs a <code>method_info</code> structure.
-     * The initial value of <code>access_flags</code> is zero.
-     *
-     * @param cp                a constant pool table
-     * @param methodname        method name
-     * @param desc              method descriptor
-     * @see Descriptor
-     */
-    public MethodInfo(ConstPool cp, String methodname, String desc) {
-        this(cp);
-        accessFlags = 0;
-        name = cp.addUtf8Info(methodname);
-        descriptor = constPool.addUtf8Info(desc);
-    }
-
-    MethodInfo(ConstPool cp, DataInputStream in) throws IOException {
-        this(cp);
-        read(in);
-    }
-
-    /**
-     * Constructs a copy of <code>method_info</code> structure.
-     * Class names appearing in the source <code>method_info</code>
-     * are renamed according to <code>classnameMap</code>.
-     *
-     * <p>Note: only <code>Code</code> and <code>Exceptions</code>
-     * attributes are copied from the source.  The other attributes
-     * are ignored.
-     *
-     * @param cp                a constant pool table
-     * @param methodname        a method name
-     * @param src               a source <code>method_info</code>
-     * @param classnameMap      specifies pairs of replaced and substituted
-     *                          name.
-     * @see Descriptor
-     */
-    public MethodInfo(ConstPool cp, String methodname, MethodInfo src,
-                      Map classnameMap) throws BadBytecode
-    {
-        this(cp);
-        read(src, methodname, classnameMap);
-    }
-
-    void prune(ConstPool cp) {
-        attribute = null;
-        name = cp.addUtf8Info(getName());
-        descriptor = cp.addUtf8Info(getDescriptor());
-        constPool = cp;
-    }
-
-    /**
-     * Returns a method name.
-     */
-    public String getName() {
-        return constPool.getUtf8Info(name);
-    }
-
-    /**
-     * Sets a method name.
-     */
-    public void setName(String newName) {
-        name = constPool.addUtf8Info(newName);
-    }
-
-    /**
-     * Returns true if this is not a constructor or a class initializer
-     * (static initializer).
-     */
-    public boolean isMethod() {
-        String n = getName();
-        return !n.equals(nameInit) && !n.equals(nameClinit);
-    }
-
-    /**
-     * Returns a constant pool table used by this method.
-     */
-    public ConstPool getConstPool() {
-        return constPool;
-    }
-
-    /**
-     * Returns true if this is a constructor.
-     */
-    public boolean isConstructor() {
-        return getName().equals(nameInit);
-    }
-
-    /**
-     * Returns true if this is a class initializer (static initializer).
-     */
-    public boolean isStaticInitializer() {
-        return getName().equals(nameClinit);
-    }
-
-    /**
-     * Returns access flags.
-     *
-     * @see AccessFlag
-     */
-    public int getAccessFlags() {
-        return accessFlags;
-    }
-
-    /**
-     * Sets access flags.
-     *
-     * @see AccessFlag
-     */
-    public void setAccessFlags(int acc) {
-        accessFlags = acc;
-    }
-
-    /**
-     * Returns a method descriptor.
-     *
-     * @see Descriptor
-     */
-    public String getDescriptor() {
-        return constPool.getUtf8Info(descriptor);
-    }
-
-    /**
-     * Sets a method descriptor.
-     *
-     * @see Descriptor
-     */
-    public void setDescriptor(String desc) {
-        if (!desc.equals(getDescriptor()))
-            descriptor = constPool.addUtf8Info(desc);
-    }
-
-    /**
-     * Returns all the attributes.
-     * A new element can be added to the returned list
-     * and an existing element can be removed from the list.
-     *
-     * @return a list of <code>AttributeInfo</code> objects.
-     * @see AttributeInfo
-     */
-    public List getAttributes() {
-        if (attribute == null)
-            attribute = new LinkedList();
-
-        return attribute;
-    }
-
-    /**
-     * Returns the attribute with the specified name.
-     * If it is not found, this method returns null.
-     *
-     * @param name      attribute name
-     * @return an <code>AttributeInfo</code> object or null.
-     */
-    public AttributeInfo getAttribute(String name) {
-        return AttributeInfo.lookup(attribute, name);
-    }
-
-    /**
-     * Appends an attribute.  If there is already an attribute with
-     * the same name, the new one substitutes for it.
-     */
-    public void addAttribute(AttributeInfo info) {
-        if (attribute == null)
-            attribute = new LinkedList();
-
-        AttributeInfo.remove(attribute, info.getName());
-        attribute.add(info);
-    }
-
-    /**
-     * Returns an Exceptions attribute.
-     *
-     * @return an Exceptions attribute
-     *         or null if it is not specified.
-     */
-    public ExceptionsAttribute getExceptionsAttribute() {
-        AttributeInfo info
-            = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag);
-        return (ExceptionsAttribute)info;
-    }
-
-    /**
-     * Returns a Code attribute.
-     *
-     * @return a Code attribute
-     *         or null if it is not specified.
-     */
-    public CodeAttribute getCodeAttribute() {
-        AttributeInfo info
-            = AttributeInfo.lookup(attribute, CodeAttribute.tag);
-        return (CodeAttribute)info;
-    }
-
-    /**
-     * Removes an Exception attribute.
-     */
-    public void removeExceptionsAttribute() {
-        AttributeInfo.remove(attribute, ExceptionsAttribute.tag);
-    }
-
-    /**
-     * Adds an Exception attribute.
-     *
-     * <p>The added attribute must share the same constant pool table
-     * as this <code>method_info</code> structure.
-     */
-    public void setExceptionsAttribute(ExceptionsAttribute cattr) {
-        removeExceptionsAttribute();
-        if (attribute == null)
-            attribute = new LinkedList();
-
-        attribute.add(cattr);
-    }
-
-    /**
-     * Removes a Code attribute.
-     */
-    public void removeCodeAttribute() {
-        AttributeInfo.remove(attribute, CodeAttribute.tag);
-    }
-
-    /**
-     * Adds a Code attribute.
-     *
-     * <p>The added attribute must share the same constant pool table
-     * as this <code>method_info</code> structure.
-     */
-    public void setCodeAttribute(CodeAttribute cattr) {
-        removeCodeAttribute();
-        if (attribute == null)
-            attribute = new LinkedList();
-
-        attribute.add(cattr);
-    }
-
-    /**
-     * Returns the line number of the source line corresponding to the
-     * specified bytecode contained in this method.
-     *
-     * @param pos       the position of the bytecode (&gt;= 0).
-     *                  an index into the code array.
-     * @return -1       if this information is not available.
-     */
-    public int getLineNumber(int pos) {
-        CodeAttribute ca = getCodeAttribute();
-        if (ca == null)
-            return -1;
-
-        LineNumberAttribute ainfo =
-            (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
-        if (ainfo == null)
-            return -1;
-
-        return ainfo.toLineNumber(pos);
-    }
-
-    /**
-     * Changes a super constructor called by this constructor.
-     *
-     * <p>This method modifies a call to <code>super()</code>,
-     * which should be at the
-     * head of a constructor body, so that a constructor in a different
-     * super class is called.  This method does not change actural
-     * parameters.  Hence the new super class must have a constructor
-     * with the same signature as the original one.
-     *
-     * <p>This method should be called when the super class
-     * of the class declaring this method is changed.
-     *
-     * <p>This method does not perform anything unless this
-     * <code>MethodInfo</code> represents a constructor.
-     *
-     * @param superclass        the new super class
-     */
-    public void setSuperclass(String superclass) throws BadBytecode {
-        if (!isConstructor())
-            return;
-
-        CodeAttribute ca = getCodeAttribute();
-        byte[] code = ca.getCode();
-        CodeIterator iterator = ca.iterator();
-        int pos = iterator.skipSuperConstructor();
-        if (pos >= 0) { // not this()
-            ConstPool cp = constPool;
-            int mref = ByteArray.readU16bit(code, pos + 1);
-            int nt = cp.getMethodrefNameAndType(mref);
-            int sc = cp.addClassInfo(superclass);
-            int mref2 = cp.addMethodrefInfo(sc, nt);
-            ByteArray.write16bit(mref2, code, pos + 1);
-        }
-    }
-
-    private void read(MethodInfo src, String methodname, Map classnames)
-        throws BadBytecode
-    {
-        ConstPool destCp = constPool;
-        accessFlags = src.accessFlags;
-        name = destCp.addUtf8Info(methodname);
-
-        ConstPool srcCp = src.constPool;
-        String desc = srcCp.getUtf8Info(src.descriptor);
-        String desc2 = Descriptor.rename(desc, classnames);
-        descriptor = destCp.addUtf8Info(desc2);
-
-        attribute = new LinkedList();
-        ExceptionsAttribute eattr = src.getExceptionsAttribute();
-        if (eattr != null)
-            attribute.add(eattr.copy(destCp, classnames));
-
-        CodeAttribute cattr = src.getCodeAttribute();
-        if (cattr != null)
-            attribute.add(cattr.copy(destCp, classnames));
-    }
-
-    private void read(DataInputStream in) throws IOException {
-        accessFlags = in.readUnsignedShort();
-        name = in.readUnsignedShort();
-        descriptor = in.readUnsignedShort();
-        int n = in.readUnsignedShort();
-        attribute = new LinkedList();
-        for (int i = 0; i < n; ++i)
-            attribute.add(AttributeInfo.read(constPool, in));
-    }
-
-    void write(DataOutputStream out) throws IOException {
-        out.writeShort(accessFlags);
-        out.writeShort(name);
-        out.writeShort(descriptor);
-
-        if (attribute == null)
-            out.writeShort(0);
-        else {
-            out.writeShort(attribute.size());
-            AttributeInfo.writeAll(attribute, out);
-        }
-    }
+public final class MethodInfo
+{
+   ConstPool constPool;
+   int accessFlags;
+   int name;
+   int descriptor;
+   LinkedList attribute;       // may be null
+   public Exception created = new Exception();
+
+   /**
+    * The name of constructors: <code>&lt;init&gt</code>.
+    */
+   public static final String nameInit = "<init>";
+
+   /**
+    * The name of class initializer (static initializer):
+    * <code>&lt;clinit&gt</code>.
+    */
+   public static final String nameClinit = "<clinit>";
+
+   private MethodInfo(ConstPool cp)
+   {
+      constPool = cp;
+      attribute = null;
+   }
+
+   /**
+    * Constructs a <code>method_info</code> structure.
+    * The initial value of <code>access_flags</code> is zero.
+    *
+    * @param cp         a constant pool table
+    * @param methodname method name
+    * @param desc       method descriptor
+    * @see Descriptor
+    */
+   public MethodInfo(ConstPool cp, String methodname, String desc)
+   {
+      this(cp);
+      accessFlags = 0;
+      name = cp.addUtf8Info(methodname);
+      descriptor = constPool.addUtf8Info(desc);
+   }
+
+   MethodInfo(ConstPool cp, DataInputStream in) throws IOException
+   {
+      this(cp);
+      read(in);
+   }
+
+   /**
+    * Constructs a copy of <code>method_info</code> structure.
+    * Class names appearing in the source <code>method_info</code>
+    * are renamed according to <code>classnameMap</code>.
+    * <p/>
+    * <p>Note: only <code>Code</code> and <code>Exceptions</code>
+    * attributes are copied from the source.  The other attributes
+    * are ignored.
+    *
+    * @param cp           a constant pool table
+    * @param methodname   a method name
+    * @param src          a source <code>method_info</code>
+    * @param classnameMap specifies pairs of replaced and substituted
+    *                     name.
+    * @see Descriptor
+    */
+   public MethodInfo(ConstPool cp, String methodname, MethodInfo src,
+                     Map classnameMap) throws BadBytecode
+   {
+      this(cp);
+      read(src, methodname, classnameMap);
+   }
+
+   public String toString()
+   {
+      return constPool.getUtf8Info(name) + " " + constPool.getUtf8Info(descriptor);
+   }
+
+   void prune(ConstPool cp)
+   {
+      attribute = null;
+      name = cp.addUtf8Info(getName());
+      descriptor = cp.addUtf8Info(getDescriptor());
+      constPool = cp;
+   }
+
+   /**
+    * Returns a method name.
+    */
+   public String getName()
+   {
+      return constPool.getUtf8Info(name);
+   }
+
+   /**
+    * Sets a method name.
+    */
+   public void setName(String newName)
+   {
+      name = constPool.addUtf8Info(newName);
+   }
+
+   /**
+    * Returns true if this is not a constructor or a class initializer
+    * (static initializer).
+    */
+   public boolean isMethod()
+   {
+      String n = getName();
+      return !n.equals(nameInit) && !n.equals(nameClinit);
+   }
+
+   /**
+    * Returns a constant pool table used by this method.
+    */
+   public ConstPool getConstPool()
+   {
+      return constPool;
+   }
+
+   /**
+    * Returns true if this is a constructor.
+    */
+   public boolean isConstructor()
+   {
+      return getName().equals(nameInit);
+   }
+
+   /**
+    * Returns true if this is a class initializer (static initializer).
+    */
+   public boolean isStaticInitializer()
+   {
+      return getName().equals(nameClinit);
+   }
+
+   /**
+    * Returns access flags.
+    *
+    * @see AccessFlag
+    */
+   public int getAccessFlags()
+   {
+      return accessFlags;
+   }
+
+   /**
+    * Sets access flags.
+    *
+    * @see AccessFlag
+    */
+   public void setAccessFlags(int acc)
+   {
+      accessFlags = acc;
+   }
+
+   /**
+    * Returns a method descriptor.
+    *
+    * @see Descriptor
+    */
+   public String getDescriptor()
+   {
+      return constPool.getUtf8Info(descriptor);
+   }
+
+   /**
+    * Sets a method descriptor.
+    *
+    * @see Descriptor
+    */
+   public void setDescriptor(String desc)
+   {
+      if (!desc.equals(getDescriptor()))
+         descriptor = constPool.addUtf8Info(desc);
+   }
+
+   /**
+    * Returns all the attributes.
+    * A new element can be added to the returned list
+    * and an existing element can be removed from the list.
+    *
+    * @return a list of <code>AttributeInfo</code> objects.
+    * @see AttributeInfo
+    */
+   public List getAttributes()
+   {
+      if (attribute == null)
+         attribute = new LinkedList();
+
+      return attribute;
+   }
+
+   /**
+    * Returns the attribute with the specified name.
+    * If it is not found, this method returns null.
+    *
+    * @param name attribute name
+    * @return an <code>AttributeInfo</code> object or null.
+    */
+   public AttributeInfo getAttribute(String name)
+   {
+      return AttributeInfo.lookup(attribute, name);
+   }
+
+   /**
+    * Appends an attribute.  If there is already an attribute with
+    * the same name, the new one substitutes for it.
+    */
+   public void addAttribute(AttributeInfo info)
+   {
+      if (attribute == null)
+         attribute = new LinkedList();
+
+      AttributeInfo.remove(attribute, info.getName());
+      attribute.add(info);
+   }
+
+   /**
+    * Returns an Exceptions attribute.
+    *
+    * @return an Exceptions attribute
+    *         or null if it is not specified.
+    */
+   public ExceptionsAttribute getExceptionsAttribute()
+   {
+      AttributeInfo info
+      = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag);
+      return (ExceptionsAttribute) info;
+   }
+
+   /**
+    * Returns a Code attribute.
+    *
+    * @return a Code attribute
+    *         or null if it is not specified.
+    */
+   public CodeAttribute getCodeAttribute()
+   {
+      AttributeInfo info
+      = AttributeInfo.lookup(attribute, CodeAttribute.tag);
+      return (CodeAttribute) info;
+   }
+
+   /**
+    * Removes an Exception attribute.
+    */
+   public void removeExceptionsAttribute()
+   {
+      AttributeInfo.remove(attribute, ExceptionsAttribute.tag);
+   }
+
+   /**
+    * Adds an Exception attribute.
+    * <p/>
+    * <p>The added attribute must share the same constant pool table
+    * as this <code>method_info</code> structure.
+    */
+   public void setExceptionsAttribute(ExceptionsAttribute cattr)
+   {
+      removeExceptionsAttribute();
+      if (attribute == null)
+         attribute = new LinkedList();
+
+      attribute.add(cattr);
+   }
+
+   /**
+    * Removes a Code attribute.
+    */
+   public void removeCodeAttribute()
+   {
+      AttributeInfo.remove(attribute, CodeAttribute.tag);
+   }
+
+   /**
+    * Adds a Code attribute.
+    * <p/>
+    * <p>The added attribute must share the same constant pool table
+    * as this <code>method_info</code> structure.
+    */
+   public void setCodeAttribute(CodeAttribute cattr)
+   {
+      removeCodeAttribute();
+      if (attribute == null)
+         attribute = new LinkedList();
+
+      attribute.add(cattr);
+   }
+
+   /**
+    * Returns the line number of the source line corresponding to the
+    * specified bytecode contained in this method.
+    *
+    * @param pos the position of the bytecode (&gt;= 0).
+    *            an index into the code array.
+    * @return -1       if this information is not available.
+    */
+   public int getLineNumber(int pos)
+   {
+      CodeAttribute ca = getCodeAttribute();
+      if (ca == null)
+         return -1;
+
+      LineNumberAttribute ainfo =
+      (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag);
+      if (ainfo == null)
+         return -1;
+
+      return ainfo.toLineNumber(pos);
+   }
+
+   /**
+    * Changes a super constructor called by this constructor.
+    * <p/>
+    * <p>This method modifies a call to <code>super()</code>,
+    * which should be at the
+    * head of a constructor body, so that a constructor in a different
+    * super class is called.  This method does not change actural
+    * parameters.  Hence the new super class must have a constructor
+    * with the same signature as the original one.
+    * <p/>
+    * <p>This method should be called when the super class
+    * of the class declaring this method is changed.
+    * <p/>
+    * <p>This method does not perform anything unless this
+    * <code>MethodInfo</code> represents a constructor.
+    *
+    * @param superclass the new super class
+    */
+   public void setSuperclass(String superclass) throws BadBytecode
+   {
+      if (!isConstructor())
+         return;
+
+      CodeAttribute ca = getCodeAttribute();
+      byte[] code = ca.getCode();
+      CodeIterator iterator = ca.iterator();
+      int pos = iterator.skipSuperConstructor();
+      if (pos >= 0)
+      { // not this()
+         ConstPool cp = constPool;
+         int mref = ByteArray.readU16bit(code, pos + 1);
+         int nt = cp.getMethodrefNameAndType(mref);
+         int sc = cp.addClassInfo(superclass);
+         int mref2 = cp.addMethodrefInfo(sc, nt);
+         ByteArray.write16bit(mref2, code, pos + 1);
+      }
+   }
+
+   private void read(MethodInfo src, String methodname, Map classnames)
+   throws BadBytecode
+   {
+      ConstPool destCp = constPool;
+      accessFlags = src.accessFlags;
+      name = destCp.addUtf8Info(methodname);
+
+      ConstPool srcCp = src.constPool;
+      String desc = srcCp.getUtf8Info(src.descriptor);
+      String desc2 = Descriptor.rename(desc, classnames);
+      descriptor = destCp.addUtf8Info(desc2);
+
+      attribute = new LinkedList();
+      ExceptionsAttribute eattr = src.getExceptionsAttribute();
+      if (eattr != null)
+         attribute.add(eattr.copy(destCp, classnames));
+
+      CodeAttribute cattr = src.getCodeAttribute();
+      if (cattr != null)
+         attribute.add(cattr.copy(destCp, classnames));
+   }
+
+   private void read(DataInputStream in) throws IOException
+   {
+      accessFlags = in.readUnsignedShort();
+      name = in.readUnsignedShort();
+      descriptor = in.readUnsignedShort();
+      int n = in.readUnsignedShort();
+      attribute = new LinkedList();
+      for (int i = 0; i < n; ++i)
+         attribute.add(AttributeInfo.read(constPool, in));
+   }
+
+   void write(DataOutputStream out) throws IOException
+   {
+      out.writeShort(accessFlags);
+      out.writeShort(name);
+      out.writeShort(descriptor);
+
+      if (attribute == null)
+         out.writeShort(0);
+      else
+      {
+         out.writeShort(attribute.size());
+         AttributeInfo.writeAll(attribute, out);
+      }
+   }
 }
index 3c99b1fc7e138a49e9efbf9a2e6a4733ef95dc25..8d2b75ab30398b7983600e8c78a184d2d75d525f 100644 (file)
 
 package javassist.expr;
 
-import javassist.*;
-import javassist.bytecode.*;
-import javassist.compiler.*;
-import java.util.LinkedList;
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtBehavior;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtPrimitiveType;
+import javassist.NotFoundException;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.BadBytecode;
+import javassist.bytecode.Bytecode;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.CodeAttribute;
+import javassist.bytecode.CodeIterator;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.ExceptionTable;
+import javassist.bytecode.ExceptionsAttribute;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.Opcode;
+import javassist.compiler.Javac;
+
 import java.util.Iterator;
+import java.util.LinkedList;
 
 /**
  * Expression.
  */
-public abstract class Expr implements Opcode {
-    int currentPos;
-    CodeIterator iterator;
-    CtClass thisClass;
-    MethodInfo thisMethod;
-
-    boolean edited;
-    int maxLocals, maxStack;
-
-    static final String javaLangObject = "java.lang.Object";
-
-    /**
-     * Undocumented constructor.  Do not use; internal-use only.
-     */
-    protected Expr(int pos, CodeIterator i, CtClass declaring, MethodInfo m) {
-        currentPos = pos;
-        iterator = i;
-        thisClass = declaring;
-        thisMethod = m;
-    }
-
-    protected final ConstPool getConstPool() {
-        return thisMethod.getConstPool();
-    }
-
-    protected final boolean edited() { return edited; }
-
-    protected final int locals() { return maxLocals; }
-
-    protected final int stack() { return maxStack; }
-
-    /**
-     * Returns true if this method is static.
-     */
-    protected final boolean withinStatic() {
-        return (thisMethod.getAccessFlags() & AccessFlag.STATIC) != 0;
-    }
-
-    /**
-     * Returns the constructor or method containing the expression.
-     */
-    public CtBehavior where() {
-        MethodInfo mi = thisMethod;
-        CtBehavior[] cb = thisClass.getDeclaredBehaviors();
-        for (int i = cb.length - 1; i >= 0; --i)
-            if (cb[i].getMethodInfo2() == mi)
-                return cb[i];
-
-        CtConstructor init = thisClass.getClassInitializer();
-        if (init.getMethodInfo2() == mi)
-            return init;
-
-        throw new RuntimeException("fatal: not found");
-    }
-
-    /**
-     * Returns the list of exceptions that the expression may throw.
-     * This list includes both the exceptions that the try-catch statements
-     * including the expression can catch and the exceptions that
-     * the throws declaration allows the method to throw.
-     */
-    public CtClass[] mayThrow() {
-        ClassPool pool = thisClass.getClassPool();
-        ConstPool cp = thisMethod.getConstPool();
-        LinkedList list = new LinkedList();
-        try {
-            CodeAttribute ca = thisMethod.getCodeAttribute();
-            ExceptionTable et = ca.getExceptionTable();
-            int pos = currentPos;
-            int n = et.size();
-            for (int i = 0; i < n; ++i)
-                if (et.startPc(i) <= pos && pos < et.endPc(i)) {
-                    int t = et.catchType(i);
-                    if (t > 0)
-                        try {
-                            addClass(list, pool.get(cp.getClassInfo(t)));
-                        }
-                        catch (NotFoundException e) {}
-                }
-        }
-        catch (NullPointerException e) {}
-
-        ExceptionsAttribute ea = thisMethod.getExceptionsAttribute();
-        if (ea != null) {
-            String[] exceptions = ea.getExceptions();
-            if (exceptions != null) {
-                int n = exceptions.length;
-                for (int i = 0; i < n; ++i)
-                    try {
-                        addClass(list, pool.get(exceptions[i]));
-                    }
-                    catch (NotFoundException e) {}
+public abstract class Expr implements Opcode
+{
+   int currentPos;
+   CodeIterator iterator;
+   CtClass thisClass;
+   MethodInfo thisMethod;
+
+   boolean edited;
+   int maxLocals, maxStack;
+
+   static final String javaLangObject = "java.lang.Object";
+
+   /**
+    * Undocumented constructor.  Do not use; internal-use only.
+    */
+   protected Expr(int pos, CodeIterator i, CtClass declaring, MethodInfo m)
+   {
+      currentPos = pos;
+      iterator = i;
+      thisClass = declaring;
+      thisMethod = m;
+   }
+
+   protected final ConstPool getConstPool()
+   {
+      return thisMethod.getConstPool();
+   }
+
+   protected final boolean edited()
+   {
+      return edited;
+   }
+
+   protected final int locals()
+   {
+      return maxLocals;
+   }
+
+   protected final int stack()
+   {
+      return maxStack;
+   }
+
+   /**
+    * Returns true if this method is static.
+    */
+   protected final boolean withinStatic()
+   {
+      return (thisMethod.getAccessFlags() & AccessFlag.STATIC) != 0;
+   }
+
+   /**
+    * Returns the constructor or method containing the expression.
+    */
+   public CtBehavior where()
+   {
+      MethodInfo mi = thisMethod;
+      CtBehavior[] cb = thisClass.getDeclaredBehaviors();
+      for (int i = cb.length - 1; i >= 0; --i)
+         if (cb[i].getMethodInfo2() == mi)
+            return cb[i];
+
+      CtConstructor init = thisClass.getClassInitializer();
+      if (init != null && init.getMethodInfo2() == mi)
+         return init;
+
+      // todo REVISIT I needed to add this because for some reason mi != cb[i]
+      for (int i = cb.length - 1; i >= 0; --i)
+      {
+         if (thisMethod.getName().equals(cb[i].getMethodInfo2().getName()) && thisMethod.getDescriptor().equals(cb[i].getMethodInfo2().getDescriptor()))
+         {
+            return cb[i];
+         }
+      }
+
+      String msg = "fatal: not found";
+      throw new RuntimeException(msg);
+   }
+
+   /**
+    * Returns the list of exceptions that the expression may throw.
+    * This list includes both the exceptions that the try-catch statements
+    * including the expression can catch and the exceptions that
+    * the throws declaration allows the method to throw.
+    */
+   public CtClass[] mayThrow()
+   {
+      ClassPool pool = thisClass.getClassPool();
+      ConstPool cp = thisMethod.getConstPool();
+      LinkedList list = new LinkedList();
+      try
+      {
+         CodeAttribute ca = thisMethod.getCodeAttribute();
+         ExceptionTable et = ca.getExceptionTable();
+         int pos = currentPos;
+         int n = et.size();
+         for (int i = 0; i < n; ++i)
+            if (et.startPc(i) <= pos && pos < et.endPc(i))
+            {
+               int t = et.catchType(i);
+               if (t > 0)
+                  try
+                  {
+                     addClass(list, pool.get(cp.getClassInfo(t)));
+                  }
+                  catch (NotFoundException e)
+                  {
+                  }
             }
-        }
-
-        return (CtClass[])list.toArray(new CtClass[list.size()]);
-    }
-
-    private static void addClass(LinkedList list, CtClass c) {
-        Iterator it = list.iterator();
-        while (it.hasNext())
-            if (it.next() == c)
-                return;
-
-        list.add(c);
-    }
-
-    /**
-     * Returns the index of the bytecode corresponding to the
-     * expression.
-     * It is the index into the byte array containing the Java bytecode
-     * that implements the method.
-     */
-    public int indexOfBytecode() {
-        return currentPos;
-    }
-
-    /**
-     * Returns the line number of the source line containing the
-     * expression.
-     *
-     * @return -1       if this information is not available.
-     */
-    public int getLineNumber() {
-        return thisMethod.getLineNumber(currentPos);
-    }
-
-    /**
-     * Returns the source file containing the expression.
-     *
-     * @return null     if this information is not available.
-     */
-    public String getFileName() {
-        ClassFile cf = thisClass.getClassFile2();
-        if (cf == null)
-            return null;
-        else
-            return cf.getSourceFile();
-    }
-
-    static final boolean checkResultValue(CtClass retType, String prog)
-        throws CannotCompileException
-    {
-        /* Is $_ included in the source code?
-         */
-        boolean hasIt = (prog.indexOf(Javac.resultVarName) >= 0);
-        if (!hasIt && retType != CtClass.voidType)
-            throw new CannotCompileException(
-                        "the resulting value is not stored in "
-                        + Javac.resultVarName);
-
-        return hasIt;
-    }
-
-    /* If isStaticCall is true, null is assigned to $0.  So $0 must
-     * be declared by calling Javac.recordParams().
-     *
-     * After executing this method, the current stack depth might
-     * be less than 0.
-     */
-    static final void storeStack(CtClass[] params, boolean isStaticCall,
-                                 int regno, Bytecode bytecode) {
-        storeStack0(0, params.length, params, regno + 1, bytecode);
-        if (isStaticCall)
-            bytecode.addOpcode(ACONST_NULL);
-
-        bytecode.addAstore(regno);
-    }
-
-    private static void storeStack0(int i, int n, CtClass[] params,
-                                    int regno, Bytecode bytecode) {
-        if (i >= n)
+      }
+      catch (NullPointerException e)
+      {
+      }
+
+      ExceptionsAttribute ea = thisMethod.getExceptionsAttribute();
+      if (ea != null)
+      {
+         String[] exceptions = ea.getExceptions();
+         if (exceptions != null)
+         {
+            int n = exceptions.length;
+            for (int i = 0; i < n; ++i)
+               try
+               {
+                  addClass(list, pool.get(exceptions[i]));
+               }
+               catch (NotFoundException e)
+               {
+               }
+         }
+      }
+
+      return (CtClass[]) list.toArray(new CtClass[list.size()]);
+   }
+
+   private static void addClass(LinkedList list, CtClass c)
+   {
+      Iterator it = list.iterator();
+      while (it.hasNext())
+         if (it.next() == c)
             return;
-        else {
-            CtClass c = params[i];
-            int size;
-            if (c instanceof CtPrimitiveType)
-                size = ((CtPrimitiveType)c).getDataSize();
-            else
-                size = 1;
-
-            storeStack0(i + 1, n, params, regno + size, bytecode);
-            bytecode.addStore(regno, c);
-        }
-    }
-
-    protected void replace0(int pos, Bytecode bytecode, int size)
-        throws BadBytecode
-    {
-        byte[] code = bytecode.get();
-        edited = true;
-        int gap = code.length - size;
-        for (int i = 0; i < size; ++i)
-            iterator.writeByte(NOP, pos + i);
-
-        if (gap > 0)
-            iterator.insertGap(pos, gap);
-
-        iterator.write(code, pos);
-        iterator.insert(bytecode.getExceptionTable(), pos);
-        maxLocals = bytecode.getMaxLocals();
-        maxStack = bytecode.getMaxStack();
-    }
+
+      list.add(c);
+   }
+
+   /**
+    * Returns the index of the bytecode corresponding to the
+    * expression.
+    * It is the index into the byte array containing the Java bytecode
+    * that implements the method.
+    */
+   public int indexOfBytecode()
+   {
+      return currentPos;
+   }
+
+   /**
+    * Returns the line number of the source line containing the
+    * expression.
+    *
+    * @return -1       if this information is not available.
+    */
+   public int getLineNumber()
+   {
+      return thisMethod.getLineNumber(currentPos);
+   }
+
+   /**
+    * Returns the source file containing the expression.
+    *
+    * @return null     if this information is not available.
+    */
+   public String getFileName()
+   {
+      ClassFile cf = thisClass.getClassFile2();
+      if (cf == null)
+         return null;
+      else
+         return cf.getSourceFile();
+   }
+
+   static final boolean checkResultValue(CtClass retType, String prog)
+   throws CannotCompileException
+   {
+      /* Is $_ included in the source code?
+       */
+      boolean hasIt = (prog.indexOf(Javac.resultVarName) >= 0);
+      if (!hasIt && retType != CtClass.voidType)
+         throw new CannotCompileException("the resulting value is not stored in "
+         + Javac.resultVarName);
+
+      return hasIt;
+   }
+
+   /* If isStaticCall is true, null is assigned to $0.  So $0 must
+    * be declared by calling Javac.recordParams().
+    *
+    * After executing this method, the current stack depth might
+    * be less than 0.
+    */
+   static final void storeStack(CtClass[] params, boolean isStaticCall,
+                                int regno, Bytecode bytecode)
+   {
+      storeStack0(0, params.length, params, regno + 1, bytecode);
+      if (isStaticCall)
+         bytecode.addOpcode(ACONST_NULL);
+
+      bytecode.addAstore(regno);
+   }
+
+   private static void storeStack0(int i, int n, CtClass[] params,
+                                   int regno, Bytecode bytecode)
+   {
+      if (i >= n)
+         return;
+      else
+      {
+         CtClass c = params[i];
+         int size;
+         if (c instanceof CtPrimitiveType)
+            size = ((CtPrimitiveType) c).getDataSize();
+         else
+            size = 1;
+
+         storeStack0(i + 1, n, params, regno + size, bytecode);
+         bytecode.addStore(regno, c);
+      }
+   }
+
+   protected void replace0(int pos, Bytecode bytecode, int size)
+   throws BadBytecode
+   {
+      byte[] code = bytecode.get();
+      edited = true;
+      int gap = code.length - size;
+      for (int i = 0; i < size; ++i)
+         iterator.writeByte(NOP, pos + i);
+
+      if (gap > 0)
+         iterator.insertGap(pos, gap);
+
+      iterator.write(code, pos);
+      iterator.insert(bytecode.getExceptionTable(), pos);
+      maxLocals = bytecode.getMaxLocals();
+      maxStack = bytecode.getMaxStack();
+   }
 }