KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > SelfCalls


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003,2004 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs;
21
22 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24
25 import org.apache.bcel.classfile.JavaClass;
26 import org.apache.bcel.classfile.Method;
27 import org.apache.bcel.generic.ConstantPoolGen;
28 import org.apache.bcel.generic.INVOKESTATIC;
29 import org.apache.bcel.generic.Instruction;
30 import org.apache.bcel.generic.InstructionHandle;
31 import org.apache.bcel.generic.InvokeInstruction;
32 import org.apache.bcel.generic.MONITORENTER;
33 import org.apache.bcel.generic.MONITOREXIT;
34 import org.apache.bcel.generic.MethodGen;
35
36 import edu.umd.cs.findbugs.ba.BasicBlock;
37 import edu.umd.cs.findbugs.ba.CFG;
38 import edu.umd.cs.findbugs.ba.CFGBuilderException;
39 import edu.umd.cs.findbugs.ba.ClassContext;
40
41 /**
42  * Build a call graph of the self calls in a class.
43  */

44 public class SelfCalls {
45     private static final boolean DEBUG = SystemProperties.getBoolean("selfcalls.debug");
46
47     private ClassContext classContext;
48     private CallGraph callGraph;
49     private HashSet JavaDoc<Method> calledMethodSet;
50     private boolean hasSynchronization;
51
52     /**
53      * Constructor.
54      *
55      * @param classContext the ClassContext for the class
56      */

57     public SelfCalls(ClassContext classContext) {
58         this.classContext = classContext;
59         this.callGraph = new CallGraph();
60         this.calledMethodSet = new HashSet JavaDoc<Method>();
61         this.hasSynchronization = false;
62     }
63
64     /**
65      * Find the self calls.
66      */

67     public void execute() throws CFGBuilderException {
68         JavaClass jclass = classContext.getJavaClass();
69         Method[] methods = jclass.getMethods();
70
71         if (DEBUG) System.out.println("Class has " + methods.length + " methods");
72
73         // Add call graph nodes for all methods
74
for (Method method : methods) {
75             callGraph.addNode(method);
76         }
77         if (DEBUG) System.out.println("Added " + callGraph.getNumVertices() + " nodes to graph");
78
79         // Scan methods for self calls
80
for (Method method : methods) {
81             MethodGen mg = classContext.getMethodGen(method);
82             if (mg == null)
83                 continue;
84
85             scan(callGraph.getNodeForMethod(method));
86         }
87
88         if (DEBUG) System.out.println("Found " + callGraph.getNumEdges() + " self calls");
89     }
90
91     /**
92      * Get the self call graph for the class.
93      */

94     public CallGraph getCallGraph() {
95         return callGraph;
96     }
97
98     /**
99      * Get an Iterator over self-called methods.
100      */

101     public Iterator JavaDoc<Method> calledMethodIterator() {
102         return calledMethodSet.iterator();
103     }
104
105     /**
106      * Determine whether we are interested in calls for the
107      * given method. Subclasses may override. The default version
108      * returns true for every method.
109      *
110      * @param method the method
111      * @return true if we want call sites for the method, false if not
112      */

113     public boolean wantCallsFor(Method method) {
114         return true;
115     }
116
117     /**
118      * Get an Iterator over all self call sites.
119      */

120     public Iterator JavaDoc<CallSite> callSiteIterator() {
121         return new Iterator JavaDoc<CallSite>() {
122             private Iterator JavaDoc<CallGraphEdge> iter = callGraph.edgeIterator();
123
124             public boolean hasNext() {
125                 return iter.hasNext();
126             }
127
128             public CallSite next() {
129                 return iter.next().getCallSite();
130             }
131
132             public void remove() {
133                 iter.remove();
134             }
135         };
136     }
137
138     /**
139      * Does this class contain any explicit synchronization?
140      */

141     public boolean hasSynchronization() {
142         return hasSynchronization;
143     }
144
145     /**
146      * Scan a method for self call sites.
147      *
148      * @param node the CallGraphNode for the method to be scanned
149      */

150     private void scan(CallGraphNode node) throws CFGBuilderException {
151         Method method = node.getMethod();
152         CFG cfg = classContext.getCFG(method);
153
154         if (method.isSynchronized())
155             hasSynchronization = true;
156
157         Iterator JavaDoc<BasicBlock> i = cfg.blockIterator();
158         while (i.hasNext()) {
159             BasicBlock block = i.next();
160             Iterator JavaDoc<InstructionHandle> j = block.instructionIterator();
161             while (j.hasNext()) {
162                 InstructionHandle handle = j.next();
163
164                 Instruction ins = handle.getInstruction();
165                 if (ins instanceof InvokeInstruction) {
166                     InvokeInstruction inv = (InvokeInstruction) ins;
167                     Method called = isSelfCall(inv);
168                     if (called != null) {
169                         // Add edge to call graph
170
CallSite callSite = new CallSite(method, block, handle);
171                         callGraph.createEdge(node, callGraph.getNodeForMethod(called), callSite);
172
173                         // Add to called method set
174
calledMethodSet.add(called);
175                     }
176                 } else if (ins instanceof MONITORENTER || ins instanceof MONITOREXIT) {
177                     hasSynchronization = true;
178                 }
179             }
180         }
181     }
182
183     /**
184      * Is the given instruction a self-call?
185      */

186     private Method isSelfCall(InvokeInstruction inv) {
187         ConstantPoolGen cpg = classContext.getConstantPoolGen();
188         JavaClass jclass = classContext.getJavaClass();
189
190         String JavaDoc calledClassName = inv.getClassName(cpg);
191
192         // FIXME: is it possible we would see a superclass name here?
193
// Not a big deal for now, as we are mostly just interested in calls
194
// to private methods, for which we will definitely see the right
195
// called class name.
196
if (!calledClassName.equals(jclass.getClassName()))
197             return null;
198
199         String JavaDoc calledMethodName = inv.getMethodName(cpg);
200         String JavaDoc calledMethodSignature = inv.getSignature(cpg);
201         boolean isStaticCall = (inv instanceof INVOKESTATIC);
202
203         // Scan methods for one that matches.
204
Method[] methods = jclass.getMethods();
205         for (Method method : methods) {
206             String JavaDoc methodName = method.getName();
207             String JavaDoc signature = method.getSignature();
208             boolean isStatic = method.isStatic();
209
210             if (methodName.equals(calledMethodName) &&
211                     signature.equals(calledMethodSignature) &&
212                     isStatic == isStaticCall) {
213                 // This method looks like a match.
214
return wantCallsFor(method) ? method : null;
215             }
216         }
217
218         // Hmm...no matching method found.
219
// This is almost certainly because the named method
220
// was inherited from a superclass.
221
if (DEBUG) System.out.println("No method found for " + calledClassName + "." + calledMethodName + " : " + calledMethodSignature);
222         return null;
223     }
224 }
225
226 // vim:ts=4
227
Popular Tags