1 /*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2007 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 */ 30 package org.mockito.asm.util; 31 32 import org.mockito.asm.Opcodes; 33 import org.mockito.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 */ 42 public class TraceSignatureVisitor implements SignatureVisitor { 43 44 private final 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 TraceSignatureVisitor(final int access)77 public TraceSignatureVisitor(final int access) { 78 isInterface = (access & Opcodes.ACC_INTERFACE) != 0; 79 this.declaration = new StringBuffer(); 80 } 81 TraceSignatureVisitor(final StringBuffer buf)82 private TraceSignatureVisitor(final StringBuffer buf) { 83 this.declaration = buf; 84 } 85 visitFormalTypeParameter(final String name)86 public void visitFormalTypeParameter(final String name) { 87 declaration.append(seenFormalParameter ? ", " : "<").append(name); 88 seenFormalParameter = true; 89 seenInterfaceBound = false; 90 } 91 visitClassBound()92 public SignatureVisitor visitClassBound() { 93 separator = " extends "; 94 startType(); 95 return this; 96 } 97 visitInterfaceBound()98 public SignatureVisitor visitInterfaceBound() { 99 separator = seenInterfaceBound ? ", " : " extends "; 100 seenInterfaceBound = true; 101 startType(); 102 return this; 103 } 104 visitSuperclass()105 public SignatureVisitor visitSuperclass() { 106 endFormals(); 107 separator = " extends "; 108 startType(); 109 return this; 110 } 111 visitInterface()112 public SignatureVisitor visitInterface() { 113 separator = seenInterface ? ", " : isInterface 114 ? " extends " 115 : " implements "; 116 seenInterface = true; 117 startType(); 118 return this; 119 } 120 visitParameterType()121 public SignatureVisitor visitParameterType() { 122 endFormals(); 123 if (seenParameter) { 124 declaration.append(", "); 125 } else { 126 seenParameter = true; 127 declaration.append('('); 128 } 129 startType(); 130 return this; 131 } 132 visitReturnType()133 public SignatureVisitor visitReturnType() { 134 endFormals(); 135 if (seenParameter) { 136 seenParameter = false; 137 } else { 138 declaration.append('('); 139 } 140 declaration.append(')'); 141 returnType = new StringBuffer(); 142 return new TraceSignatureVisitor(returnType); 143 } 144 visitExceptionType()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 visitBaseType(final char descriptor)155 public void visitBaseType(final 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 visitTypeVariable(final String name)189 public void visitTypeVariable(final String name) { 190 declaration.append(name); 191 endType(); 192 } 193 visitArrayType()194 public SignatureVisitor visitArrayType() { 195 startType(); 196 arrayStack |= 1; 197 return this; 198 } 199 visitClassType(final String name)200 public void visitClassType(final String name) { 201 if ("java/lang/Object".equals(name)) { 202 // Map<java.lang.Object,java.util.List> 203 // or 204 // abstract public V get(Object key); (seen in Dictionary.class) 205 // should have Object 206 // but java.lang.String extends java.lang.Object is unnecessary 207 boolean needObjectClass = argumentStack % 2 != 0 || seenParameter; 208 if (needObjectClass) { 209 declaration.append(separator).append(name.replace('/', '.')); 210 } 211 } else { 212 declaration.append(separator).append(name.replace('/', '.')); 213 } 214 separator = ""; 215 argumentStack *= 2; 216 } 217 visitInnerClassType(final String name)218 public void visitInnerClassType(final String name) { 219 if (argumentStack % 2 != 0) { 220 declaration.append('>'); 221 } 222 argumentStack /= 2; 223 declaration.append('.'); 224 declaration.append(separator).append(name.replace('/', '.')); 225 separator = ""; 226 argumentStack *= 2; 227 } 228 visitTypeArgument()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 visitTypeArgument(final char tag)239 public SignatureVisitor visitTypeArgument(final char tag) { 240 if (argumentStack % 2 == 0) { 241 ++argumentStack; 242 declaration.append('<'); 243 } else { 244 declaration.append(", "); 245 } 246 247 if (tag == EXTENDS) { 248 declaration.append("? extends "); 249 } else if (tag == SUPER) { 250 declaration.append("? super "); 251 } 252 253 startType(); 254 return this; 255 } 256 visitEnd()257 public void visitEnd() { 258 if (argumentStack % 2 != 0) { 259 declaration.append('>'); 260 } 261 argumentStack /= 2; 262 endType(); 263 } 264 getDeclaration()265 public String getDeclaration() { 266 return declaration.toString(); 267 } 268 getReturnType()269 public String getReturnType() { 270 return returnType == null ? null : returnType.toString(); 271 } 272 getExceptions()273 public String getExceptions() { 274 return exceptions == null ? null : exceptions.toString(); 275 } 276 277 // ----------------------------------------------- 278 endFormals()279 private void endFormals() { 280 if (seenFormalParameter) { 281 declaration.append('>'); 282 seenFormalParameter = false; 283 } 284 } 285 startType()286 private void startType() { 287 arrayStack *= 2; 288 } 289 endType()290 private void endType() { 291 if (arrayStack % 2 == 0) { 292 arrayStack /= 2; 293 } else { 294 while (arrayStack % 2 != 0) { 295 arrayStack /= 2; 296 declaration.append("[]"); 297 } 298 } 299 } 300 } 301