OSDN Git Service

LayoutLib: import of the GB layoutlib.
[android-x86/frameworks-base.git] / tools / layoutlib / create / src / com / android / tools / layoutlib / create / TransformClassAdapter.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.ClassAdapter;
20 import org.objectweb.asm.ClassVisitor;
21 import org.objectweb.asm.FieldVisitor;
22 import org.objectweb.asm.MethodVisitor;
23 import org.objectweb.asm.Opcodes;
24 import org.objectweb.asm.Type;
25
26 import java.util.Set;
27
28 /**
29  * Class adapter that can stub some or all of the methods of the class.
30  */
31 class TransformClassAdapter extends ClassAdapter {
32
33     /** True if all methods should be stubbed, false if only native ones must be stubbed. */
34     private final boolean mStubAll;
35     /** True if the class is an interface. */
36     private boolean mIsInterface;
37     private final String mClassName;
38     private final Log mLog;
39     private final Set<String> mStubMethods;
40     private Set<String> mDeleteReturns;
41
42     /**
43      * Creates a new class adapter that will stub some or all methods.
44      * @param logger
45      * @param stubMethods  list of method signatures to always stub out
46      * @param deleteReturns list of types that trigger the deletion of methods returning them.
47      * @param className The name of the class being modified
48      * @param cv The parent class writer visitor
49      * @param stubNativesOnly True if only native methods should be stubbed. False if all
50      *                        methods should be stubbed.
51      * @param hasNative True if the method has natives, in which case its access should be
52      *                  changed.
53      */
54     public TransformClassAdapter(Log logger, Set<String> stubMethods,
55             Set<String> deleteReturns, String className, ClassVisitor cv,
56             boolean stubNativesOnly, boolean hasNative) {
57         super(cv);
58         mLog = logger;
59         mStubMethods = stubMethods;
60         mClassName = className;
61         mStubAll = !stubNativesOnly;
62         mIsInterface = false;
63         mDeleteReturns = deleteReturns;
64     }
65
66     /* Visits the class header. */
67     @Override
68     public void visit(int version, int access, String name,
69             String signature, String superName, String[] interfaces) {
70
71         // This class might be being renamed.
72         name = mClassName;
73
74         // remove protected or private and set as public
75         access = access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
76         access |= Opcodes.ACC_PUBLIC;
77         // remove final
78         access = access & ~Opcodes.ACC_FINAL;
79         // note: leave abstract classes as such
80         // don't try to implement stub for interfaces
81
82         mIsInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
83         super.visit(version, access, name, signature, superName, interfaces);
84     }
85
86     /* Visits the header of an inner class. */
87     @Override
88     public void visitInnerClass(String name, String outerName, String innerName, int access) {
89         // remove protected or private and set as public
90         access = access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
91         access |= Opcodes.ACC_PUBLIC;
92         // remove final
93         access = access & ~Opcodes.ACC_FINAL;
94         // note: leave abstract classes as such
95         // don't try to implement stub for interfaces
96
97         super.visitInnerClass(name, outerName, innerName, access);
98     }
99
100     /* Visits a method. */
101     @Override
102     public MethodVisitor visitMethod(int access, String name, String desc,
103             String signature, String[] exceptions) {
104
105         if (mDeleteReturns != null) {
106             Type t = Type.getReturnType(desc);
107             if (t.getSort() == Type.OBJECT) {
108                 String returnType = t.getInternalName();
109                 if (returnType != null) {
110                     if (mDeleteReturns.contains(returnType)) {
111                         return null;
112                     }
113                 }
114             }
115         }
116
117         String methodSignature = mClassName.replace('/', '.') + "#" + name;
118
119         // change access to public
120         access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE);
121         access |= Opcodes.ACC_PUBLIC;
122
123         // remove final
124         access = access & ~Opcodes.ACC_FINAL;
125
126         // stub this method if they are all to be stubbed or if it is a native method
127         // and don't try to stub interfaces nor abstract non-native methods.
128         if (!mIsInterface &&
129             ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) != Opcodes.ACC_ABSTRACT) &&
130             (mStubAll ||
131              (access & Opcodes.ACC_NATIVE) != 0) ||
132              mStubMethods.contains(methodSignature)) {
133
134             boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
135             boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
136
137             // remove abstract, final and native
138             access = access & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_FINAL | Opcodes.ACC_NATIVE);
139
140             String invokeSignature = methodSignature + desc;
141             mLog.debug("  Stub: %s (%s)", invokeSignature, isNative ? "native" : "");
142
143             MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
144             return new StubMethodAdapter(mw, name, returnType(desc), invokeSignature,
145                     isStatic, isNative);
146
147         } else {
148             mLog.debug("  Keep: %s %s", name, desc);
149             return super.visitMethod(access, name, desc, signature, exceptions);
150         }
151     }
152
153     /* Visits a field. Makes it public. */
154     @Override
155     public FieldVisitor visitField(int access, String name, String desc, String signature,
156             Object value) {
157         // change access to public
158         access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE);
159         access |= Opcodes.ACC_PUBLIC;
160
161         return super.visitField(access, name, desc, signature, value);
162     }
163
164     /**
165      * Extracts the return {@link Type} of this descriptor.
166      */
167     Type returnType(String desc) {
168         if (desc != null) {
169             try {
170                 return Type.getReturnType(desc);
171             } catch (ArrayIndexOutOfBoundsException e) {
172                 // ignore, not a valid type.
173             }
174         }
175         return null;
176     }
177 }