1 /*******************************************************************************
2 * This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v1.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v10.html.
7 * This file is a derivative of code released by the University of
8 * California under the terms listed below.
10 * Refinement Analysis Tools is Copyright ©2007 The Regents of the
11 * University of California (Regents). Provided that this notice and
12 * the following two paragraphs are included in any distribution of
13 * Refinement Analysis Tools or its derivative work, Regents agrees
14 * not to assert any of Regents' copyright rights in Refinement
15 * Analysis Tools against recipient for recipients reproduction,
16 * preparation of derivative works, public display, public
17 * performance, distribution or sublicensing of Refinement Analysis
18 * Tools and derivative works, in source code and object code form.
19 * This agreement not to assert does not confer, by implication,
20 * estoppel, or otherwise any license or rights in any intellectual
21 * property of Regents, including, but not limited to, any patents
22 * of Regents or Regents employees.
24 * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
25 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
26 * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
27 * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32 * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
33 * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
34 * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
35 * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
36 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
38 package edu
.berkeley
.cs
.bodik
.svelte
;
40 import java
.io
.IOException
;
41 import java
.io
.PrintStream
;
42 import java
.net
.MalformedURLException
;
44 import java
.util
.Iterator
;
47 import junit
.framework
.Assert
;
49 import com
.ibm
.wala
.cast
.tree
.CAstSourcePositionMap
.Position
;
50 import com
.ibm
.wala
.classLoader
.IClass
;
51 import com
.ibm
.wala
.classLoader
.IClassLoader
;
52 import com
.ibm
.wala
.classLoader
.IMethod
;
53 import com
.ibm
.wala
.eclipse
.util
.EclipseProjectPath
;
54 import com
.ibm
.wala
.ipa
.callgraph
.CGNode
;
55 import com
.ibm
.wala
.ipa
.callgraph
.CallGraph
;
56 import com
.ibm
.wala
.ipa
.cha
.IClassHierarchy
;
57 import com
.ibm
.wala
.types
.Descriptor
;
58 import com
.ibm
.wala
.util
.collections
.HashSetFactory
;
59 import com
.ibm
.wala
.util
.debug
.Assertions
;
60 import com
.ibm
.wala
.util
.strings
.Atom
;
63 * Utilities for dealing with call graphs and call graph
65 * @author Evan Battaglia
68 public class CallGraphUtils
{
71 * Find a method whose signature matches <code>([Ljava/lang/String;)V</code>, that is,
72 * <code>void main(String args[])</code>
75 * The callgraph to search thru. WARNING: May not look thru all nodes (see code
78 * @return The CGNode representing the method, or null if it could not be found.
80 public static CGNode
findMainMethod(CallGraph cg
) {
81 Descriptor d
= Descriptor
.findOrCreateUTF8("([Ljava/lang/String;)V");
82 Atom name
= Atom
.findOrCreateUnicodeAtom("main");
83 for (Iterator
<?
extends CGNode
> it
= cg
.getSuccNodes(cg
.getFakeRootNode()); it
.hasNext();) {
85 if (n
.getMethod().getName().equals(name
) && n
.getMethod().getDescriptor().equals(d
)) {
89 Assertions
.UNREACHABLE("failed to find main() method");
94 * Find any method in a callgraph. Usually not general enough to find all methods. Don't use
95 * this, use the code from the slicer plugin (added here later hopefully) Parameters same as
102 public static CGNode
findMethod(CallGraph cg
, String name
) {
103 Atom a
= Atom
.findOrCreateUnicodeAtom(name
);
104 for (Iterator
<?
extends CGNode
> it
= cg
.iterator(); it
.hasNext();) {
105 CGNode n
= it
.next();
106 if (n
.getMethod().getName().equals(a
)) {
110 Assertions
.UNREACHABLE("failed to find method " + name
);
115 * Print (to System.out) the IR of a Call Graph.
118 * @param assertReachable
119 * @throws IOException
121 protected static void dumpIR(CallGraph cg
, boolean assertReachable
) throws IOException
{
122 Set
<IMethod
> unreachable
= HashSetFactory
.make();
123 IClassHierarchy cha
= cg
.getClassHierarchy();
124 IClassLoader sourceLoader
= cha
.getLoader(EclipseProjectPath
.SOURCE_REF
);
125 for (Iterator
<IClass
> iter
= sourceLoader
.iterateAllClasses(); iter
.hasNext();) {
126 IClass clazz
= iter
.next();
127 PrintStream Trace
= System
.out
; // CHANGED by evan
128 Trace
.println(clazz
);
129 if (clazz
.isInterface())
132 for (IMethod m
: clazz
.getDeclaredMethods()) {
133 if (m
.isAbstract()) {
136 Iterator
<CGNode
> nodeIter
= cg
.getNodes(m
.getReference()).iterator();
137 if (!nodeIter
.hasNext()) {
138 Trace
.println("Method " + m
.getReference() + " not reachable?");
142 CGNode node
= nodeIter
.next();
143 Trace
.println(node
.getIR());
148 if (assertReachable
) {
149 Assert
.assertTrue(unreachable
.toString(), unreachable
.isEmpty());
154 * Find shortest method whose range of line numbers includes linenum, in the class classname.
155 * This is useful if you are trying to find the statement on a particular line number. You can
156 * first find the method with this, then look through and find the statement matching the line
162 * A line number in the file, STARTING FROM 1. If this is between a method's start
163 * and end line numbers, the method will be returned.
165 * A fully qualified class name (i.e. com.example.mypackage.MyClass). For the case of inner
166 * classes, the outer/enclosing class is acceptable (i.e. Foo for Foo$Bar or Foo$1)
168 * @return The CGNode of the method found.
170 public static CGNode
findMethodIncludingLineNumInClass(CallGraph cg
, int linenum
,
172 String codedclassname
= "L" + classname
.replace('.', '/');
173 String classnameplusdollarsign
= codedclassname
+ "$"; // the code we want may actually be in Foo$Bar or Foo$1
174 // we check if starts with Foo$ (same file -- line numbers are unique within this file)
175 CGNode shortest_node
= null;
176 int len_shortest_node
= Integer
.MAX_VALUE
;
177 for (Iterator
<?
extends CGNode
> it
= cg
.iterator(); it
.hasNext();) {
178 CGNode n
= it
.next();
179 IMethod m
= n
.getMethod();
181 if (m
.getDeclaringClass().getName().toString().equals(codedclassname
)
182 || m
.getDeclaringClass().getName().toString().startsWith(classnameplusdollarsign
)) {
183 Position pos
= CGNodeUtils
.getSourcePosition(n
);
184 System
.out
.printf("***METHOD %s line %d to %d\n", m
.toString(), pos
.getFirstLine(),
186 if (linenum
>= pos
.getFirstLine() && linenum
<= pos
.getLastLine()) {
187 if ((pos
.getLastLine() - pos
.getFirstLine()) < len_shortest_node
) {
188 len_shortest_node
= pos
.getLastLine() - pos
.getFirstLine();
194 return shortest_node
;
198 * Find a method whose range of line numbers includes linenum, in the file filename (absolute
199 * [?]) This is useful if you are trying to find the statement on a particular line number. You
200 * can first find the method with this, then look through and find the statement matching the
208 public static CGNode
findMethodIncludingLineNum(CallGraph cg
, int linenum
,
210 String windowsFixedFilename
= null;
212 windowsFixedFilename
= new URL("file:" + filename
).getFile();
213 } catch (MalformedURLException e
) {
214 Assertions
.UNREACHABLE("Invalid filename in findMethodIncludingLineNum?!");
216 CGNode shortest_node
= null;
217 int len_shortest_node
= Integer
.MAX_VALUE
;
218 for (Iterator
<?
extends CGNode
> it
= cg
.iterator(); it
.hasNext();) {
219 CGNode n
= it
.next();
220 IMethod m
= n
.getMethod();
222 if (m
.getDeclaringClass().getSourceFileName() != null && m
.getDeclaringClass().getSourceFileName().toString().equals(windowsFixedFilename
)) {
223 Position pos
= CGNodeUtils
.getSourcePosition(n
);
225 System
.out
.printf("***METHOD %s line %d to %d\n", m
.toString(), pos
.getFirstLine(),
227 if (linenum
>= pos
.getFirstLine() && linenum
<= pos
.getLastLine()) {
228 if ((pos
.getLastLine() - pos
.getFirstLine()) < len_shortest_node
) {
229 len_shortest_node
= pos
.getLastLine() - pos
.getFirstLine();
236 return shortest_node
;