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