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