2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.tools.layoutlib.create;
19 import org.objectweb.asm.AnnotationVisitor;
20 import org.objectweb.asm.ClassAdapter;
21 import org.objectweb.asm.ClassWriter;
22 import org.objectweb.asm.FieldVisitor;
23 import org.objectweb.asm.Label;
24 import org.objectweb.asm.MethodAdapter;
25 import org.objectweb.asm.MethodVisitor;
26 import org.objectweb.asm.Type;
27 import org.objectweb.asm.signature.SignatureReader;
28 import org.objectweb.asm.signature.SignatureVisitor;
29 import org.objectweb.asm.signature.SignatureWriter;
32 * This class visitor renames a class from a given old name to a given new name.
33 * The class visitor will also rename all inner classes and references in the methods.
36 * For inner classes, this handles only the case where the outer class name changes.
37 * The inner class name should remain the same.
39 public class RenameClassAdapter extends ClassAdapter {
42 private final String mOldName;
43 private final String mNewName;
44 private String mOldBase;
45 private String mNewBase;
48 * Creates a class visitor that renames a class from a given old name to a given new name.
49 * The class visitor will also rename all inner classes and references in the methods.
50 * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
52 public RenameClassAdapter(ClassWriter cv, String oldName, String newName) {
54 mOldBase = mOldName = oldName;
55 mNewBase = mNewName = newName;
57 int pos = mOldName.indexOf('$');
59 mOldBase = mOldName.substring(0, pos);
61 pos = mNewName.indexOf('$');
63 mNewBase = mNewName.substring(0, pos);
66 assert (mOldBase == null && mNewBase == null) || (mOldBase != null && mNewBase != null);
71 * Renames a type descriptor, e.g. "Lcom.package.MyClass;"
72 * If the type doesn't need to be renamed, returns the input string as-is.
74 String renameTypeDesc(String desc) {
79 return renameType(Type.getType(desc));
83 * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
84 * object element, e.g. "[Lcom.package.MyClass;"
85 * If the type doesn't need to be renamed, returns the internal name of the input type.
87 String renameType(Type type) {
92 if (type.getSort() == Type.OBJECT) {
93 String in = type.getInternalName();
94 return "L" + renameInternalType(in) + ";";
95 } else if (type.getSort() == Type.ARRAY) {
96 StringBuilder sb = new StringBuilder();
97 for (int n = type.getDimensions(); n > 0; n--) {
100 sb.append(renameType(type.getElementType()));
101 return sb.toString();
103 return type.getDescriptor();
107 * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
108 * object element, e.g. "[Lcom.package.MyClass;".
109 * This is like renameType() except that it returns a Type object.
110 * If the type doesn't need to be renamed, returns the input type object.
112 Type renameTypeAsType(Type type) {
117 if (type.getSort() == Type.OBJECT) {
118 String in = type.getInternalName();
119 String newIn = renameInternalType(in);
121 return Type.getType("L" + newIn + ";");
123 } else if (type.getSort() == Type.ARRAY) {
124 StringBuilder sb = new StringBuilder();
125 for (int n = type.getDimensions(); n > 0; n--) {
128 sb.append(renameType(type.getElementType()));
129 return Type.getType(sb.toString());
135 * Renames an internal type name, e.g. "com.package.MyClass".
136 * If the type doesn't need to be renamed, returns the input string as-is.
138 * The internal type of some of the MethodVisitor turns out to be a type
139 descriptor sometimes so descriptors are renamed too.
141 String renameInternalType(String type) {
146 if (type.equals(mOldName)) {
150 if (mOldBase != mOldName && type.equals(mOldBase)) {
154 int pos = type.indexOf('$');
155 if (pos == mOldBase.length() && type.startsWith(mOldBase)) {
156 return mNewBase + type.substring(pos);
159 // The internal type of some of the MethodVisitor turns out to be a type
160 // descriptor sometimes. This is the case with visitTypeInsn(type) and
161 // visitMethodInsn(owner). We try to detect it and adjust it here.
162 if (type.indexOf(';') > 0) {
163 type = renameTypeDesc(type);
170 * Renames a method descriptor, i.e. applies renameType to all arguments and to the
173 String renameMethodDesc(String desc) {
178 Type[] args = Type.getArgumentTypes(desc);
180 StringBuilder sb = new StringBuilder("(");
181 for (Type arg : args) {
182 String name = renameType(arg);
187 Type ret = Type.getReturnType(desc);
188 String name = renameType(ret);
191 return sb.toString();
196 * Renames the ClassSignature handled by ClassVisitor.visit
197 * or the MethodTypeSignature handled by ClassVisitor.visitMethod.
199 String renameTypeSignature(String sig) {
203 SignatureReader reader = new SignatureReader(sig);
204 SignatureWriter writer = new SignatureWriter();
205 reader.accept(new RenameSignatureAdapter(writer));
206 sig = writer.toString();
212 * Renames the FieldTypeSignature handled by ClassVisitor.visitField
213 * or MethodVisitor.visitLocalVariable.
215 String renameFieldSignature(String sig) {
219 SignatureReader reader = new SignatureReader(sig);
220 SignatureWriter writer = new SignatureWriter();
221 reader.acceptType(new RenameSignatureAdapter(writer));
222 sig = writer.toString();
227 //----------------------------------
228 // Methods from the ClassAdapter
231 public void visit(int version, int access, String name, String signature,
232 String superName, String[] interfaces) {
233 name = renameInternalType(name);
234 superName = renameInternalType(superName);
235 signature = renameTypeSignature(signature);
237 super.visit(version, access, name, signature, superName, interfaces);
241 public void visitInnerClass(String name, String outerName, String innerName, int access) {
242 assert outerName.equals(mOldName);
243 outerName = renameInternalType(outerName);
244 name = outerName + "$" + innerName;
245 super.visitInnerClass(name, outerName, innerName, access);
249 public MethodVisitor visitMethod(int access, String name, String desc,
250 String signature, String[] exceptions) {
251 desc = renameMethodDesc(desc);
252 signature = renameTypeSignature(signature);
253 MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
254 return new RenameMethodAdapter(mw);
258 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
259 desc = renameTypeDesc(desc);
260 return super.visitAnnotation(desc, visible);
264 public FieldVisitor visitField(int access, String name, String desc,
265 String signature, Object value) {
266 desc = renameTypeDesc(desc);
267 signature = renameFieldSignature(signature);
268 return super.visitField(access, name, desc, signature, value);
272 //----------------------------------
275 * A method visitor that renames all references from an old class name to a new class name.
277 public class RenameMethodAdapter extends MethodAdapter {
280 * Creates a method visitor that renames all references from a given old name to a given new
281 * name. The method visitor will also rename all inner classes.
282 * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
284 public RenameMethodAdapter(MethodVisitor mv) {
289 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
290 desc = renameTypeDesc(desc);
292 return super.visitAnnotation(desc, visible);
296 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
297 desc = renameTypeDesc(desc);
299 return super.visitParameterAnnotation(parameter, desc, visible);
303 public void visitTypeInsn(int opcode, String type) {
304 type = renameInternalType(type);
306 super.visitTypeInsn(opcode, type);
310 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
311 owner = renameInternalType(owner);
312 desc = renameTypeDesc(desc);
314 super.visitFieldInsn(opcode, owner, name, desc);
318 public void visitMethodInsn(int opcode, String owner, String name, String desc) {
319 owner = renameInternalType(owner);
320 desc = renameMethodDesc(desc);
322 super.visitMethodInsn(opcode, owner, name, desc);
326 public void visitLdcInsn(Object cst) {
327 // If cst is a Type, this means the code is trying to pull the .class constant
328 // for this class, so it needs to be renamed too.
329 if (cst instanceof Type) {
330 cst = renameTypeAsType((Type) cst);
332 super.visitLdcInsn(cst);
336 public void visitMultiANewArrayInsn(String desc, int dims) {
337 desc = renameTypeDesc(desc);
339 super.visitMultiANewArrayInsn(desc, dims);
343 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
344 type = renameInternalType(type);
346 super.visitTryCatchBlock(start, end, handler, type);
350 public void visitLocalVariable(String name, String desc, String signature,
351 Label start, Label end, int index) {
352 desc = renameTypeDesc(desc);
353 signature = renameFieldSignature(signature);
355 super.visitLocalVariable(name, desc, signature, start, end, index);
360 //----------------------------------
362 public class RenameSignatureAdapter implements SignatureVisitor {
364 private final SignatureVisitor mSv;
366 public RenameSignatureAdapter(SignatureVisitor sv) {
370 public void visitClassType(String name) {
371 name = renameInternalType(name);
372 mSv.visitClassType(name);
375 public void visitInnerClassType(String name) {
376 name = renameInternalType(name);
377 mSv.visitInnerClassType(name);
380 public SignatureVisitor visitArrayType() {
381 SignatureVisitor sv = mSv.visitArrayType();
382 return new RenameSignatureAdapter(sv);
385 public void visitBaseType(char descriptor) {
386 mSv.visitBaseType(descriptor);
389 public SignatureVisitor visitClassBound() {
390 SignatureVisitor sv = mSv.visitClassBound();
391 return new RenameSignatureAdapter(sv);
394 public void visitEnd() {
398 public SignatureVisitor visitExceptionType() {
399 SignatureVisitor sv = mSv.visitExceptionType();
400 return new RenameSignatureAdapter(sv);
403 public void visitFormalTypeParameter(String name) {
404 mSv.visitFormalTypeParameter(name);
407 public SignatureVisitor visitInterface() {
408 SignatureVisitor sv = mSv.visitInterface();
409 return new RenameSignatureAdapter(sv);
412 public SignatureVisitor visitInterfaceBound() {
413 SignatureVisitor sv = mSv.visitInterfaceBound();
414 return new RenameSignatureAdapter(sv);
417 public SignatureVisitor visitParameterType() {
418 SignatureVisitor sv = mSv.visitParameterType();
419 return new RenameSignatureAdapter(sv);
422 public SignatureVisitor visitReturnType() {
423 SignatureVisitor sv = mSv.visitReturnType();
424 return new RenameSignatureAdapter(sv);
427 public SignatureVisitor visitSuperclass() {
428 SignatureVisitor sv = mSv.visitSuperclass();
429 return new RenameSignatureAdapter(sv);
432 public void visitTypeArgument() {
433 mSv.visitTypeArgument();
436 public SignatureVisitor visitTypeArgument(char wildcard) {
437 SignatureVisitor sv = mSv.visitTypeArgument(wildcard);
438 return new RenameSignatureAdapter(sv);
441 public void visitTypeVariable(String name) {
442 mSv.visitTypeVariable(name);