OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / tools / layoutlib / create / src / com / android / tools / layoutlib / create / RenameClassAdapter.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.android.tools.layoutlib.create;
18
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;
30
31 /**
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.
34  * <p/>
35  * 
36  * For inner classes, this handles only the case where the outer class name changes.
37  * The inner class name should remain the same. 
38  */
39 public class RenameClassAdapter extends ClassAdapter {
40
41     
42     private final String mOldName;
43     private final String mNewName;
44     private String mOldBase;
45     private String mNewBase;
46
47     /**
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).
51      */
52     public RenameClassAdapter(ClassWriter cv, String oldName, String newName) {
53         super(cv);
54         mOldBase = mOldName = oldName;
55         mNewBase = mNewName = newName;
56         
57         int pos = mOldName.indexOf('$');
58         if (pos > 0) {
59             mOldBase = mOldName.substring(0, pos);
60         }
61         pos = mNewName.indexOf('$');
62         if (pos > 0) {
63             mNewBase = mNewName.substring(0, pos);
64         }
65         
66         assert (mOldBase == null && mNewBase == null) || (mOldBase != null && mNewBase != null);
67     }
68
69
70     /**
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.
73      */
74     String renameTypeDesc(String desc) {
75         if (desc == null) {
76             return null;
77         }
78
79         return renameType(Type.getType(desc));
80     }
81     
82     /**
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.
86      */
87     String renameType(Type type) {
88         if (type == null) {
89             return null;
90         }
91
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--) {
98                 sb.append('[');
99             }
100             sb.append(renameType(type.getElementType()));
101             return sb.toString();
102         }
103         return type.getDescriptor();
104     }
105
106     /**
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.
111      */
112     Type renameTypeAsType(Type type) {
113         if (type == null) {
114             return null;
115         }
116
117         if (type.getSort() == Type.OBJECT) {
118             String in = type.getInternalName();
119             String newIn = renameInternalType(in);
120             if (newIn != in) {
121                 return Type.getType("L" + newIn + ";");
122             }
123         } else if (type.getSort() == Type.ARRAY) {
124             StringBuilder sb = new StringBuilder();
125             for (int n = type.getDimensions(); n > 0; n--) {
126                 sb.append('[');
127             }
128             sb.append(renameType(type.getElementType()));
129             return Type.getType(sb.toString());
130         }
131         return type;
132     }
133
134     /**
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.
137      * <p/>
138      * The internal type of some of the MethodVisitor turns out to be a type
139        descriptor sometimes so descriptors are renamed too.
140      */
141     String renameInternalType(String type) {
142         if (type == null) {
143             return null;
144         }
145
146         if (type.equals(mOldName)) {
147             return mNewName;
148         }
149
150         if (mOldBase != mOldName && type.equals(mOldBase)) {
151             return mNewBase;
152         }
153     
154         int pos = type.indexOf('$');
155         if (pos == mOldBase.length() && type.startsWith(mOldBase)) {
156             return mNewBase + type.substring(pos);
157         }
158
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);
164         }
165
166         return type;
167     }
168
169     /**
170      * Renames a method descriptor, i.e. applies renameType to all arguments and to the
171      * return value.
172      */
173     String renameMethodDesc(String desc) {
174         if (desc == null) {
175             return null;
176         }
177
178         Type[] args = Type.getArgumentTypes(desc);
179
180         StringBuilder sb = new StringBuilder("(");
181         for (Type arg : args) {
182             String name = renameType(arg);
183             sb.append(name);
184         }
185         sb.append(')');
186         
187         Type ret = Type.getReturnType(desc);
188         String name = renameType(ret);
189         sb.append(name);
190
191         return sb.toString();
192     }
193
194     
195     /**
196      * Renames the ClassSignature handled by ClassVisitor.visit 
197      * or the MethodTypeSignature handled by ClassVisitor.visitMethod.
198      */
199     String renameTypeSignature(String sig) {
200         if (sig == null) {
201             return null;
202         }
203         SignatureReader reader = new SignatureReader(sig);
204         SignatureWriter writer = new SignatureWriter();
205         reader.accept(new RenameSignatureAdapter(writer));
206         sig = writer.toString();
207         return sig;
208     }
209
210     
211     /**
212      * Renames the FieldTypeSignature handled by ClassVisitor.visitField
213      * or MethodVisitor.visitLocalVariable.
214      */
215     String renameFieldSignature(String sig) {
216         if (sig == null) {
217             return null;
218         }
219         SignatureReader reader = new SignatureReader(sig);
220         SignatureWriter writer = new SignatureWriter();
221         reader.acceptType(new RenameSignatureAdapter(writer));
222         sig = writer.toString();
223         return sig;
224     }
225
226     
227     //----------------------------------
228     // Methods from the ClassAdapter
229     
230     @Override
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);
236         
237         super.visit(version, access, name, signature, superName, interfaces);
238     }
239
240     @Override
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);
246     }
247
248     @Override
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);
255     }
256
257     @Override
258     public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
259         desc = renameTypeDesc(desc);
260         return super.visitAnnotation(desc, visible);
261     }
262     
263     @Override
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);
269     }
270     
271     
272     //----------------------------------
273
274     /**
275      * A method visitor that renames all references from an old class name to a new class name.
276      */
277     public class RenameMethodAdapter extends MethodAdapter {
278
279         /**
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).
283          */
284         public RenameMethodAdapter(MethodVisitor mv) {
285             super(mv);
286         }
287
288         @Override
289         public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
290             desc = renameTypeDesc(desc);
291             
292             return super.visitAnnotation(desc, visible);
293         }
294
295         @Override
296         public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
297             desc = renameTypeDesc(desc);
298
299             return super.visitParameterAnnotation(parameter, desc, visible);
300         }
301
302         @Override
303         public void visitTypeInsn(int opcode, String type) {
304             type = renameInternalType(type);
305             
306             super.visitTypeInsn(opcode, type);
307         }
308
309         @Override
310         public void visitFieldInsn(int opcode, String owner, String name, String desc) {
311             owner = renameInternalType(owner);
312             desc = renameTypeDesc(desc);
313
314             super.visitFieldInsn(opcode, owner, name, desc);
315         }
316
317         @Override
318         public void visitMethodInsn(int opcode, String owner, String name, String desc) {
319             owner = renameInternalType(owner);
320             desc = renameMethodDesc(desc);
321
322             super.visitMethodInsn(opcode, owner, name, desc);
323         }
324         
325         @Override
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);
331             }
332             super.visitLdcInsn(cst);
333         }
334
335         @Override
336         public void visitMultiANewArrayInsn(String desc, int dims) {
337             desc = renameTypeDesc(desc);
338          
339             super.visitMultiANewArrayInsn(desc, dims);
340         }
341
342         @Override
343         public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
344             type = renameInternalType(type);
345             
346             super.visitTryCatchBlock(start, end, handler, type);
347         }
348
349         @Override
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);
354             
355             super.visitLocalVariable(name, desc, signature, start, end, index);
356         }
357
358     }
359
360     //----------------------------------
361     
362     public class RenameSignatureAdapter implements SignatureVisitor {
363
364         private final SignatureVisitor mSv;
365
366         public RenameSignatureAdapter(SignatureVisitor sv) {
367             mSv = sv;
368         }
369
370         public void visitClassType(String name) {
371             name = renameInternalType(name);
372             mSv.visitClassType(name);
373         }
374
375         public void visitInnerClassType(String name) {
376             name = renameInternalType(name);
377             mSv.visitInnerClassType(name);
378         }
379
380         public SignatureVisitor visitArrayType() {
381             SignatureVisitor sv = mSv.visitArrayType();
382             return new RenameSignatureAdapter(sv);
383         }
384
385         public void visitBaseType(char descriptor) {
386             mSv.visitBaseType(descriptor);
387         }
388
389         public SignatureVisitor visitClassBound() {
390             SignatureVisitor sv = mSv.visitClassBound();
391             return new RenameSignatureAdapter(sv);
392         }
393
394         public void visitEnd() {
395             mSv.visitEnd();
396         }
397
398         public SignatureVisitor visitExceptionType() {
399             SignatureVisitor sv = mSv.visitExceptionType();
400             return new RenameSignatureAdapter(sv);
401         }
402
403         public void visitFormalTypeParameter(String name) {
404             mSv.visitFormalTypeParameter(name);
405         }
406
407         public SignatureVisitor visitInterface() {
408             SignatureVisitor sv = mSv.visitInterface();
409             return new RenameSignatureAdapter(sv);
410         }
411
412         public SignatureVisitor visitInterfaceBound() {
413             SignatureVisitor sv = mSv.visitInterfaceBound();
414             return new RenameSignatureAdapter(sv);
415         }
416
417         public SignatureVisitor visitParameterType() {
418             SignatureVisitor sv = mSv.visitParameterType();
419             return new RenameSignatureAdapter(sv);
420         }
421
422         public SignatureVisitor visitReturnType() {
423             SignatureVisitor sv = mSv.visitReturnType();
424             return new RenameSignatureAdapter(sv);
425         }
426
427         public SignatureVisitor visitSuperclass() {
428             SignatureVisitor sv = mSv.visitSuperclass();
429             return new RenameSignatureAdapter(sv);
430         }
431
432         public void visitTypeArgument() {
433             mSv.visitTypeArgument();
434         }
435
436         public SignatureVisitor visitTypeArgument(char wildcard) {
437             SignatureVisitor sv = mSv.visitTypeArgument(wildcard);
438             return new RenameSignatureAdapter(sv);
439         }
440
441         public void visitTypeVariable(String name) {
442             mSv.visitTypeVariable(name);
443         }
444         
445     }
446 }