001: /***
002: * ASM: a very small and fast Java bytecode manipulation framework
003: * Copyright (c) 2000-2005 INRIA, France Telecom
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */package com.tc.asm.util;
030:
031: import com.tc.asm.Opcodes;
032: import com.tc.asm.signature.SignatureVisitor;
033:
034: /**
035: * A {@link SignatureVisitor} that prints a disassembled view of the signature
036: * it visits.
037: *
038: * @author Eugene Kuleshov
039: * @author Eric Bruneton
040: */
041: public class TraceSignatureVisitor implements SignatureVisitor {
042:
043: private StringBuffer declaration;
044:
045: private boolean isInterface;
046:
047: private boolean seenFormalParameter;
048:
049: private boolean seenInterfaceBound;
050:
051: private boolean seenParameter;
052:
053: private boolean seenInterface;
054:
055: private StringBuffer returnType;
056:
057: private StringBuffer exceptions;
058:
059: /**
060: * Stack used to keep track of class types that have arguments. Each element
061: * of this stack is a boolean encoded in one bit. The top of the stack is
062: * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
063: * /2.
064: */
065: private int argumentStack;
066:
067: /**
068: * Stack used to keep track of array class types. Each element of this stack
069: * is a boolean encoded in one bit. The top of the stack is the lowest order
070: * bit. Pushing false = *2, pushing true = *2+1, popping = /2.
071: */
072: private int arrayStack;
073:
074: private String separator = "";
075:
076: public TraceSignatureVisitor(final int access) {
077: isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
078: this .declaration = new StringBuffer();
079: }
080:
081: private TraceSignatureVisitor(final StringBuffer buf) {
082: this .declaration = buf;
083: }
084:
085: public void visitFormalTypeParameter(final String name) {
086: declaration.append(seenFormalParameter ? ", " : "<").append(
087: name);
088: seenFormalParameter = true;
089: seenInterfaceBound = false;
090: }
091:
092: public SignatureVisitor visitClassBound() {
093: separator = " extends ";
094: startType();
095: return this ;
096: }
097:
098: public SignatureVisitor visitInterfaceBound() {
099: 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 ? " extends "
114: : " implements ";
115: seenInterface = true;
116: startType();
117: return this ;
118: }
119:
120: public SignatureVisitor visitParameterType() {
121: endFormals();
122: if (!seenParameter) {
123: seenParameter = true;
124: declaration.append('(');
125: } else {
126: declaration.append(", ");
127: }
128: startType();
129: return this ;
130: }
131:
132: public SignatureVisitor visitReturnType() {
133: endFormals();
134: if (!seenParameter) {
135: declaration.append('(');
136: } else {
137: seenParameter = false;
138: }
139: declaration.append(')');
140: returnType = new StringBuffer();
141: return new TraceSignatureVisitor(returnType);
142: }
143:
144: public SignatureVisitor visitExceptionType() {
145: if (exceptions == null) {
146: exceptions = new StringBuffer();
147: } else {
148: exceptions.append(", ");
149: }
150: // startType();
151: return new TraceSignatureVisitor(exceptions);
152: }
153:
154: public void visitBaseType(final char descriptor) {
155: switch (descriptor) {
156: case 'V':
157: declaration.append("void");
158: break;
159: case 'B':
160: declaration.append("byte");
161: break;
162: case 'J':
163: declaration.append("long");
164: break;
165: case 'Z':
166: declaration.append("boolean");
167: break;
168: case 'I':
169: declaration.append("int");
170: break;
171: case 'S':
172: declaration.append("short");
173: break;
174: case 'C':
175: declaration.append("char");
176: break;
177: case 'F':
178: declaration.append("float");
179: break;
180: // case 'D':
181: default:
182: declaration.append("double");
183: break;
184: }
185: endType();
186: }
187:
188: public void visitTypeVariable(final String name) {
189: declaration.append(name);
190: endType();
191: }
192:
193: public SignatureVisitor visitArrayType() {
194: startType();
195: arrayStack |= 1;
196: return this ;
197: }
198:
199: public void visitClassType(final String name) {
200: if (!"java/lang/Object".equals(name)) {
201: declaration.append(separator)
202: .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 != 0
210: || seenParameter;
211: if (needObjectClass) {
212: declaration.append(separator).append(
213: name.replace('/', '.'));
214: }
215: }
216: separator = "";
217: argumentStack *= 2;
218: }
219:
220: public void visitInnerClassType(final String name) {
221: if (argumentStack % 2 != 0) {
222: declaration.append('>');
223: }
224: argumentStack /= 2;
225: declaration.append('.');
226: declaration.append(separator).append(name.replace('/', '.'));
227: separator = "";
228: argumentStack *= 2;
229: }
230:
231: public void visitTypeArgument() {
232: if (argumentStack % 2 == 0) {
233: ++argumentStack;
234: declaration.append('<');
235: } else {
236: declaration.append(", ");
237: }
238: declaration.append('?');
239: }
240:
241: public SignatureVisitor visitTypeArgument(final char tag) {
242: if (argumentStack % 2 == 0) {
243: ++argumentStack;
244: declaration.append('<');
245: } else {
246: declaration.append(", ");
247: }
248:
249: if (tag == SignatureVisitor.EXTENDS) {
250: declaration.append("? extends ");
251: } else if (tag == SignatureVisitor.SUPER) {
252: declaration.append("? super ");
253: }
254:
255: startType();
256: return this ;
257: }
258:
259: public void visitEnd() {
260: if (argumentStack % 2 != 0) {
261: declaration.append('>');
262: }
263: argumentStack /= 2;
264: endType();
265: }
266:
267: public String getDeclaration() {
268: return declaration.toString();
269: }
270:
271: public String getReturnType() {
272: return returnType == null ? null : returnType.toString();
273: }
274:
275: public String getExceptions() {
276: return exceptions == null ? null : exceptions.toString();
277: }
278:
279: // -----------------------------------------------
280:
281: private void endFormals() {
282: if (seenFormalParameter) {
283: declaration.append('>');
284: seenFormalParameter = false;
285: }
286: }
287:
288: private void startType() {
289: arrayStack *= 2;
290: }
291:
292: private void endType() {
293: if (arrayStack % 2 != 0) {
294: while (arrayStack % 2 != 0) {
295: arrayStack /= 2;
296: declaration.append("[]");
297: }
298: } else {
299: arrayStack /= 2;
300: }
301: }
302: }
|