View Javadoc
1 /*** 2 * MethInstClassLoader 3 * 4 * This is a superclass for all class loaders at 5 * the Method Instrumentation level. If you 6 * want to have more information at any one time 7 * than just the method, then use ClassLoader. 8 */ 9 10 package junit.quilt.cover.generic; 11 12 import junit.quilt.exception.*; 13 14 import org.apache.commons.graph.*; 15 16 import org.apache.bcel.*; 17 import org.apache.bcel.generic.*; 18 import org.apache.bcel.classfile.*; 19 import java.lang.ClassLoader; 20 21 import java.util.Iterator; 22 import java.util.Map; 23 import java.util.HashMap; 24 import java.util.SortedMap; 25 import java.util.TreeMap; 26 import java.util.List; 27 import java.util.ArrayList; 28 29 import java.net.URL; 30 31 public abstract class MethInstClassLoader 32 extends QuiltClassLoader 33 { 34 private EdgeFactory edgeFactory = new EdgeFactoryImpl(); 35 36 publicMethInstClassLoader( String packages[],/index.html"> MethInstClassLoader( String packages[], 37 URL path[]) { 38 super( packages, path ); 39 } 40 41 publicMethInstClassLoader( String packages[],/index.html"> MethInstClassLoader( String packages[], 42 URL path[], 43 ClassLoader parent) { 44 super( packages, path, parent ); 45 } 46 47 /*** 48 * modifyClass 49 * 50 * This is a generic version. It basically cleans some 51 * things in the class (i.e. make it public.) Pass 52 * each Method and a Graph representing the method 53 * to the super class. 54 */ 55 56 protected JavaClass modifyClass( JavaClass jClass ) { 57 if (jClass == null) { 58 System.err.println("Warning: modifyClass called with null JavaClass"); 59 } 60 61 if (!jClass.isClass()) return jClass; 62 63 InstContext context = new InstContext(); 64 65 ConstantPoolGen pool = new ConstantPoolGen( jClass.getConstantPool() ); 66 67 context.setConstantPoolGen( pool ); 68 69 ClassGen clazz = new ClassGen( jClass ); 70 context.setClassGen( clazz ); 71 72 int accFlags = clazz.getAccessFlags(); 73 74 if ((accFlags & org.apache.bcel.Constants.ACC_PRIVATE) > 0) { 75 System.err.println("Warning: Changing class " + 76 clazz.getClassName() + 77 " to public."); 78 accFlags = (accFlags & (~org.apache.bcel.Constants.ACC_PRIVATE)) 79 | org.apache.bcel.Constants.ACC_PUBLIC; 80 clazz.setAccessFlags( accFlags ); 81 } 82 83 if ((accFlags & org.apache.bcel.Constants.ACC_PROTECTED) > 0) { 84 System.err.println("Warning: Changing class " + 85 clazz.getClassName() + 86 " to public."); 87 accFlags = (accFlags & (~org.apache.bcel.Constants.ACC_PROTECTED)) 88 | org.apache.bcel.Constants.ACC_PUBLIC; 89 clazz.setAccessFlags( accFlags ); 90 } 91 92 if ((accFlags & org.apache.bcel.Constants.ACC_PUBLIC) == 0) { 93 System.err.println("Warning: Changing class " + 94 clazz.getClassName() + 95 " to public."); 96 accFlags = accFlags | org.apache.bcel.Constants.ACC_PUBLIC; 97 clazz.setAccessFlags( accFlags ); 98 } 99 100 if (!clazz.isPublic()) { 101 System.err.println("Warning: " + clazz.getClassName() + 102 " is not public."); 103 } 104 105 /* 106 * Allow the subclass to modify the pool if they want. 107 */ 108 instrumentPool( context ); 109 110 Method [] methods = clazz.getMethods(); 111 112 for (int i = 0; i < methods.length; i++) { 113 if (isMethodOK( methods[i] )) { 114 MethodGen method = new MethodGen( methods[i], 115 clazz.getClassName(), 116 pool ); 117 try { 118 ControlFlowGraph cfg = 119 new ControlFlowGraph( context, method ); 120 cfg.initialize( getEdgeFactory() ); 121 instrumentMethod( context, cfg ); 122 clazz.replaceMethod( methods[i], 123 cfg.getMethod() ); 124 } catch (QuiltException e) { 125 System.err.println("Warning: Unable to instrument method " + 126 method.getName() + " / " + e.toString() ); 127 } 128 } 129 } 130 131 clazz.setConstantPool( pool ); 132 JavaClass RC = clazz.getJavaClass(); 133 134 if (!RC.isPublic()) 135 System.err.println("Warning: Class isn't public."); 136 return RC; 137 } 138 139 /*** 140 * Override this abstract method to instrument a method. 141 */ 142 public abstract void instrumentMethod( InstContext context, 143 ControlFlowGraph graph ) 144 throws QuiltException; 145 146 /*** 147 * Call this to add a Vertex in place of an edge. 148 */ 149 public void instrumentEdge( InstContext context, 150 ControlFlowGraph graph, 151 FlowControlEdge edge, 152 BlockVertex vertex ) { 153 154 if (edge.getTarget() != null) { 155 156 // 157 // *-------* 158 // 159 graph.addVertex( vertex ); 160 161 // 162 // * 163 // 164 // *-------* 165 // 166 167 FlowControlEdge outEdge = 168 getEdgeFactory().makeNormalEdge( vertex, edge.getTarget() ); 169 graph.addEdge( outEdge ); 170 171 // 172 // *---+ 173 // | 174 // *-------* 175 // 176 177 edge.setTarget( vertex ); 178 graph.updateEdge( edge ); 179 180 // 181 // +---*---+ 182 // | | 183 // * * 184 // 185 } 186 } 187 188 /*** 189 * instrumentPool 190 * 191 * Gives the subclass a chance to add things into the Constant Pool. 192 * If you need to pass information from here to the instrumentMethod 193 * make sure you drop it in the context. 194 */ 195 public void instrumentPool( InstContext context ) 196 {} 197 198 /*** 199 * getEdgeFactory() 200 * 201 * Override this method to provide your own edges. . . 202 */ 203 public EdgeFactory getEdgeFactory() { 204 return edgeFactory; 205 } 206 207 private boolean isMethodOK( Method method ) { 208 // Don't instrument the Class Initializer. Its bad luck. 209 if (method.getName().equals("<clinit>")) return false; 210 211 // Don't instrument any abstract methods. 212 if (method.getCode() == null) return false; 213 214 return true; 215 } 216 217 218 } 219 220 221 222 223

This page was automatically generated by Maven