/* Soot - a J*va Optimization Framework * Copyright (C) 2005 Nomair A. Naeem * * 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. */ /* * Maintained by Nomair A. Naeem */ /* * CHANGLE LOG: * */ package soot.dava.toolkits.base.AST.traversals; import soot.*; import java.util.*; import soot.jimple.*; import soot.dava.internal.javaRep.*; import soot.dava.internal.AST.*; import soot.dava.internal.SET.*; import soot.dava.toolkits.base.AST.analysis.*; /** * This class has been created because we need the immediate * target of a implicit break/continue statement i.e. a break/continue * statement which does not break/continue a particular label explicitly. * Notice that this is only allowed for * while * do while, * unconditional loop * for loop * switch construct. * Notice continue is not allowed for switch also * Explicit breaks can on the other hand break any label (that on a construct) which we are not * worried about in this analysis */ public class ClosestAbruptTargetFinder extends DepthFirstAdapter{ public ClosestAbruptTargetFinder( Singletons.Global g ) {} public static ClosestAbruptTargetFinder v() { return G.v().soot_dava_toolkits_base_AST_traversals_ClosestAbruptTargetFinder(); } HashMap<DAbruptStmt, ASTNode> closestNode = new HashMap<DAbruptStmt, ASTNode>();//a mapping of each abrupt statement to the node they are targeting ArrayList<ASTLabeledNode> nodeStack = new ArrayList<ASTLabeledNode>(); //the last element will always be the "currentNode" meaning the closest target to a abrupt stmt /** * To be invoked by other analyses. Given an abrupt stmt as input this method * will locate the closest target and return it */ public ASTNode getTarget(DAbruptStmt ab){ Object node = closestNode.get(ab); if(node!=null) return (ASTNode)node; else throw new RuntimeException("Unable to find target for AbruptStmt"); } /** * Following methods add a new node to the end of the nodeStack arrayList * Since that node becomes the closest target of an implicit break or continue */ public void inASTWhileNode(ASTWhileNode node){ nodeStack.add(node); } public void inASTDoWhileNode(ASTDoWhileNode node){ nodeStack.add(node); } public void inASTUnconditionalLoopNode(ASTUnconditionalLoopNode node){ nodeStack.add(node); } public void inASTForLoopNode(ASTForLoopNode node){ nodeStack.add(node); } public void inASTSwitchNode(ASTSwitchNode node){ nodeStack.add(node); } /** * Following methods remove the last node from the end of the nodeStack arrayList * Since the previous node now becomes the closest target to an implict break or continue */ public void outASTWhileNode(ASTWhileNode node){ if(nodeStack.isEmpty()) throw new RuntimeException("trying to remove node from empty stack: ClosestBreakTargetFinder"); nodeStack.remove(nodeStack.size()-1); } public void outASTDoWhileNode(ASTDoWhileNode node){ if(nodeStack.isEmpty()) throw new RuntimeException("trying to remove node from empty stack: ClosestBreakTargetFinder"); nodeStack.remove(nodeStack.size()-1); } public void outASTUnconditionalLoopNode(ASTUnconditionalLoopNode node){ if(nodeStack.isEmpty()) throw new RuntimeException("trying to remove node from empty stack: ClosestBreakTargetFinder"); nodeStack.remove(nodeStack.size()-1); } public void outASTForLoopNode(ASTForLoopNode node){ if(nodeStack.isEmpty()) throw new RuntimeException("trying to remove node from empty stack: ClosestBreakTargetFinder"); nodeStack.remove(nodeStack.size()-1); } public void outASTSwitchNode(ASTSwitchNode node){ if(nodeStack.isEmpty()) throw new RuntimeException("trying to remove node from empty stack: ClosestBreakTargetFinder"); nodeStack.remove(nodeStack.size()-1); } public void inStmt(Stmt s){ if(s instanceof DAbruptStmt){ //breaks and continues are abrupt statements DAbruptStmt ab = (DAbruptStmt)s; SETNodeLabel label = ab.getLabel(); if(label != null){ if(label.toString() != null){ //not considering explicit breaks return; } } //the break is an implict break if(ab.is_Break()){ //get the top of the stack int index = nodeStack.size()-1; if(index<0){ //error throw new RuntimeException("nodeStack empty??"+nodeStack.toString()); } ASTNode currentNode = nodeStack.get(nodeStack.size()-1); closestNode.put(ab,currentNode); } else if(ab.is_Continue()){ //need something different because continues dont target switch int index = nodeStack.size()-1; if(index<0){ //error throw new RuntimeException("nodeStack empty??"+nodeStack.toString()); } ASTNode currentNode = nodeStack.get(index); while(currentNode instanceof ASTSwitchNode){ if(index>0){ //more elements present in nodeStack index--; currentNode = nodeStack.get(index); } else{ //error throw new RuntimeException("Unable to find closest break Target"); } } //know that the currentNode is not an ASTSwitchNode closestNode.put(ab,currentNode); } } } /* public void outASTMethodNode(ASTMethodNode node){ Iterator it = closestNode.keySet().iterator(); while(it.hasNext()){ DAbruptStmt ab = (DAbruptStmt)it.next(); System.out.println("Closest to "+ab+" is "+((ASTNode)closestNode.get(ab)).toString()+"\n\n"); } }*/ }