/* Soot - a J*va Optimization Framework * Copyright (C) 2004 Jennifer Lhotak * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package ca.mcgill.sable.soot.callgraph; import org.eclipse.ui.*; import org.eclipse.jface.action.*; import org.eclipse.jface.viewers.*; import ca.mcgill.sable.graph.*; import ca.mcgill.sable.graph.model.*; import org.eclipse.core.runtime.*; import java.util.*; import java.lang.reflect.*; import soot.jimple.toolkits.annotation.callgraph.*; import soot.*; import soot.tagkit.*; import ca.mcgill.sable.soot.interaction.*; import ca.mcgill.sable.soot.*; import org.eclipse.swt.widgets.*; import org.eclipse.ui.plugin.*; import soot.toolkits.graph.interaction.*; import org.eclipse.core.resources.*; import org.eclipse.jdt.core.*; import org.eclipse.ui.texteditor.*; import org.eclipse.ui.part.*; public class CallGraphGenerator { private CallGraphInfo info; private Graph graph; private InteractionController controller; private ArrayList centerList; public CallGraphGenerator() { } public void run(){ IWorkbench workbench = SootPlugin.getDefault().getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage();; try{ if (graph == null){ setGraph(new Graph()); graph.setName("CallGraph"); } else{ graph.removeAllChildren(); } IEditorPart part = page.openEditor(graph, "ca.mcgill.sable.graph.GraphEditor", true); ((GraphEditor)part).setPartFactory(new CallGraphPartFactory()); addActions((GraphEditor)part); ((GraphEditor)part).setMenuProvider(new CGMenuProvider(((GraphEditor)part).getGraphEditorGraphicalViewer(), ((GraphEditor)part).getGraphEditorActionRegistry(), part)); buildModel(); } catch (PartInitException e3){ e3.printStackTrace(); } catch (Exception e2){ e2.printStackTrace(); } } public void addActions(GraphEditor part){ ShowCodeAction showCode = new ShowCodeAction((IWorkbenchPart)part); part.getGraphEditorActionRegistry().registerAction(showCode); part.getGraphEditorSelectionActions().add(showCode.getId()); ExpandAction expand = new ExpandAction((IWorkbenchPart)part); part.getGraphEditorActionRegistry().registerAction(expand); part.getGraphEditorSelectionActions().add(expand.getId()); CollapseAction collapse = new CollapseAction((IWorkbenchPart)part); part.getGraphEditorActionRegistry().registerAction(collapse); part.getGraphEditorSelectionActions().add(collapse.getId()); } public void buildModel(){ CallGraphNode cgn = new CallGraphNode(); getGraph().addChild(cgn); cgn.setGenerator(this); cgn.setData(getInfo().getCenter()); cgn.setExpand(false); makeCons(getInfo(), cgn); } private CallGraphNode getNodeForMethod(SootMethod meth){ CallGraphNode node = null; Iterator it = getGraph().getChildren().iterator(); while (it.hasNext()){ CallGraphNode next = (CallGraphNode)it.next(); if (next.getData().equals(meth)){ node = next; } } if (node == null){ node = new CallGraphNode(); getGraph().addChild(node); node.setData(meth); } return node; } private void makeCons(CallGraphInfo info, CallGraphNode center){ Iterator it1 = info.getInputs().iterator(); while (it1.hasNext()){ MethInfo mInfo = (MethInfo)it1.next(); SootMethod sm = mInfo.method(); CallGraphNode inNode = getNodeForMethod(sm); inNode.setGenerator(this); Edge inEdge = new Edge(inNode, center); inEdge.setLabel(mInfo.edgeKind().name()); } Iterator it2 = info.getOutputs().iterator(); while (it2.hasNext()){ MethInfo mInfo = (MethInfo)it2.next(); SootMethod sm = mInfo.method(); CallGraphNode outNode = getNodeForMethod(sm); outNode.setGenerator(this); Edge inEdge = new Edge(center, outNode); inEdge.setLabel(mInfo.edgeKind().name()); } } public void collapseGraph(CallGraphNode node){ // need to undo (remove in and out nodes // who are not in center list) ArrayList inputsToRemove = new ArrayList(); ArrayList outputsToRemove = new ArrayList(); ArrayList nodesToRemove = new ArrayList(); if (node.getInputs() != null){ Iterator inIt = node.getInputs().iterator(); while (inIt.hasNext()){ Edge next = (Edge)inIt.next(); CallGraphNode src = (CallGraphNode)next.getSrc(); if (src.isLeaf()){ inputsToRemove.add(next); nodesToRemove.add(src); } } } if (node.getOutputs() != null){ Iterator outIt = node.getOutputs().iterator(); while (outIt.hasNext()){ Edge next = (Edge)outIt.next(); CallGraphNode tgt = (CallGraphNode)next.getTgt(); if (tgt.isLeaf()){ outputsToRemove.add(next); nodesToRemove.add(tgt); } } } Iterator inRIt = inputsToRemove.iterator(); while (inRIt.hasNext()){ Edge temp = (Edge)inRIt.next(); node.removeInput(temp); } Iterator outRIt = outputsToRemove.iterator(); while (outRIt.hasNext()){ Edge temp = (Edge)outRIt.next(); node.removeInput(temp); } Iterator nodeRIt = nodesToRemove.iterator(); while (nodeRIt.hasNext()){ CallGraphNode temp = (CallGraphNode)nodeRIt.next(); temp.removeAllInputs(); temp.removeAllOutputs(); getGraph().removeChild(temp); } node.setExpand(true); } public void expandGraph(CallGraphNode node){ getController().setEvent(new InteractionEvent(IInteractionConstants.CALL_GRAPH_NEXT_METHOD, node.getData())); getController().handleEvent(); } public void showInCode(CallGraphNode node){ SootMethod meth = (SootMethod)node.getData(); String sootClassName = meth.getDeclaringClass().getName(); sootClassName = sootClassName.replaceAll("\\.", System.getProperty("file.separator")); sootClassName = sootClassName + ".java"; String sootMethName = meth.getName(); IProject [] progs = SootPlugin.getWorkspace().getRoot().getProjects(); IResource fileToOpen = null; for (int i = 0; i < progs.length; i++){ IProject project = progs[i]; IJavaProject jProj = JavaCore.create(project); try { IPackageFragmentRoot [] roots = jProj.getAllPackageFragmentRoots(); for (int j = 0; j < roots.length; j++){ if (!(roots[j].getResource() instanceof IContainer)) continue; fileToOpen = ((IContainer)roots[j].getResource()).findMember(sootClassName); if (fileToOpen == null) continue; else break; } } catch(Exception e){ } if (fileToOpen != null) break; } IWorkbench workbench = SootPlugin.getDefault().getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage();; try{ IEditorPart part = page.openEditor(new FileEditorInput((IFile)fileToOpen), org.eclipse.jdt.ui.JavaUI.ID_CU_EDITOR); SourceLnPosTag methTag = (SourceLnPosTag)meth.getTag("SourceLnPosTag"); if (methTag != null){ int selOffset = ((AbstractTextEditor)part).getDocumentProvider().getDocument(part.getEditorInput()).getLineOffset(methTag.startLn()-1); ((AbstractTextEditor)SootPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor()).selectAndReveal(selOffset, 0); } } catch (PartInitException e3){ e3.printStackTrace(); } catch (Exception e2){ e2.printStackTrace(); } } public void addToGraph(Object info){ CallGraphInfo cgInfo = (CallGraphInfo)info; SootMethod center = cgInfo.getCenter(); // find the center who is already in the graph CallGraphNode centerNode = getNodeForMethod(cgInfo.getCenter()); //addToCenterList(cgInfo.getCenter()); centerNode.setExpand(false); // make connections to all the children makeCons(cgInfo, centerNode); } /** * @return */ public Graph getGraph() { return graph; } /** * @param graph */ public void setGraph(Graph graph) { this.graph = graph; } /** * @return */ public CallGraphInfo getInfo() { return info; } /** * @param info */ public void setInfo(CallGraphInfo info) { this.info = info; } /** * @return */ public InteractionController getController() { return controller; } /** * @param controller */ public void setController(InteractionController controller) { this.controller = controller; } public void addToCenterList(Object obj){ if (getCenterList() == null){ setCenterList(new ArrayList()); } getCenterList().add(obj); } /** * @return */ public ArrayList getCenterList() { return centerList; } /** * @param list */ public void setCenterList(ArrayList list) { centerList = list; } }