From d8ba90667b8d2ca3ce409d355373aecaf48ae871 Mon Sep 17 00:00:00 2001 From: chiba Date: Thu, 2 Jul 2009 11:17:17 +0000 Subject: [PATCH] fixed JIRA JASSIST-77 git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@485 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- Readme.html | 2 +- .../javassist/bytecode/AttributeInfo.java | 31 ++++- src/main/javassist/bytecode/ClassFile.java | 6 + .../javassist/bytecode/CodeAttribute.java | 9 ++ .../bytecode/LocalVariableAttribute.java | 53 +++++++- .../bytecode/LocalVariableTypeAttribute.java | 62 ++++++++++ .../bytecode/SignatureAttribute.java | 113 ++++++++++++++++++ 7 files changed, 267 insertions(+), 9 deletions(-) create mode 100644 src/main/javassist/bytecode/LocalVariableTypeAttribute.java diff --git a/Readme.html b/Readme.html index 6317e262..7d5792aa 100644 --- a/Readme.html +++ b/Readme.html @@ -283,7 +283,7 @@ see javassist.Dump.

-version 3.11

diff --git a/src/main/javassist/bytecode/AttributeInfo.java b/src/main/javassist/bytecode/AttributeInfo.java index 67d1c48e..915f291f 100644 --- a/src/main/javassist/bytecode/AttributeInfo.java +++ b/src/main/javassist/bytecode/AttributeInfo.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.util.Map; import java.util.LinkedList; import java.util.ListIterator; +import java.util.List; +import java.util.Iterator; // Note: if you define a new subclass of AttributeInfo, then // update AttributeInfo.read(), .copy(), and (maybe) write(). @@ -92,9 +94,10 @@ public class AttributeInfo { */ if (nameStr.equals(LineNumberAttribute.tag)) return new LineNumberAttribute(cp, name, in); - else if (nameStr.equals(LocalVariableAttribute.tag) - || nameStr.equals(LocalVariableAttribute.typeTag)) + else if (nameStr.equals(LocalVariableAttribute.tag)) return new LocalVariableAttribute(cp, name, in); + else if (nameStr.equals(LocalVariableTypeAttribute.tag)) + return new LocalVariableTypeAttribute(cp, name, in); else if (nameStr.equals(AnnotationsAttribute.visibleTag) || nameStr.equals(AnnotationsAttribute.invisibleTag)) { // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations @@ -243,4 +246,28 @@ public class AttributeInfo { return newList; } + + /* The following two methods are used to implement + * ClassFile.renameClass(). + * Only CodeAttribute and LocalVariableAttribute override + * this method. + */ + void renameClass(String oldname, String newname) {} + void renameClass(Map classnames) {} + + static void renameClass(List attributes, String oldname, String newname) { + Iterator iterator = attributes.iterator(); + while (iterator.hasNext()) { + AttributeInfo ai = (AttributeInfo)iterator.next(); + ai.renameClass(oldname, newname); + } + } + + static void renameClass(List attributes, Map classnames) { + Iterator iterator = attributes.iterator(); + while (iterator.hasNext()) { + AttributeInfo ai = (AttributeInfo)iterator.next(); + ai.renameClass(classnames); + } + } } diff --git a/src/main/javassist/bytecode/ClassFile.java b/src/main/javassist/bytecode/ClassFile.java index b2828f20..f03537c8 100644 --- a/src/main/javassist/bytecode/ClassFile.java +++ b/src/main/javassist/bytecode/ClassFile.java @@ -404,12 +404,14 @@ public final class ClassFile { newname = Descriptor.toJvmName(newname); constPool.renameClass(oldname, newname); + AttributeInfo.renameClass(attributes, oldname, newname); list = methods; n = list.size(); for (int i = 0; i < n; ++i) { MethodInfo minfo = (MethodInfo)list.get(i); String desc = minfo.getDescriptor(); minfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); + AttributeInfo.renameClass(minfo.getAttributes(), oldname, newname); } list = fields; @@ -418,6 +420,7 @@ public final class ClassFile { FieldInfo finfo = (FieldInfo)list.get(i); String desc = finfo.getDescriptor(); finfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); + AttributeInfo.renameClass(finfo.getAttributes(), oldname, newname); } } @@ -438,12 +441,14 @@ public final class ClassFile { constPool.renameClass(classnames); + AttributeInfo.renameClass(attributes, classnames); ArrayList list = methods; int n = list.size(); for (int i = 0; i < n; ++i) { MethodInfo minfo = (MethodInfo)list.get(i); String desc = minfo.getDescriptor(); minfo.setDescriptor(Descriptor.rename(desc, classnames)); + AttributeInfo.renameClass(minfo.getAttributes(), classnames); } list = fields; @@ -452,6 +457,7 @@ public final class ClassFile { FieldInfo finfo = (FieldInfo)list.get(i); String desc = finfo.getDescriptor(); finfo.setDescriptor(Descriptor.rename(desc, classnames)); + AttributeInfo.renameClass(finfo.getAttributes(), classnames); } } diff --git a/src/main/javassist/bytecode/CodeAttribute.java b/src/main/javassist/bytecode/CodeAttribute.java index 34a4fa5b..0f81ae59 100644 --- a/src/main/javassist/bytecode/CodeAttribute.java +++ b/src/main/javassist/bytecode/CodeAttribute.java @@ -20,6 +20,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.List; import java.util.LinkedList; +import java.util.Iterator; import java.util.Map; /** @@ -191,6 +192,14 @@ public class CodeAttribute extends AttributeInfo implements Opcode { throw new UnsupportedOperationException("CodeAttribute.set()"); } + void renameClass(String oldname, String newname) { + AttributeInfo.renameClass(attributes, oldname, newname); + } + + void renameClass(Map classnames) { + AttributeInfo.renameClass(attributes, classnames); + } + /** * Returns the name of the class declaring the method including * this code attribute. diff --git a/src/main/javassist/bytecode/LocalVariableAttribute.java b/src/main/javassist/bytecode/LocalVariableAttribute.java index 80f96533..d01aa408 100644 --- a/src/main/javassist/bytecode/LocalVariableAttribute.java +++ b/src/main/javassist/bytecode/LocalVariableAttribute.java @@ -20,8 +20,7 @@ import java.io.IOException; import java.util.Map; /** - * LocalVariableTable_attribute or - * LocalVariableTypeTable_attribute. + * LocalVariableTable_attribute. */ public class LocalVariableAttribute extends AttributeInfo { /** @@ -38,7 +37,8 @@ public class LocalVariableAttribute extends AttributeInfo { * Constructs an empty LocalVariableTable. */ public LocalVariableAttribute(ConstPool cp) { - this(cp, tag); + super(cp, tag, new byte[2]); + ByteArray.write16bit(0, info, 0); } /** @@ -50,6 +50,7 @@ public class LocalVariableAttribute extends AttributeInfo { * @see #tag * @see #typeTag * @since 3.1 + * @deprecated */ public LocalVariableAttribute(ConstPool cp, String name) { super(cp, name, new byte[2]); @@ -62,7 +63,7 @@ public class LocalVariableAttribute extends AttributeInfo { super(cp, n, in); } - private LocalVariableAttribute(ConstPool cp, String name, byte[] i) { + LocalVariableAttribute(ConstPool cp, String name, byte[] i) { super(cp, name, i); } @@ -91,6 +92,42 @@ public class LocalVariableAttribute extends AttributeInfo { info = newInfo; } + void renameClass(String oldname, String newname) { + ConstPool cp = getConstPool(); + int n = tableLength(); + for (int i = 0; i < n; ++i) { + int pos = i * 10 + 2; + int index = ByteArray.readU16bit(info, pos + 6); + if (index != 0) { + String desc = cp.getUtf8Info(index); + desc = renameEntry(desc, oldname, newname); + ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6); + } + } + } + + String renameEntry(String desc, String oldname, String newname) { + return Descriptor.rename(desc, oldname, newname); + } + + void renameClass(Map classnames) { + ConstPool cp = getConstPool(); + int n = tableLength(); + for (int i = 0; i < n; ++i) { + int pos = i * 10 + 2; + int index = ByteArray.readU16bit(info, pos + 6); + if (index != 0) { + String desc = cp.getUtf8Info(index); + desc = renameEntry(desc, classnames); + ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6); + } + } + } + + String renameEntry(String desc, Map classnames) { + return Descriptor.rename(desc, classnames); + } + /** * For each local_variable_table[i].index, * this method increases index by delta. @@ -257,8 +294,7 @@ public class LocalVariableAttribute extends AttributeInfo { byte[] src = get(); byte[] dest = new byte[src.length]; ConstPool cp = getConstPool(); - LocalVariableAttribute attr - = new LocalVariableAttribute(newCp, getName(), dest); + LocalVariableAttribute attr = makeThisAttr(newCp, dest); int n = ByteArray.readU16bit(src, 0); ByteArray.write16bit(n, dest, 0); int j = 2; @@ -289,4 +325,9 @@ public class LocalVariableAttribute extends AttributeInfo { return attr; } + + // LocalVariableTypeAttribute overrides this method. + LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) { + return new LocalVariableAttribute(cp, tag, dest); + } } diff --git a/src/main/javassist/bytecode/LocalVariableTypeAttribute.java b/src/main/javassist/bytecode/LocalVariableTypeAttribute.java new file mode 100644 index 00000000..d7ac098b --- /dev/null +++ b/src/main/javassist/bytecode/LocalVariableTypeAttribute.java @@ -0,0 +1,62 @@ +/* + * Javassist, a Java-bytecode translator toolkit. + * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. Alternatively, the contents of this file may be used under + * the terms of the GNU Lesser General Public License Version 2.1 or later. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + */ + +package javassist.bytecode; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Map; + +/** + * LocalVariableTypeTable_attribute. + * + * @since 3.11 + */ +public class LocalVariableTypeAttribute extends LocalVariableAttribute { + /** + * The name of the attribute "LocalVariableTypeTable". + */ + public static final String tag = LocalVariableAttribute.typeTag; + + /** + * Constructs an empty LocalVariableTypeTable. + */ + public LocalVariableTypeAttribute(ConstPool cp) { + super(cp, tag, new byte[2]); + ByteArray.write16bit(0, info, 0); + } + + LocalVariableTypeAttribute(ConstPool cp, int n, DataInputStream in) + throws IOException + { + super(cp, n, in); + } + + private LocalVariableTypeAttribute(ConstPool cp, byte[] dest) { + super(cp, tag, dest); + } + + String renameEntry(String desc, String oldname, String newname) { + return SignatureAttribute.renameClass(desc, oldname, newname); + } + + String renameEntry(String desc, Map classnames) { + return SignatureAttribute.renameClass(desc, classnames); + } + + LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) { + return new LocalVariableTypeAttribute(cp, dest); + } +} diff --git a/src/main/javassist/bytecode/SignatureAttribute.java b/src/main/javassist/bytecode/SignatureAttribute.java index 2c8f0e9b..267098f8 100644 --- a/src/main/javassist/bytecode/SignatureAttribute.java +++ b/src/main/javassist/bytecode/SignatureAttribute.java @@ -61,6 +61,18 @@ public class SignatureAttribute extends AttributeInfo { return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0)); } + /** + * Sets signature_index to the index of the given signature, + * which is added to a constant pool. + * + * @param sig new signature. + * @since 3.11 + */ + public void setSignature(String sig) { + int index = getConstPool().addUtf8Info(sig); + ByteArray.write16bit(index, info, 0); + } + /** * Makes a copy. Class names are replaced according to the * given Map object. @@ -73,6 +85,107 @@ public class SignatureAttribute extends AttributeInfo { return new SignatureAttribute(newCp, getSignature()); } + void renameClass(String oldname, String newname) { + String sig = renameClass(getSignature(), oldname, newname); + setSignature(sig); + } + + void renameClass(Map classnames) { + String sig = renameClass(getSignature(), classnames); + setSignature(sig); + } + + static String renameClass(String desc, String oldname, String newname) { + if (desc.indexOf(oldname) < 0) + return desc; + + StringBuffer newdesc = new StringBuffer(); + int head = 0; + int i = 0; + for (;;) { + int j = desc.indexOf('L', i); + if (j < 0) + break; + + int k = j; + int p = 0; + char c; + boolean match = true; + try { + int len = oldname.length(); + while (isNamePart(c = desc.charAt(++k))) + if (p >= len || c != oldname.charAt(p++)) + match = false; + } + catch (IndexOutOfBoundsException e) { break; } + i = k + 1; + if (match && p == oldname.length()) { + newdesc.append(desc.substring(head, j)); + newdesc.append('L'); + newdesc.append(newname); + newdesc.append(c); + head = i; + } + } + + if (head == 0) + return desc; + else { + int len = desc.length(); + if (head < len) + newdesc.append(desc.substring(head, len)); + + return newdesc.toString(); + } + } + + static String renameClass(String desc, Map map) { + if (map == null) + return desc; + + StringBuffer newdesc = new StringBuffer(); + int head = 0; + int i = 0; + for (;;) { + int j = desc.indexOf('L', i); + if (j < 0) + break; + + StringBuffer nameBuf = new StringBuffer(); + int k = j; + char c; + try { + while (isNamePart(c = desc.charAt(++k))) + nameBuf.append(c); + } + catch (IndexOutOfBoundsException e) { break; } + i = k + 1; + String name = nameBuf.toString(); + String name2 = (String)map.get(name); + if (name2 != null) { + newdesc.append(desc.substring(head, j)); + newdesc.append('L'); + newdesc.append(name2); + newdesc.append(c); + head = i; + } + } + + if (head == 0) + return desc; + else { + int len = desc.length(); + if (head < len) + newdesc.append(desc.substring(head, len)); + + return newdesc.toString(); + } + } + + private static boolean isNamePart(int c) { + return c != ';' && c != '<'; + } + static private class Cursor { int position = 0; -- 2.39.5