1/*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2005 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30package org.objectweb.asm.util; 31 32import org.objectweb.asm.Opcodes; 33import org.objectweb.asm.signature.SignatureVisitor; 34 35/** 36 * A {@link SignatureVisitor} that prints a disassembled view of the signature 37 * it visits. 38 * 39 * @author Eugene Kuleshov 40 * @author Eric Bruneton 41 */ 42public class TraceSignatureVisitor implements SignatureVisitor { 43 44 private StringBuffer declaration; 45 46 private boolean isInterface; 47 48 private boolean seenFormalParameter; 49 50 private boolean seenInterfaceBound; 51 52 private boolean seenParameter; 53 54 private boolean seenInterface; 55 56 private StringBuffer returnType; 57 58 private StringBuffer exceptions; 59 60 /** 61 * Stack used to keep track of class types that have arguments. Each element 62 * of this stack is a boolean encoded in one bit. The top of the stack is 63 * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = 64 * /2. 65 */ 66 private int argumentStack; 67 68 /** 69 * Stack used to keep track of array class types. Each element of this stack 70 * is a boolean encoded in one bit. The top of the stack is the lowest order 71 * bit. Pushing false = *2, pushing true = *2+1, popping = /2. 72 */ 73 private int arrayStack; 74 75 private String separator = ""; 76 77 public TraceSignatureVisitor(int access) { 78 isInterface = (access & Opcodes.ACC_INTERFACE) != 0; 79 this.declaration = new StringBuffer(); 80 } 81 82 private TraceSignatureVisitor(StringBuffer buf) { 83 this.declaration = buf; 84 } 85 86 public void visitFormalTypeParameter(String name) { 87 declaration.append(seenFormalParameter ? ", " : "<").append(name); 88 seenFormalParameter = true; 89 seenInterfaceBound = false; 90 } 91 92 public SignatureVisitor visitClassBound() { 93 separator = " extends "; 94 startType(); 95 return this; 96 } 97 98 public SignatureVisitor visitInterfaceBound() { 99 separator = seenInterfaceBound ? ", " : " extends "; 100 seenInterfaceBound = true; 101 startType(); 102 return this; 103 } 104 105 public SignatureVisitor visitSuperclass() { 106 endFormals(); 107 separator = " extends "; 108 startType(); 109 return this; 110 } 111 112 public SignatureVisitor visitInterface() { 113 separator = seenInterface ? ", " : (isInterface 114 ? " extends " 115 : " implements "); 116 seenInterface = true; 117 startType(); 118 return this; 119 } 120 121 public SignatureVisitor visitParameterType() { 122 endFormals(); 123 if (!seenParameter) { 124 seenParameter = true; 125 declaration.append('('); 126 } else { 127 declaration.append(", "); 128 } 129 startType(); 130 return this; 131 } 132 133 public SignatureVisitor visitReturnType() { 134 endFormals(); 135 if (!seenParameter) { 136 declaration.append('('); 137 } else { 138 seenParameter = false; 139 } 140 declaration.append(')'); 141 returnType = new StringBuffer(); 142 return new TraceSignatureVisitor(returnType); 143 } 144 145 public SignatureVisitor visitExceptionType() { 146 if (exceptions == null) { 147 exceptions = new StringBuffer(); 148 } else { 149 exceptions.append(", "); 150 } 151 // startType(); 152 return new TraceSignatureVisitor(exceptions); 153 } 154 155 public void visitBaseType(char descriptor) { 156 switch (descriptor) { 157 case 'V': 158 declaration.append("void"); 159 break; 160 case 'B': 161 declaration.append("byte"); 162 break; 163 case 'J': 164 declaration.append("long"); 165 break; 166 case 'Z': 167 declaration.append("boolean"); 168 break; 169 case 'I': 170 declaration.append("int"); 171 break; 172 case 'S': 173 declaration.append("short"); 174 break; 175 case 'C': 176 declaration.append("char"); 177 break; 178 case 'F': 179 declaration.append("float"); 180 break; 181 // case 'D': 182 default: 183 declaration.append("double"); 184 break; 185 } 186 endType(); 187 } 188 189 public void visitTypeVariable(String name) { 190 declaration.append(name); 191 endType(); 192 } 193 194 public SignatureVisitor visitArrayType() { 195 startType(); 196 arrayStack |= 1; 197 return this; 198 } 199 200 public void visitClassType(String name) { 201 if (!"java/lang/Object".equals(name)) { 202 declaration.append(separator).append(name.replace('/', '.')); 203 } else { 204 // Map<java.lang.Object,java.util.List> 205 // or 206 // abstract public V get(Object key); (seen in Dictionary.class) 207 // should have Object 208 // but java.lang.String extends java.lang.Object is unnecessary 209 boolean needObjectClass = argumentStack % 2 == 1 || seenParameter; 210 if (needObjectClass) { 211 declaration.append(separator).append(name.replace('/', '.')); 212 } 213 } 214 separator = ""; 215 argumentStack *= 2; 216 } 217 218 public void visitInnerClassType(String name) { 219 if (argumentStack % 2 == 1) { 220 declaration.append('>'); 221 } 222 argumentStack /= 2; 223 declaration.append('.'); 224 declaration.append(separator).append(name.replace('/', '.')); 225 separator = ""; 226 argumentStack *= 2; 227 } 228 229 public void visitTypeArgument() { 230 if (argumentStack % 2 == 0) { 231 ++argumentStack; 232 declaration.append('<'); 233 } else { 234 declaration.append(", "); 235 } 236 declaration.append('?'); 237 } 238 239 public SignatureVisitor visitTypeArgument(char tag) { 240 if (argumentStack % 2 == 0) { 241 ++argumentStack; 242 declaration.append('<'); 243 } else { 244 declaration.append(", "); 245 } 246 247 if (tag == SignatureVisitor.EXTENDS) { 248 declaration.append("? extends "); 249 } else if (tag == SignatureVisitor.SUPER) { 250 declaration.append("? super "); 251 } 252 253 startType(); 254 return this; 255 } 256 257 public void visitEnd() { 258 if (argumentStack % 2 == 1) { 259 declaration.append('>'); 260 } 261 argumentStack /= 2; 262 endType(); 263 } 264 265 public String getDeclaration() { 266 return declaration.toString(); 267 } 268 269 public String getReturnType() { 270 return returnType == null ? null : returnType.toString(); 271 } 272 273 public String getExceptions() { 274 return exceptions == null ? null : exceptions.toString(); 275 } 276 277 // ----------------------------------------------- 278 279 private void endFormals() { 280 if (seenFormalParameter) { 281 declaration.append('>'); 282 seenFormalParameter = false; 283 } 284 } 285 286 private void startType() { 287 arrayStack *= 2; 288 } 289 290 private void endType() { 291 if (arrayStack % 2 == 1) { 292 while (arrayStack % 2 == 1) { 293 arrayStack /= 2; 294 declaration.append("[]"); 295 } 296 } else { 297 arrayStack /= 2; 298 } 299 } 300} 301