1 package csdl.jblanket.modifier; 2 3 import java.io.File ; 4 import java.io.FileInputStream ; 5 import java.util.ArrayList ; 6 import java.util.Date ; 7 8 import org.apache.bcel.Constants; 9 import org.apache.bcel.classfile.Method; 10 import org.apache.bcel.generic.ALOAD; 11 import org.apache.bcel.generic.ASTORE; 12 import org.apache.bcel.generic.ConstantPoolGen; 13 import org.apache.bcel.generic.InstructionConstants; 14 import org.apache.bcel.generic.InstructionFactory; 15 import org.apache.bcel.generic.InstructionList; 16 import org.apache.bcel.generic.LineNumberGen; 17 import org.apache.bcel.generic.LocalVariableGen; 18 import org.apache.bcel.generic.MethodGen; 19 import org.apache.bcel.generic.ObjectType; 20 import org.apache.bcel.generic.POP; 21 import org.apache.bcel.generic.PUSH; 22 import org.apache.bcel.generic.Type; 23 24 import csdl.jblanket.methodset.MethodInfo; 25 import csdl.jblanket.methodset.MethodSet; 26 import csdl.jblanket.methodset.MethodSetManager; 27 import csdl.jblanket.util.MethodCategories; 28 29 40 public class MethodModifier { 41 42 43 private MethodGen method; 44 45 46 private String testGrammar; 47 48 49 private boolean excludeOneLineMethods; 50 51 private boolean excludeConstructors; 52 53 54 private MethodSetManager manager; 55 56 private MethodCategories categories; 57 58 private MethodSet excludedIndividualSet; 59 60 private boolean excludeIndividualMethods; 61 62 71 public MethodModifier(boolean verbose, String testGrammar, boolean excludeOneLineMethods, 72 boolean excludeIndividualMethods, boolean excludeConstructors, 73 MethodGen method) { 74 75 this.method = method; 76 77 this.testGrammar = testGrammar; 78 79 this.excludeOneLineMethods = excludeOneLineMethods; 80 this.excludeConstructors = excludeConstructors; 81 82 this.manager = MethodSetManager.getInstance(); 83 this.categories = MethodCategories.getInstance(); 84 85 this.excludeIndividualMethods = excludeIndividualMethods; 86 this.excludedIndividualSet = new MethodSet(); 87 if (this.excludeIndividualMethods) { 88 File excludeIndividualFile = 89 new File (this.categories.getFileName("excludedIndividualFile")); 90 if (excludeIndividualFile.exists()) { 92 loadMethods(this.excludedIndividualSet, excludeIndividualFile); 93 } 94 else { 95 this.excludedIndividualSet = new MethodSet(); 96 } 97 } 98 } 99 100 109 public Method processMethod(ConstantPoolGen pool, boolean isModified) { 110 111 if (isExcluded()) { 112 return this.method.getMethod(); 113 } 114 115 if (isConstructor() || !isMethodUntestable()) { 116 117 if (!hasLineNumbers()) { 118 String methodName = this.method.getClassName() + "." + this.method.getName(); 119 String message = "No line numbers detected in " + methodName + ". " 120 + "Either remove the 'oneLineFile' tag or turn debug on when compiling."; 121 throw new UnsupportedOperationException (message); 122 } 123 124 if (this.excludeConstructors && isConstructor()) { 126 excludeMethod(manager.getMethodSet(categories.getFileName("constructorFile"))); 127 } 128 else if (this.excludeOneLineMethods && isOneLine() && !isConstructor()) { 130 excludeMethod(manager.getMethodSet(categories.getFileName("oneLineFile"))); 131 } 132 else if (!isModified) { 134 return modifyMethod(pool); 135 } 136 } 137 else { 139 excludeMethod(manager.getMethodSet(categories.getFileName("untestableFile"))); 140 } 141 142 return this.method.getMethod(); 143 } 144 145 148 private boolean isExcluded() { 149 return (excludeIndividualMethods && excludedIndividualSet.contains(getMethodInfo())); 150 } 151 152 155 private boolean isMethodUntestable() { 156 if (this.method.isAbstract()) { 157 return true; 158 } 159 if (this.method.isNative()) { 160 return true; 161 } 162 LineNumberGen[] lineNumbers = this.method.getLineNumbers(); 164 165 if (this.method.getReturnType() == Type.VOID && lineNumbers.length == 1) { 168 return true; 169 } 170 171 return false; 172 } 173 174 180 public boolean hasLineNumbers() { 181 182 LineNumberGen[] lineNumbers = this.method.getLineNumbers(); 183 if (lineNumbers.length == 0) { 184 return false; 185 } 186 187 return true; 188 } 189 190 197 public boolean isConstructor() { 198 199 if ("<init>".equals(this.method.getName())) { 200 return true; 201 } 202 203 return false; 204 } 205 206 212 public boolean isOneLine() { 213 214 LineNumberGen[] lineNumbers = this.method.getLineNumbers(); 216 217 if (this.method.getReturnType() == Type.VOID && lineNumbers.length == 2) { 220 return true; 221 } 222 else if (this.method.getReturnType() != Type.VOID && lineNumbers.length == 1) { 224 return true; 225 } 226 227 return false; 228 } 229 230 238 private Method modifyMethod(ConstantPoolGen pool) { 239 240 InstructionList oldList = method.getInstructionList(); 241 242 InstructionList newList = null; 244 newList = addStoreMethodTypeSignature(pool, method); 245 246 oldList.append(oldList.getStart(), newList); 248 this.method.setInstructionList(oldList); 249 this.method.setMaxStack(); 250 Method m = this.method.getMethod(); 251 252 oldList.dispose(); 254 newList.dispose(); 255 256 return m; 257 } 258 259 269 private InstructionList addStoreMethodTypeSignature(ConstantPoolGen pool, MethodGen method) { 270 271 String methodName = method.getName(); 273 String className = method.getClassName(); 274 Type[] types = method.getArgumentTypes(); 275 276 String arrayList = "java.util.ArrayList"; 278 String reportClass = "csdl.jblanket.modifier.MethodCollector"; 279 ObjectType arrayObject = new ObjectType(arrayList); 280 281 InstructionFactory factory = new InstructionFactory(pool); 283 InstructionList newList = new InstructionList(); 284 LocalVariableGen variable; 285 286 variable = method.addLocalVariable("params", new ObjectType(arrayList), null, null); 288 int params = variable.getIndex(); 289 newList.append(factory.createNew(arrayList)); 290 newList.append(InstructionConstants.DUP); 291 newList.append(factory.createInvoke(arrayList, "<init>", Type.VOID, Type.NO_ARGS, 292 Constants.INVOKESPECIAL)); 293 variable.setStart(newList.append(new ASTORE(params))); 294 295 for (int i = 0; i < types.length; i++) { 297 newList.append(new ALOAD(params)); 298 newList.append(new PUSH(pool, types[i].getSignature())); 299 newList.append(factory.createInvoke(arrayList, "add", Type.BOOLEAN, new Type[]{Type.OBJECT}, 300 Constants.INVOKEVIRTUAL)); 301 newList.append(new POP()); 303 } 304 305 Type[] invokeMethodParams = new Type[]{Type.STRING, Type.STRING, arrayObject, Type.STRING}; 307 newList.append(new PUSH(pool, className)); 308 newList.append(new PUSH(pool, methodName)); 309 newList.append(new ALOAD(params)); 310 newList.append(new PUSH(pool, this.testGrammar)); 311 newList.append(factory.createInvoke(reportClass, "storeMethodTypeSignature", Type.VOID, 312 invokeMethodParams, Constants.INVOKESTATIC)); 313 314 return newList; 315 } 316 317 322 public void excludeMethod(MethodSet excludeSet) { 323 MethodInfo methodInfo = getMethodInfo(); 324 excludeSet.add(methodInfo); 325 } 326 327 330 private MethodInfo getMethodInfo() { 331 String className = this.method.getClassName(); 332 String methodName = this.method.getName(); 333 Type[] paramTypes = this.method.getArgumentTypes(); 334 ArrayList paramList = new ArrayList (); 335 for (int i = 0; i < paramTypes.length; i++) { 336 paramList.add(MethodCollector.reconstructType(paramTypes[i].getSignature())); 337 } 338 if ("<init>".equals(methodName)) { 340 methodName = MethodCollector.removePackagePrefix(className); 341 } 342 if ("<clinit>".equals(methodName)) { 343 methodName = MethodCollector.removePackagePrefix(className) + "[static initializer]"; 344 } 345 methodName = methodName.replaceAll("<", "_").replaceAll(">", "_"); 346 MethodInfo methodInfo = new MethodInfo(className, methodName, paramList); 347 return methodInfo; 348 } 349 350 358 private Date loadMethods(MethodSet methodSet, File file) { 359 360 Date timeStamp = null; 361 try { 362 FileInputStream in = new FileInputStream (file); 364 timeStamp = methodSet.load(in); 366 in.close(); 368 } 369 catch (Exception e) { 370 e.printStackTrace(); 373 } 374 375 return timeStamp; 376 } 377 } 378 | Popular Tags |