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