001: // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
002: package jodd.proxetta;
003:
004: import org.objectweb.asm.Opcodes;
005: import org.objectweb.asm.signature.SignatureVisitor;
006: import jodd.util.collection.IntArrayList;
007: import jodd.mutable.MutableInteger;
008:
009: import java.util.List;
010: import java.util.ArrayList;
011:
012: /**
013: * A {@link SignatureVisitor} that prints a disassembled view of the signature
014: * it visits.
015: *
016: * MethodSignature = ( visitFormalTypeParameter visitClassBound? visitInterfaceBound* )* ( visitParameterType* visitReturnType visitExceptionType* )
017: *
018: * @author Eugene Kuleshov
019: * @author Eric Bruneton
020: * @author Igor Spasic
021: */
022: class MethodSignatureVisitor implements SignatureVisitor,
023: MethodSignature {
024:
025: int access;
026: StringBuffer declaration;
027: boolean isInterface;
028: private boolean seenFormalParameter;
029: private boolean seenInterfaceBound;
030: private boolean seenParameter;
031: private boolean seenInterface;
032: StringBuffer returnType;
033: StringBuffer exceptions;
034: String methodName;
035: String signature;
036: int parametersCount;
037: int parametersWords;
038: MutableInteger returnOpcodeType;
039: String classname;
040: String description;
041: List<AnnotationData> annotations;
042:
043: /**
044: * Stack used to keep track of class types that have arguments. Each element
045: * of this stack is a boolean encoded in one bit. The top of the stack is
046: * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
047: * /2.
048: */
049: private int argumentStack;
050:
051: /**
052: * Stack used to keep track of array class types. Each element of this stack
053: * is a boolean encoded in one bit. The top of the stack is the lowest order
054: * bit. Pushing false = *2, pushing true = *2+1, popping = /2.
055: */
056: private int arrayStack;
057:
058: private String separator = "";
059:
060: MethodSignatureVisitor(String description) {
061: this .declaration = new StringBuffer();
062: this .description = description;
063: }
064:
065: MethodSignatureVisitor(String methodName, final int access,
066: String classname, String description) {
067: isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
068: this .declaration = new StringBuffer();
069: this .methodName = methodName;
070: this .access = access;
071: this .classname = classname;
072: this .description = description;
073: this .annotations = new ArrayList<AnnotationData>();
074: }
075:
076: private MethodSignatureVisitor(final StringBuffer buf) {
077: this .declaration = buf;
078: }
079:
080: private MethodSignatureVisitor(final StringBuffer buf,
081: MutableInteger returnOpcodeType) {
082: this .declaration = buf;
083: this .returnOpcodeType = returnOpcodeType;
084: }
085:
086: public void visitFormalTypeParameter(final String name) {
087: declaration.append(seenFormalParameter ? ", " : "<").append(
088: name);
089: seenFormalParameter = true;
090: seenInterfaceBound = false;
091: }
092:
093: public SignatureVisitor visitClassBound() {
094: separator = " extends ";
095: startType();
096: return this ;
097: }
098:
099: public SignatureVisitor visitInterfaceBound() {
100: separator = seenInterfaceBound ? ", " : " extends ";
101: seenInterfaceBound = true;
102: startType();
103: return this ;
104: }
105:
106: public SignatureVisitor visitSuperclass() {
107: endFormals();
108: separator = " extends ";
109: startType();
110: return this ;
111: }
112:
113: public SignatureVisitor visitInterface() {
114: separator = seenInterface ? ", " : isInterface ? " extends "
115: : " implements ";
116: seenInterface = true;
117: startType();
118: return this ;
119: }
120:
121: private boolean visitingParameter;
122: private IntArrayList paramsOpcodeType;
123: private IntArrayList paramsOffset;
124:
125: public SignatureVisitor visitParameterType() {
126: endFormals();
127: if (!seenParameter) {
128: seenParameter = true;
129: declaration.append('(');
130: } else {
131: declaration.append(", ");
132: }
133: startType();
134: visitingParameter = true;
135: if (paramsOpcodeType == null) {
136: paramsOpcodeType = new IntArrayList();
137: paramsOpcodeType.add('L');
138: paramsOffset = new IntArrayList();
139: paramsOffset.add(0);
140: }
141: return this ;
142: }
143:
144: public SignatureVisitor visitReturnType() {
145: endFormals();
146: if (!seenParameter) {
147: declaration.append('(');
148: } else {
149: seenParameter = false;
150: }
151: declaration.append(')');
152: returnType = new StringBuffer();
153: returnOpcodeType = new MutableInteger();
154: return new MethodSignatureVisitor(returnType, returnOpcodeType);
155: }
156:
157: public SignatureVisitor visitExceptionType() {
158: if (exceptions == null) {
159: exceptions = new StringBuffer();
160: } else {
161: exceptions.append(", ");
162: }
163: // startTxype();
164: return new MethodSignatureVisitor(exceptions);
165: }
166:
167: public void visitBaseType(final char descriptor) {
168: switch (descriptor) {
169: case 'V':
170: declaration.append("void");
171: maybeUseType('V');
172: break;
173: case 'B':
174: declaration.append("byte");
175: maybeUseType('B');
176: break;
177: case 'J':
178: declaration.append("long");
179: maybeUseType('L');
180: break;
181: case 'Z':
182: declaration.append("boolean");
183: maybeUseType('Z');
184: break;
185: case 'I':
186: declaration.append("int");
187: maybeUseType('I');
188: break;
189: case 'S':
190: declaration.append("short");
191: maybeUseType('S');
192: break;
193: case 'C':
194: declaration.append("char");
195: maybeUseType('C');
196: break;
197: case 'F':
198: declaration.append("float");
199: maybeUseType('F');
200: break;
201: // case 'D':
202: default:
203: declaration.append("double");
204: maybeUseType('D');
205: break;
206: }
207: endType();
208: }
209:
210: public void visitTypeVariable(final String name) {
211: declaration.append(name);
212: endType();
213: maybeUseType('L');
214: }
215:
216: public SignatureVisitor visitArrayType() {
217: startType();
218: arrayStack |= 1;
219: maybeUseType('L');
220: return this ;
221: }
222:
223: public void visitClassType(final String name) {
224: if (!"java/lang/Object".equals(name)) {
225: declaration.append(separator)
226: .append(name.replace('/', '.'));
227: } else {
228: // Map<java.lang.Object,java.util.List>
229: // or
230: // abstract public V get(Object key); (seen in Dictionary.class)
231: // should have Object
232: // but java.lang.String extends java.lang.Object is unnecessary
233: boolean needObjectClass = argumentStack % 2 != 0
234: || seenParameter;
235: if (needObjectClass) {
236: declaration.append(separator).append(
237: name.replace('/', '.'));
238: }
239: }
240: separator = "";
241: argumentStack <<= 1;
242: maybeUseType('L');
243: }
244:
245: public void visitInnerClassType(final String name) {
246: if (argumentStack % 2 != 0) {
247: declaration.append('>');
248: }
249: argumentStack >>= 1;
250: declaration.append('.');
251: declaration.append(separator).append(name.replace('/', '.'));
252: separator = "";
253: argumentStack <<= 1;
254: }
255:
256: public void visitTypeArgument() {
257: if (argumentStack % 2 == 0) {
258: ++argumentStack;
259: declaration.append('<');
260: } else {
261: declaration.append(", ");
262: }
263: declaration.append('?');
264: }
265:
266: public SignatureVisitor visitTypeArgument(final char tag) {
267: if (argumentStack % 2 == 0) {
268: ++argumentStack;
269: declaration.append('<');
270: } else {
271: declaration.append(", ");
272: }
273:
274: if (tag == SignatureVisitor.EXTENDS) {
275: declaration.append("? extends ");
276: } else if (tag == SignatureVisitor.SUPER) {
277: declaration.append("? super ");
278: }
279:
280: startType();
281: return this ;
282: }
283:
284: public void visitEnd() {
285: if (argumentStack % 2 != 0) {
286: declaration.append('>');
287: }
288: argumentStack >>= 1;
289: endType();
290: }
291:
292: // ---------------------------------------------------------------- method signature
293:
294: public String getDeclaration() {
295: return declaration.toString();
296: }
297:
298: public String getReturnType() {
299: return returnType == null ? null : returnType.toString();
300: }
301:
302: public String getExceptions() {
303: return exceptions == null ? null : exceptions.toString();
304: }
305:
306: public String getSignature() {
307: if (signature == null) {
308: signature = createSignature();
309: }
310: return signature;
311: }
312:
313: private String createSignature() {
314: StringBuilder methodDecl = new StringBuilder(30);
315: methodDecl.append(getReturnType()).append(' ').append(
316: methodName).append(getDeclaration());
317: String genericExceptions = getExceptions();
318: if (genericExceptions != null) {
319: methodDecl.append(" throws ").append(genericExceptions);
320: }
321: return methodDecl.toString();
322: }
323:
324: public String getMethodName() {
325: return methodName;
326: }
327:
328: public int getParamCount() {
329: return parametersCount;
330: }
331:
332: public int getParamOpcodeType(int i) {
333: return paramsOpcodeType.get(i);
334: }
335:
336: protected int getParamOffset(int i) {
337: return paramsOffset.get(i);
338: }
339:
340: protected int getParamSize() {
341: return parametersWords;
342: }
343:
344: public int getReturnOpcodeType() {
345: return returnOpcodeType.value;
346: }
347:
348: public int getAccessFlags() {
349: return access;
350: }
351:
352: public String getClassname() {
353: return classname;
354: }
355:
356: public String getDescription() {
357: return description;
358: }
359:
360: public List<AnnotationData> getAnnotations() {
361: return annotations;
362: }
363:
364: // ---------------------------------------------------------------- utilities
365:
366: /**
367: * Saves parameter type if parameter was visited.
368: * Stores current parameter offset.
369: */
370: private void maybeUseType(int type) {
371: if (visitingParameter == true) {
372: if (type != 'V') {
373: paramsOpcodeType.add(type);
374: parametersCount++;
375: if ((type == 'D') || (type == 'J')) {
376: parametersWords += 2;
377: } else {
378: parametersWords++;
379: }
380: paramsOffset.add(parametersWords);
381: }
382: visitingParameter = false;
383: } else if (returnOpcodeType != null) {
384: returnOpcodeType.value = type;
385: }
386: }
387:
388: private void endFormals() {
389: if (seenFormalParameter) {
390: declaration.append('>');
391: seenFormalParameter = false;
392: }
393: }
394:
395: private void startType() {
396: arrayStack <<= 1;
397: }
398:
399: private void endType() {
400: if (arrayStack % 2 != 0) {
401: while (arrayStack % 2 != 0) {
402: arrayStack >>= 1;
403: declaration.append("[]");
404: }
405: } else {
406: arrayStack >>= 1;
407: }
408: }
409:
410: // ---------------------------------------------------------------- toString
411:
412: @Override
413: public String toString() {
414: return "MethodSignature: " + classname + " " + getSignature();
415: }
416: }
|