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