001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2004 Jennifer Lhotak
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: package ca.mcgill.sable.soot.callgraph;
021:
022: import org.eclipse.ui.*;
023: import org.eclipse.jface.action.*;
024: import org.eclipse.jface.viewers.*;
025: import ca.mcgill.sable.graph.*;
026: import ca.mcgill.sable.graph.model.*;
027: import org.eclipse.core.runtime.*;
028: import java.util.*;
029: import java.lang.reflect.*;
030: import soot.jimple.toolkits.annotation.callgraph.*;
031: import soot.*;
032: import soot.tagkit.*;
033: import ca.mcgill.sable.soot.interaction.*;
034: import ca.mcgill.sable.soot.*;
035: import org.eclipse.swt.widgets.*;
036: import org.eclipse.ui.plugin.*;
037: import soot.toolkits.graph.interaction.*;
038: import org.eclipse.core.resources.*;
039: import org.eclipse.jdt.core.*;
040: import org.eclipse.ui.texteditor.*;
041: import org.eclipse.ui.part.*;
042:
043: public class CallGraphGenerator {
044:
045: private CallGraphInfo info;
046: private Graph graph;
047: private InteractionController controller;
048: private ArrayList centerList;
049:
050: public CallGraphGenerator() {
051: }
052:
053: public void run() {
054:
055: IWorkbench workbench = SootPlugin.getDefault().getWorkbench();
056: IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
057: IWorkbenchPage page = window.getActivePage();
058: ;
059:
060: try {
061: if (graph == null) {
062: setGraph(new Graph());
063: graph.setName("CallGraph");
064: } else {
065: graph.removeAllChildren();
066: }
067: IEditorPart part = page.openEditor(graph,
068: "ca.mcgill.sable.graph.GraphEditor", true);
069: ((GraphEditor) part)
070: .setPartFactory(new CallGraphPartFactory());
071: addActions((GraphEditor) part);
072: ((GraphEditor) part)
073: .setMenuProvider(new CGMenuProvider(
074: ((GraphEditor) part)
075: .getGraphEditorGraphicalViewer(),
076: ((GraphEditor) part)
077: .getGraphEditorActionRegistry(),
078: part));
079:
080: buildModel();
081: } catch (PartInitException e3) {
082: e3.printStackTrace();
083: } catch (Exception e2) {
084: e2.printStackTrace();
085: }
086: }
087:
088: public void addActions(GraphEditor part) {
089: ShowCodeAction showCode = new ShowCodeAction(
090: (IWorkbenchPart) part);
091: part.getGraphEditorActionRegistry().registerAction(showCode);
092: part.getGraphEditorSelectionActions().add(showCode.getId());
093:
094: ExpandAction expand = new ExpandAction((IWorkbenchPart) part);
095: part.getGraphEditorActionRegistry().registerAction(expand);
096: part.getGraphEditorSelectionActions().add(expand.getId());
097:
098: CollapseAction collapse = new CollapseAction(
099: (IWorkbenchPart) part);
100: part.getGraphEditorActionRegistry().registerAction(collapse);
101: part.getGraphEditorSelectionActions().add(collapse.getId());
102:
103: }
104:
105: public void buildModel() {
106: CallGraphNode cgn = new CallGraphNode();
107: getGraph().addChild(cgn);
108: cgn.setGenerator(this );
109: cgn.setData(getInfo().getCenter());
110:
111: cgn.setExpand(false);
112: makeCons(getInfo(), cgn);
113:
114: }
115:
116: private CallGraphNode getNodeForMethod(SootMethod meth) {
117: CallGraphNode node = null;
118: Iterator it = getGraph().getChildren().iterator();
119: while (it.hasNext()) {
120: CallGraphNode next = (CallGraphNode) it.next();
121: if (next.getData().equals(meth)) {
122: node = next;
123: }
124: }
125: if (node == null) {
126: node = new CallGraphNode();
127: getGraph().addChild(node);
128: node.setData(meth);
129: }
130: return node;
131: }
132:
133: private void makeCons(CallGraphInfo info, CallGraphNode center) {
134: Iterator it1 = info.getInputs().iterator();
135: while (it1.hasNext()) {
136: MethInfo mInfo = (MethInfo) it1.next();
137: SootMethod sm = mInfo.method();
138: CallGraphNode inNode = getNodeForMethod(sm);
139: inNode.setGenerator(this );
140: Edge inEdge = new Edge(inNode, center);
141: inEdge.setLabel(mInfo.edgeKind().name());
142: }
143:
144: Iterator it2 = info.getOutputs().iterator();
145: while (it2.hasNext()) {
146: MethInfo mInfo = (MethInfo) it2.next();
147: SootMethod sm = mInfo.method();
148: CallGraphNode outNode = getNodeForMethod(sm);
149: outNode.setGenerator(this );
150: Edge inEdge = new Edge(center, outNode);
151: inEdge.setLabel(mInfo.edgeKind().name());
152: }
153: }
154:
155: public void collapseGraph(CallGraphNode node) {
156: // need to undo (remove in and out nodes
157: // who are not in center list)
158: ArrayList inputsToRemove = new ArrayList();
159: ArrayList outputsToRemove = new ArrayList();
160: ArrayList nodesToRemove = new ArrayList();
161:
162: if (node.getInputs() != null) {
163: Iterator inIt = node.getInputs().iterator();
164: while (inIt.hasNext()) {
165: Edge next = (Edge) inIt.next();
166: CallGraphNode src = (CallGraphNode) next.getSrc();
167: if (src.isLeaf()) {
168: inputsToRemove.add(next);
169: nodesToRemove.add(src);
170: }
171: }
172: }
173:
174: if (node.getOutputs() != null) {
175: Iterator outIt = node.getOutputs().iterator();
176: while (outIt.hasNext()) {
177: Edge next = (Edge) outIt.next();
178: CallGraphNode tgt = (CallGraphNode) next.getTgt();
179: if (tgt.isLeaf()) {
180: outputsToRemove.add(next);
181: nodesToRemove.add(tgt);
182: }
183: }
184: }
185:
186: Iterator inRIt = inputsToRemove.iterator();
187: while (inRIt.hasNext()) {
188: Edge temp = (Edge) inRIt.next();
189: node.removeInput(temp);
190: }
191:
192: Iterator outRIt = outputsToRemove.iterator();
193: while (outRIt.hasNext()) {
194: Edge temp = (Edge) outRIt.next();
195: node.removeInput(temp);
196: }
197:
198: Iterator nodeRIt = nodesToRemove.iterator();
199: while (nodeRIt.hasNext()) {
200: CallGraphNode temp = (CallGraphNode) nodeRIt.next();
201: temp.removeAllInputs();
202: temp.removeAllOutputs();
203: getGraph().removeChild(temp);
204: }
205:
206: node.setExpand(true);
207: }
208:
209: public void expandGraph(CallGraphNode node) {
210: getController().setEvent(
211: new InteractionEvent(
212: IInteractionConstants.CALL_GRAPH_NEXT_METHOD,
213: node.getData()));
214: getController().handleEvent();
215:
216: }
217:
218: public void showInCode(CallGraphNode node) {
219: SootMethod meth = (SootMethod) node.getData();
220: String sootClassName = meth.getDeclaringClass().getName();
221: sootClassName = sootClassName.replaceAll("\\.", System
222: .getProperty("file.separator"));
223: sootClassName = sootClassName + ".java";
224: String sootMethName = meth.getName();
225:
226: IProject[] progs = SootPlugin.getWorkspace().getRoot()
227: .getProjects();
228: IResource fileToOpen = null;
229: for (int i = 0; i < progs.length; i++) {
230: IProject project = progs[i];
231:
232: IJavaProject jProj = JavaCore.create(project);
233: try {
234:
235: IPackageFragmentRoot[] roots = jProj
236: .getAllPackageFragmentRoots();
237: for (int j = 0; j < roots.length; j++) {
238: if (!(roots[j].getResource() instanceof IContainer))
239: continue;
240: fileToOpen = ((IContainer) roots[j].getResource())
241: .findMember(sootClassName);
242: if (fileToOpen == null)
243: continue;
244: else
245: break;
246: }
247: } catch (Exception e) {
248: }
249:
250: if (fileToOpen != null)
251: break;
252: }
253:
254: IWorkbench workbench = SootPlugin.getDefault().getWorkbench();
255: IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
256: IWorkbenchPage page = window.getActivePage();
257: ;
258:
259: try {
260: IEditorPart part = page.openEditor(new FileEditorInput(
261: (IFile) fileToOpen),
262: org.eclipse.jdt.ui.JavaUI.ID_CU_EDITOR);
263: SourceLnPosTag methTag = (SourceLnPosTag) meth
264: .getTag("SourceLnPosTag");
265: if (methTag != null) {
266:
267: int selOffset = ((AbstractTextEditor) part)
268: .getDocumentProvider().getDocument(
269: part.getEditorInput()).getLineOffset(
270: methTag.startLn() - 1);
271:
272: ((AbstractTextEditor) SootPlugin.getDefault()
273: .getWorkbench().getActiveWorkbenchWindow()
274: .getActivePage().getActiveEditor())
275: .selectAndReveal(selOffset, 0);
276: }
277:
278: } catch (PartInitException e3) {
279: e3.printStackTrace();
280: }
281:
282: catch (Exception e2) {
283: e2.printStackTrace();
284: }
285: }
286:
287: public void addToGraph(Object info) {
288: CallGraphInfo cgInfo = (CallGraphInfo) info;
289:
290: SootMethod center = cgInfo.getCenter();
291:
292: // find the center who is already in the graph
293: CallGraphNode centerNode = getNodeForMethod(cgInfo.getCenter());
294: //addToCenterList(cgInfo.getCenter());
295: centerNode.setExpand(false);
296: // make connections to all the children
297: makeCons(cgInfo, centerNode);
298: }
299:
300: /**
301: * @return
302: */
303: public Graph getGraph() {
304: return graph;
305: }
306:
307: /**
308: * @param graph
309: */
310: public void setGraph(Graph graph) {
311: this .graph = graph;
312: }
313:
314: /**
315: * @return
316: */
317: public CallGraphInfo getInfo() {
318: return info;
319: }
320:
321: /**
322: * @param info
323: */
324: public void setInfo(CallGraphInfo info) {
325: this .info = info;
326: }
327:
328: /**
329: * @return
330: */
331: public InteractionController getController() {
332: return controller;
333: }
334:
335: /**
336: * @param controller
337: */
338: public void setController(InteractionController controller) {
339: this .controller = controller;
340: }
341:
342: public void addToCenterList(Object obj) {
343: if (getCenterList() == null) {
344: setCenterList(new ArrayList());
345: }
346: getCenterList().add(obj);
347: }
348:
349: /**
350: * @return
351: */
352: public ArrayList getCenterList() {
353: return centerList;
354: }
355:
356: /**
357: * @param list
358: */
359: public void setCenterList(ArrayList list) {
360: centerList = list;
361: }
362:
363: }
|