• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.mkstubs.sourcer;
18 
19 import org.objectweb.asm.Opcodes;
20 import org.objectweb.asm.Type;
21 import org.objectweb.asm.signature.SignatureReader;
22 import org.objectweb.asm.signature.SignatureVisitor;
23 import org.objectweb.asm.signature.SignatureWriter;
24 
25 import java.util.ArrayList;
26 
27 /**
28  * A signature visitor that can be used to generate Java source corresponding to
29  * various types of signatures.
30  * <p/>
31  * Terminology: a "signature" is a type descriptor for generics. There are different types
32  * of signatures depending on the context where they are used, e.g. method declarations,
33  * method parameters, class declarations, etc..
34  * <p/>
35  * Note: most of the implementation is a duplicate of ASM's SignatureWriter with some
36  * slight variations.
37  * <p/>
38  * Note: When processing a method's signature, the signature order is the reverse of the source
39  * order, e.g. the signature is written as "(parameters)return-type" where we want to generate
40  * "return-type method-name (parameters)". To handle this case, the return-type and parameters
41  * are <em>not</em> output directly but are instead accumulated in internal variables that you can
42  * get later using {@link #getReturnType()}, {@link #getParameters()}, {@link #getSuperClass()}
43  * and {@link #formalsToString()}.
44  */
45 class SignatureSourcer extends SignatureVisitor {
46 
47     /**
48      * Buffer used to construct the signature.
49      */
50     private final StringBuilder mBuf = new StringBuilder();
51 
52     /**
53      * Buffer used to construct the formals signature.
54      */
55     private final StringBuilder mFormalsBuf = new StringBuilder();
56 
57     /**
58      * Indicates if the signature is currently processing formal type parameters.
59      */
60     private boolean mWritingFormals;
61 
62     /**
63      * Stack used to keep track of class types that have arguments. Each element
64      * of this stack is a boolean encoded in one bit. The top of the stack is
65      * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
66      * /2.
67      */
68     private int mArgumentStack;
69 
70     /**
71      * {@link SignatureSourcer} generated when parsing the return type of <em>this</em>
72      * signature. Initially null.
73      */
74     private SignatureSourcer mReturnType;
75 
76     /**
77      * {@link SignatureSourcer} generated when parsing the super class of <em>this</em>
78      * signature. Initially null.
79      */
80     private SignatureSourcer mSuperClass;
81 
82     /**
83      * {@link SignatureSourcer}s for each parameters generated when parsing the method parameters
84      * of <em>this</em> signature. Initially empty but not null.
85      */
86     private ArrayList<SignatureSourcer> mParameters = new ArrayList<SignatureSourcer>();
87 
88 
89 
90     /**
91      * Constructs a new {@link SignatureWriter} object.
92      */
SignatureSourcer()93     public SignatureSourcer() {
94         super(Opcodes.ASM4);
95     }
96 
getBuf()97     private StringBuilder getBuf() {
98         if (mWritingFormals) {
99             return mFormalsBuf;
100         } else {
101             return mBuf;
102         }
103     }
104 
105     /**
106      * Contains the whole signature type when called by
107      * {@link SignatureReader#acceptType(SignatureVisitor)} or just the formals if
108      * called by {@link SignatureReader#accept(SignatureVisitor)}.
109      */
110     @Override
toString()111     public String toString() {
112         return mBuf.toString();
113     }
114 
115     /**
116      * Will be non-null if a return type was processed
117      * by {@link SignatureReader#accept(SignatureVisitor)}
118      */
getReturnType()119     public SignatureSourcer getReturnType() {
120         return mReturnType;
121     }
122 
123     /**
124      * Will be non-empty if a parameters were processed
125      * by {@link SignatureReader#accept(SignatureVisitor)}
126      */
getParameters()127     public ArrayList<SignatureSourcer> getParameters() {
128         return mParameters;
129     }
130 
131     /**
132      * True if the signature contains formal type parameters, which are available
133      * via {@link #formalsToString()} after calling {@link SignatureReader#accept(SignatureVisitor)}
134      */
hasFormalsContent()135     public boolean hasFormalsContent() {
136         return mFormalsBuf.length() > 0;
137     }
138 
formalsToString()139     public String formalsToString() {
140         return mFormalsBuf.toString();
141     }
142 
143     /**
144      * Will be non-null if a super class was processed
145      * by {@link SignatureReader#accept(SignatureVisitor)}
146      */
getSuperClass()147     public SignatureSourcer getSuperClass() {
148         return mSuperClass;
149     }
150 
151     // ------------------------------------------------------------------------
152     // Implementation of the SignatureVisitor interface
153     // ------------------------------------------------------------------------
154 
155     @Override
visitFormalTypeParameter(final String name)156     public void visitFormalTypeParameter(final String name) {
157         if (!mWritingFormals) {
158             mWritingFormals = true;
159             getBuf().append('<');
160         } else {
161             getBuf().append(", ");
162         }
163         getBuf().append(name);
164         getBuf().append(" extends ");
165     }
166 
167     @Override
visitClassBound()168     public SignatureVisitor visitClassBound() {
169         // we don't differentiate between visiting a sub class or interface type
170         return this;
171     }
172 
173     @Override
visitInterfaceBound()174     public SignatureVisitor visitInterfaceBound() {
175         // we don't differentiate between visiting a sub class or interface type
176         return this;
177     }
178 
179     @Override
visitSuperclass()180     public SignatureVisitor visitSuperclass() {
181         endFormals();
182         SignatureSourcer sourcer = new SignatureSourcer();
183         assert mSuperClass == null;
184         mSuperClass = sourcer;
185         return sourcer;
186     }
187 
188     @Override
visitInterface()189     public SignatureVisitor visitInterface() {
190         return this;
191     }
192 
193     @Override
visitParameterType()194     public SignatureVisitor visitParameterType() {
195         endFormals();
196         SignatureSourcer sourcer = new SignatureSourcer();
197         mParameters.add(sourcer);
198         return sourcer;
199     }
200 
201     @Override
visitReturnType()202     public SignatureVisitor visitReturnType() {
203         endFormals();
204         SignatureSourcer sourcer = new SignatureSourcer();
205         assert mReturnType == null;
206         mReturnType = sourcer;
207         return sourcer;
208     }
209 
210     @Override
visitExceptionType()211     public SignatureVisitor visitExceptionType() {
212         getBuf().append('^');
213         return this;
214     }
215 
216     @Override
visitBaseType(final char descriptor)217     public void visitBaseType(final char descriptor) {
218         getBuf().append(Type.getType(Character.toString(descriptor)).getClassName());
219     }
220 
221     @Override
visitTypeVariable(final String name)222     public void visitTypeVariable(final String name) {
223         getBuf().append(name.replace('/', '.'));
224     }
225 
226     @Override
visitArrayType()227     public SignatureVisitor visitArrayType() {
228         getBuf().append('[');
229         return this;
230     }
231 
232     @Override
visitClassType(final String name)233     public void visitClassType(final String name) {
234         getBuf().append(name.replace('/', '.'));
235         mArgumentStack *= 2;
236     }
237 
238     @Override
visitInnerClassType(final String name)239     public void visitInnerClassType(final String name) {
240         endArguments();
241         getBuf().append('.');
242         getBuf().append(name.replace('/', '.'));
243         mArgumentStack *= 2;
244     }
245 
246     @Override
visitTypeArgument()247     public void visitTypeArgument() {
248         if (mArgumentStack % 2 == 0) {
249             ++mArgumentStack;
250             getBuf().append('<');
251         } else {
252             getBuf().append(", ");
253         }
254         getBuf().append('*');
255     }
256 
257     @Override
visitTypeArgument(final char wildcard)258     public SignatureVisitor visitTypeArgument(final char wildcard) {
259         if (mArgumentStack % 2 == 0) {
260             ++mArgumentStack;
261             getBuf().append('<');
262         } else {
263             getBuf().append(", ");
264         }
265         if (wildcard != '=') {
266             if (wildcard == '+') {
267                 getBuf().append("? extends ");
268             } else if (wildcard == '-') {
269                 getBuf().append("? super ");
270             } else {
271                 // can this happen?
272                 getBuf().append(wildcard);
273             }
274         }
275         return this;
276     }
277 
278     @Override
visitEnd()279     public void visitEnd() {
280         endArguments();
281     }
282 
283     // ------------------------------------------------------------------------
284     // Utility methods
285     // ------------------------------------------------------------------------
286 
287     /**
288      * Ends the formal type parameters section of the signature.
289      */
endFormals()290     private void endFormals() {
291         if (mWritingFormals) {
292             getBuf().append('>');
293             mWritingFormals = false;
294         }
295     }
296 
297     /**
298      * Ends the type arguments of a class or inner class type.
299      */
endArguments()300     private void endArguments() {
301         if (mArgumentStack % 2 != 0) {
302             getBuf().append('>');
303         }
304         mArgumentStack /= 2;
305     }
306 }
307