001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2004, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba;
021:
022: import java.util.ArrayList;
023: import java.util.Iterator;
024: import java.util.NoSuchElementException;
025:
026: import org.apache.bcel.generic.ConstantPoolGen;
027: import org.apache.bcel.generic.InvokeInstruction;
028:
029: /**
030: * A simple class to parse method signatures.
031: *
032: * @author David Hovemeyer
033: */
034: public class SignatureParser {
035: int totalArgumentSize;
036: int parameterOffset[] = null;
037:
038: private void calculateOffsets() {
039: if (parameterOffset != null)
040: return;
041: ArrayList<Integer> offsets = new ArrayList<Integer>();
042: Iterator<String> i = parameterSignatureIterator();
043: totalArgumentSize = 0;
044: while (i.hasNext()) {
045: String s = i.next();
046:
047: if (s.equals("D") || s.equals("J"))
048: totalArgumentSize += 2;
049: else
050: totalArgumentSize += 1;
051: offsets.add(totalArgumentSize);
052: }
053: parameterOffset = new int[offsets.size()];
054: for (int j = 0; j < offsets.size(); j++)
055: parameterOffset[j] = offsets.get(j);
056: }
057:
058: public int getSlotsFromTopOfStackForParameter(int paramNum) {
059: calculateOffsets();
060: int result = totalArgumentSize - parameterOffset[paramNum];
061: return result;
062: }
063:
064: private class ParameterSignatureIterator implements
065: Iterator<String> {
066: private int index = 1;
067:
068: public boolean hasNext() {
069: return index < signature.length()
070: && signature.charAt(index) != ')';
071: }
072:
073: public String next() {
074: if (!hasNext())
075: throw new NoSuchElementException();
076: StringBuffer result = new StringBuffer();
077: boolean done;
078: do {
079: done = true;
080: int ch = signature.charAt(index);
081: switch (ch) {
082: case 'B':
083: case 'C':
084: case 'D':
085: case 'F':
086: case 'I':
087: case 'J':
088: case 'S':
089: case 'Z':
090: result.append(signature.charAt(index));
091: ++index;
092: break;
093:
094: case 'L':
095: int semi = signature.indexOf(';', index + 1);
096: if (semi < 0)
097: throw new IllegalStateException(
098: "Invalid method signature: "
099: + signature);
100: result.append(signature.substring(index, semi + 1));
101: index = semi + 1;
102: break;
103:
104: case '[':
105: result.append('[');
106: ++index;
107: done = false;
108: break;
109:
110: case 'V':
111: default:
112: throw new IllegalStateException(
113: "Invalid method signature: " + signature);
114: }
115: } while (!done);
116:
117: return result.toString();
118: }
119:
120: public void remove() {
121: throw new UnsupportedOperationException();
122: }
123: }
124:
125: private final String signature;
126:
127: @Override
128: public String toString() {
129: return signature;
130: }
131:
132: /**
133: * Constructor.
134: *
135: * @param signature the method signature to be parsed
136: */
137: public SignatureParser(String signature) {
138: if (!signature.startsWith("("))
139: throw new IllegalArgumentException("Bad method signature: "
140: + signature);
141: this .signature = signature;
142: }
143:
144: /**
145: * Get an Iterator over signatures of the method parameters.
146: *
147: * @return Iterator which returns the parameter type signatures in order
148: */
149: public Iterator<String> parameterSignatureIterator() {
150: return new ParameterSignatureIterator();
151: }
152:
153: /**
154: * Get the method return type signature.
155: *
156: * @return the method return type signature
157: */
158: public String getReturnTypeSignature() {
159: int endOfParams = signature.lastIndexOf(')');
160: if (endOfParams < 0)
161: throw new IllegalArgumentException("Bad method signature: "
162: + signature);
163: return signature.substring(endOfParams + 1);
164: }
165:
166: /**
167: * Get the number of parameters in the signature.
168: *
169: * @return the number of parameters
170: */
171: public int getNumParameters() {
172: int count = 0;
173: for (Iterator<String> i = parameterSignatureIterator(); i
174: .hasNext();) {
175: i.next();
176: ++count;
177: }
178: return count;
179: }
180:
181: public boolean hasReferenceParameters() {
182: for (Iterator<String> i = parameterSignatureIterator(); i
183: .hasNext();) {
184: char c = i.next().charAt(0);
185: if (c == 'L' || c == '[')
186: return true;
187: }
188: return false;
189: }
190:
191: public String getParameter(int pos) {
192: int count = 0;
193: for (Iterator<String> i = parameterSignatureIterator(); i
194: .hasNext();) {
195: String p = i.next();
196: if (pos == count)
197: return p;
198: ++count;
199: }
200: throw new IndexOutOfBoundsException("Asked for parameter "
201: + pos + " of " + signature);
202: }
203:
204: /**
205: * Determine whether or not given signature denotes a reference type.
206: *
207: * @param signature a signature
208: * @return true if signature denotes a reference type, false otherwise
209: */
210: public static boolean isReferenceType(String signature) {
211: return signature.startsWith("L") || signature.startsWith("[");
212: }
213:
214: /**
215: * Get the number of parameters passed to method invocation.
216: *
217: * @param inv
218: * @param cpg
219: * @return int number of parameters
220: */
221: public static int getNumParametersForInvocation(
222: InvokeInstruction inv, ConstantPoolGen cpg) {
223: SignatureParser sigParser = new SignatureParser(inv
224: .getSignature(cpg));
225: return sigParser.getNumParameters();
226: }
227:
228: /**
229: * Return how many stack frame slots a type whose signature
230: * is given will occupy. long and double values take 2 slots,
231: * while all other kinds of values take 1 slot.
232: *
233: * @param sig a type signature
234: * @return number of stack frame slots a value of the given type will occupy
235: */
236: public static int getNumSlotsForType(String sig) {
237: if (sig.equals("J") || sig.equals("D")) {
238: return 2;
239: } else {
240: return 1;
241: }
242: }
243:
244: public static void main(String[] args) {
245: if (args.length != 1) {
246: System.err.println("Usage: "
247: + SignatureParser.class.getName()
248: + " '<method signature>'");
249: System.exit(1);
250: }
251: SignatureParser parser = new SignatureParser(args[0]);
252: for (Iterator<String> i = parser.parameterSignatureIterator(); i
253: .hasNext();) {
254: System.out.println(i.next());
255: }
256: System.out.println(parser.getNumParameters() + " parameter(s)");
257: }
258: }
259:
260: // vim:ts=4
|