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