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 */ 92 public SignatureSourcer() { 93 } 94 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 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 */ 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 */ 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 */ 133 public boolean hasFormalsContent() { 134 return mFormalsBuf.length() > 0; 135 } 136 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 */ 145 public SignatureSourcer getSuperClass() { 146 return mSuperClass; 147 } 148 149 // ------------------------------------------------------------------------ 150 // Implementation of the SignatureVisitor interface 151 // ------------------------------------------------------------------------ 152 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 164 public SignatureVisitor visitClassBound() { 165 // we don't differentiate between visiting a sub class or interface type 166 return this; 167 } 168 169 public SignatureVisitor visitInterfaceBound() { 170 // we don't differentiate between visiting a sub class or interface type 171 return this; 172 } 173 174 public SignatureVisitor visitSuperclass() { 175 endFormals(); 176 SignatureSourcer sourcer = new SignatureSourcer(); 177 assert mSuperClass == null; 178 mSuperClass = sourcer; 179 return sourcer; 180 } 181 182 public SignatureVisitor visitInterface() { 183 return this; 184 } 185 186 public SignatureVisitor visitParameterType() { 187 endFormals(); 188 SignatureSourcer sourcer = new SignatureSourcer(); 189 mParameters.add(sourcer); 190 return sourcer; 191 } 192 193 public SignatureVisitor visitReturnType() { 194 endFormals(); 195 SignatureSourcer sourcer = new SignatureSourcer(); 196 assert mReturnType == null; 197 mReturnType = sourcer; 198 return sourcer; 199 } 200 201 public SignatureVisitor visitExceptionType() { 202 getBuf().append('^'); 203 return this; 204 } 205 206 public void visitBaseType(final char descriptor) { 207 getBuf().append(Type.getType(Character.toString(descriptor)).getClassName()); 208 } 209 210 public void visitTypeVariable(final String name) { 211 getBuf().append(name.replace('/', '.')); 212 } 213 214 public SignatureVisitor visitArrayType() { 215 getBuf().append('['); 216 return this; 217 } 218 219 public void visitClassType(final String name) { 220 getBuf().append(name.replace('/', '.')); 221 mArgumentStack *= 2; 222 } 223 224 public void visitInnerClassType(final String name) { 225 endArguments(); 226 getBuf().append('.'); 227 getBuf().append(name.replace('/', '.')); 228 mArgumentStack *= 2; 229 } 230 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 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 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 */ 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 */ 282 private void endArguments() { 283 if (mArgumentStack % 2 != 0) { 284 getBuf().append('>'); 285 } 286 mArgumentStack /= 2; 287 } 288 } 289