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 org.drools.asm.util;
030:
031: import org.drools.asm.Opcodes;
032: import org.drools.asm.signature.SignatureVisitor;
033:
034: public class TraceSignatureVisitor implements SignatureVisitor {
035:
036: private StringBuffer declaration;
037:
038: private boolean isInterface;
039:
040: private boolean seenFormalParameter;
041:
042: private boolean seenInterfaceBound;
043:
044: private boolean seenParameter;
045:
046: private boolean seenInterface;
047:
048: private StringBuffer returnType;
049:
050: private StringBuffer exceptions;
051:
052: /**
053: * Stack used to keep track of class types that have arguments. Each element
054: * of this stack is a boolean encoded in one bit. The top of the stack is
055: * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
056: * /2.
057: */
058: private int argumentStack;
059:
060: /**
061: * Stack used to keep track of array class types. Each element of this stack
062: * is a boolean encoded in one bit. The top of the stack is the lowest order
063: * bit. Pushing false = *2, pushing true = *2+1, popping = /2.
064: */
065: private int arrayStack;
066:
067: private String separator = "";
068:
069: public TraceSignatureVisitor(final int access) {
070: this .isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
071: this .declaration = new StringBuffer();
072: }
073:
074: private TraceSignatureVisitor(final StringBuffer buf) {
075: this .declaration = buf;
076: }
077:
078: public void visitFormalTypeParameter(final String name) {
079: this .declaration.append(this .seenFormalParameter ? ", " : "<")
080: .append(name);
081: this .seenFormalParameter = true;
082: this .seenInterfaceBound = false;
083: }
084:
085: public SignatureVisitor visitClassBound() {
086: this .separator = " extends ";
087: startType();
088: return this ;
089: }
090:
091: public SignatureVisitor visitInterfaceBound() {
092: this .separator = this .seenInterfaceBound ? ", " : " extends ";
093: this .seenInterfaceBound = true;
094: startType();
095: return this ;
096: }
097:
098: public SignatureVisitor visitSuperclass() {
099: endFormals();
100: this .separator = " extends ";
101: startType();
102: return this ;
103: }
104:
105: public SignatureVisitor visitInterface() {
106: this .separator = this .seenInterface ? ", "
107: : (this .isInterface ? " extends " : " implements ");
108: this .seenInterface = true;
109: startType();
110: return this ;
111: }
112:
113: public SignatureVisitor visitParameterType() {
114: endFormals();
115: if (!this .seenParameter) {
116: this .seenParameter = true;
117: this .declaration.append('(');
118: } else {
119: this .declaration.append(", ");
120: }
121: startType();
122: return this ;
123: }
124:
125: public SignatureVisitor visitReturnType() {
126: endFormals();
127: if (!this .seenParameter) {
128: this .declaration.append('(');
129: } else {
130: this .seenParameter = false;
131: }
132: this .declaration.append(')');
133: this .returnType = new StringBuffer();
134: return new TraceSignatureVisitor(this .returnType);
135: }
136:
137: public SignatureVisitor visitExceptionType() {
138: if (this .exceptions == null) {
139: this .exceptions = new StringBuffer();
140: } else {
141: this .exceptions.append(", ");
142: }
143: // startType();
144: return new TraceSignatureVisitor(this .exceptions);
145: }
146:
147: public void visitBaseType(final char descriptor) {
148: switch (descriptor) {
149: case 'V':
150: this .declaration.append("void");
151: break;
152: case 'B':
153: this .declaration.append("byte");
154: break;
155: case 'J':
156: this .declaration.append("long");
157: break;
158: case 'Z':
159: this .declaration.append("boolean");
160: break;
161: case 'I':
162: this .declaration.append("int");
163: break;
164: case 'S':
165: this .declaration.append("short");
166: break;
167: case 'C':
168: this .declaration.append("char");
169: break;
170: case 'F':
171: this .declaration.append("float");
172: break;
173: case 'D':
174: this .declaration.append("double");
175: break;
176: default:
177: throw new IllegalArgumentException("Invalid descriptor "
178: + descriptor);
179: }
180: endType();
181: }
182:
183: public void visitTypeVariable(final String name) {
184: this .declaration.append(name);
185: endType();
186: }
187:
188: public SignatureVisitor visitArrayType() {
189: startType();
190: this .arrayStack |= 1;
191: return this ;
192: }
193:
194: public void visitClassType(final String name) {
195: if (!"java/lang/Object".equals(name)) {
196: this .declaration.append(this .separator).append(
197: name.replace('/', '.'));
198: } else {
199: // Map<java.lang.Object,java.util.List>
200: // or
201: // abstract public V get(Object key); (seen in Dictionary.class)
202: // should have Object
203: // but java.lang.String extends java.lang.Object is unnecessary
204: final boolean needObjectClass = this .argumentStack % 2 == 1
205: || this .seenParameter;
206: if (needObjectClass) {
207: this .declaration.append(this .separator).append(
208: name.replace('/', '.'));
209: }
210: }
211: this .separator = "";
212: this .argumentStack *= 2;
213: }
214:
215: public void visitInnerClassType(final String name) {
216: // TODO tests
217: this .declaration.append(this .separator).append(
218: name.replace('/', '.'));
219: this .separator = "";
220: this .argumentStack *= 2;
221: }
222:
223: public void visitTypeArgument() {
224: if (this .argumentStack % 2 == 0) {
225: ++this .argumentStack;
226: this .declaration.append("<");
227: } else {
228: this .declaration.append(", ");
229: }
230: this .declaration.append("?");
231: }
232:
233: public SignatureVisitor visitTypeArgument(final char tag) {
234: if (this .argumentStack % 2 == 0) {
235: ++this .argumentStack;
236: this .declaration.append("<");
237: } else {
238: this .declaration.append(", ");
239: }
240:
241: if (tag == SignatureVisitor.EXTENDS) {
242: this .declaration.append("? extends ");
243: } else if (tag == SignatureVisitor.SUPER) {
244: this .declaration.append("? super ");
245: }
246:
247: startType();
248: return this ;
249: }
250:
251: public void visitEnd() {
252: if (this .argumentStack % 2 == 1) {
253: this .declaration.append(">");
254: }
255: this .argumentStack /= 2;
256: endType();
257: }
258:
259: public String getDeclaration() {
260: return this .declaration.toString();
261: }
262:
263: public String getReturnType() {
264: return this .returnType == null ? null : this .returnType
265: .toString();
266: }
267:
268: public String getExceptions() {
269: return this .exceptions == null ? null : this .exceptions
270: .toString();
271: }
272:
273: // -----------------------------------------------
274:
275: private void endFormals() {
276: if (this .seenFormalParameter) {
277: this .declaration.append(">");
278: this .seenFormalParameter = false;
279: }
280: }
281:
282: private void startType() {
283: this .arrayStack *= 2;
284: }
285:
286: private void endType() {
287: if (this .arrayStack % 2 == 1) {
288: while (this .arrayStack % 2 == 1) {
289: this .arrayStack /= 2;
290: this .declaration.append("[]");
291: }
292: } else {
293: this .arrayStack /= 2;
294: }
295: }
296: }
|