001 package sysModel.classFile;
002
003 import sysModel.classFile.attributes.AAttributeInfo;
004 import sysModel.classFile.attributes.CodeAttributeInfo;
005 import sysModel.classFile.attributes.visitors.ADefaultAttributeVisitor;
006 import sysModel.classFile.code.InstructionList;
007 import sysModel.classFile.constantPool.AUTFPoolInfo;
008 import sysModel.classFile.constantPool.ConstantPool;
009 import sysModel.classFile.constantPool.visitors.CheckUTFVisitor;
010
011 import java.io.DataInputStream;
012 import java.io.DataOutputStream;
013 import java.io.IOException;
014 import java.util.ArrayList;
015
016 /**
017 * Represents a method in a class file.
018 *
019 * @author Mathias Ricken
020 */
021
022 public final class MethodInfo {
023 /**
024 * Method access flags.
025 */
026 private short _accessFlags;
027
028 /**
029 * Name information.
030 */
031 private AUTFPoolInfo _name;
032
033 /**
034 * Type descriptor information.
035 */
036 private AUTFPoolInfo _descriptor;
037
038 /**
039 * Attributes.
040 */
041 private ArrayList<AAttributeInfo> _attributes = new ArrayList<AAttributeInfo>();
042
043 /**
044 * Constructor.
045 *
046 * @param accessFlags method access flags
047 * @param name method name
048 * @param signature method descriptor
049 * @param attributes array of attributes
050 */
051 public MethodInfo(short accessFlags,
052 AUTFPoolInfo name,
053 AUTFPoolInfo signature,
054 AAttributeInfo[] attributes) {
055 _accessFlags = accessFlags;
056 _name = name;
057 _descriptor = signature;
058 if (null != attributes) {
059 for(AAttributeInfo attr : attributes) {
060 _attributes.add(attr);
061 }
062 }
063 }
064
065 /**
066 * Constructor.
067 *
068 * @param di input stream
069 * @param pool constant pool
070 *
071 * @throws IOException
072 * @throws ClassFormatError
073 */
074 public MethodInfo(DataInputStream di, ConstantPool pool) throws IOException, ClassFormatError {
075 _accessFlags = di.readShort();
076 _name = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null);
077 _descriptor = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null);
078
079 int count = di.readShort();
080 for(int i = 0; i < count; i++) {
081 _attributes.add(AAttributeInfo.read(di, pool));
082 }
083 }
084
085 /**
086 * Write this method into the stream.
087 *
088 * @param dos output stream
089 * @param pool constant pool
090 *
091 * @throws IOException
092 */
093 public void write(DataOutputStream dos, ConstantPool pool) throws IOException {
094 dos.writeShort(_accessFlags);
095 dos.writeShort(pool.indexOf(_name));
096 dos.writeShort(pool.indexOf(_descriptor));
097 dos.writeShort(_attributes.size());
098 for(AAttributeInfo attr : _attributes) {
099 attr.write(dos);
100 }
101 }
102
103 /**
104 * Return a human-readable version of this method.
105 *
106 * @return string
107 */
108 public String toString() {
109 String s = _descriptor.toString();
110 String paramSig = s.substring(s.indexOf('(') + 1, s.indexOf(')'));
111 String returnSig = s.substring(s.indexOf(')') + 1);
112
113 // handle constructor correctly
114 StringBuffer parameterList = new StringBuffer();
115 parameterList.append(_name + "(");
116
117 char initialParameter = 'a';
118 if ((0 < paramSig.length()) && 'V' != paramSig.charAt(0)) {
119 StringBuffer varName = new StringBuffer();
120 while(0 < paramSig.length()) {
121 varName.setLength(0);
122 varName.append(initialParameter);
123 initialParameter++;
124 parameterList.append(ClassFileTools.getTypeString(paramSig, varName.toString()));
125 paramSig = ClassFileTools.getNextSignature(paramSig);
126 if (0 < paramSig.length()) {
127 parameterList.append(", ");
128 }
129 }
130
131 }
132 parameterList.append(')');
133
134 StringBuffer x = new StringBuffer();
135 x.append(ClassFileTools.getAccessString(_accessFlags));
136 x.append(ClassFileTools.getTypeString(returnSig, parameterList.toString()));
137
138 return x.toString();
139 }
140
141 /**
142 * Return a human-readable version of this method.
143 *
144 * @param pool constant pool
145 *
146 * @return string
147 */
148 public String toString(ConstantPool pool) {
149 return toString(pool, true, true);
150 }
151
152 /**
153 * Return a human-readable version of this method.
154 *
155 * @param pool constant pool
156 * @param lineNumbers print line numbers
157 * @param PCs print PC values
158 *
159 * @return string
160 */
161 public String toString(ConstantPool pool, boolean lineNumbers, boolean PCs) {
162 String s = _descriptor.toString();
163 String paramSig = s.substring(s.indexOf('(') + 1, s.indexOf(')'));
164 String returnSig = s.substring(s.indexOf(')') + 1);
165
166 // handle constructor correctly
167 StringBuffer parameterList = new StringBuffer();
168 parameterList.append(_name + "(");
169
170 char initialParameter = 'a';
171 if ((0 < paramSig.length()) && 'V' != paramSig.charAt(0)) {
172 StringBuffer varName = new StringBuffer();
173 while(0 < paramSig.length()) {
174 varName.setLength(0);
175 varName.append(initialParameter);
176 initialParameter++;
177 parameterList.append(ClassFileTools.getTypeString(paramSig, varName.toString()));
178 paramSig = ClassFileTools.getNextSignature(paramSig);
179 if (0 < paramSig.length()) {
180 parameterList.append(", ");
181 }
182 }
183
184 }
185 parameterList.append(')');
186
187 StringBuffer x = new StringBuffer();
188 x.append(ClassFileTools.getAccessString(_accessFlags));
189 x.append(ClassFileTools.getTypeString(returnSig, parameterList.toString()));
190
191 for(AAttributeInfo attr : _attributes) {
192 x.append("\n\t").append(attr.toString());
193 }
194
195 if (0 == (_accessFlags & (ClassFile.ACC_NATIVE | ClassFile.ACC_ABSTRACT))) {
196 CodeAttributeInfo ca = getCodeAttributeInfo();
197 x.append('\n').append((new InstructionList(ca.getCode())).toString(lineNumbers, PCs));
198 }
199
200 return x.toString();
201 }
202
203 /**
204 * Accessor for access flags.
205 *
206 * @return access flags
207 */
208 public short getAccessFlags() {
209 return _accessFlags;
210 }
211
212 /**
213 * Mutator for access flags.
214 *
215 * @param accessFlags new access flags
216 */
217 public void setAccessFlags(short accessFlags) {
218 _accessFlags = accessFlags;
219 }
220
221 /**
222 * Accessor for field name.
223 *
224 * @return field name
225 */
226 public AUTFPoolInfo getName() {
227 return _name;
228 }
229
230 /**
231 * Mutator for field name.
232 *
233 * @param name new field name
234 */
235 public void setName(AUTFPoolInfo name) {
236 _name = name;
237 }
238
239 /**
240 * Accessor for descriptor.
241 *
242 * @return descriptor
243 */
244 public AUTFPoolInfo getDescriptor() {
245 return _descriptor;
246 }
247
248 /**
249 * Mutator for descriptor.
250 *
251 * @param descriptor new descriptor
252 */
253 public void setDescriptor(AUTFPoolInfo descriptor) {
254 _descriptor = descriptor;
255 }
256
257 /**
258 * Accessor for attributes.
259 *
260 * @return attributes
261 */
262 public ArrayList<AAttributeInfo> getAttributes() {
263 return _attributes;
264 }
265
266 /**
267 * Return this method's code attribute info.
268 *
269 * @return code attribute info
270 */
271 public CodeAttributeInfo getCodeAttributeInfo() {
272 ADefaultAttributeVisitor<CodeAttributeInfo, Object> getCodeAttributeVisitor
273 = new ADefaultAttributeVisitor<CodeAttributeInfo, Object>() {
274 public CodeAttributeInfo defaultCase(AAttributeInfo host, Object o) {
275 return null;
276 }
277
278 public CodeAttributeInfo codeCase(CodeAttributeInfo host, Object o) {
279 return host;
280 }
281 };
282 for(AAttributeInfo attr : _attributes) {
283 CodeAttributeInfo code = attr.execute(getCodeAttributeVisitor, null);
284 if (null != code) {
285 return code;
286 }
287
288 }
289 throw new ClassFormatError("Method has no Code attribute");
290 }
291 }