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