/* Soot - a J*va Optimization Framework
* Copyright (C) 2006 Nomair A. Naeem (nomair.naeem@mail.mcgill.ca)
*
* 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
*/
/*
* CHANGE LOG: * 30th January 2006, Class created since FinalFieldDefinition wants
* info about uses of a particular field in a method. Writing a general
* analysis which finds all uses of Locals and SootFields
*
*/
/*
Need to be very clear when a local can be used
It can be used in the following places:
a, a conditional in if, ifelse, while , do while, for condition TICK
b, in the for init or update TICK
c, in a switch choice TICK
d, in a syncrhnoized block TICK
d, in a statement TICK
Need to be very clear when a SootField can be used
It can be used in the following places:
a, NOT used inside a Synchronized Block ........ HOWEVER ADD IT SINCE I DONT SEE WHY THIS RESTRICTION EXISTS!!! TICK
b, CAN BE USED in a condition TICK
c, CAN BE USED in the for init for update TICK
d, CAN BE USED in a switch TICK
e, CAN BE USED in a stmt TICK
*/
package soot.dava.toolkits.base.AST.traversals;
import soot.*;
import java.util.*;
import soot.jimple.*;
import soot.dava.internal.asg.*;
import soot.dava.internal.AST.*;
import soot.dava.toolkits.base.AST.analysis.*;
/*
* Creates a mapping of locals and all places where they might be used
* creates a mapping of fields and all places where they might be used
* Notice that the mapping is for SootField to uses not for FieldRef to uses
*/
public class AllVariableUses extends DepthFirstAdapter{
ASTMethodNode methodNode;
HashMap<Local, List> localsToUses;
HashMap<SootField, List> fieldsToUses;
public AllVariableUses(ASTMethodNode node){
super();
this.methodNode=node;
init();
}
public AllVariableUses(boolean verbose, ASTMethodNode node){
super(verbose);
this.methodNode=node;
init();
}
public void init(){
localsToUses = new HashMap<Local, List>();
fieldsToUses = new HashMap<SootField, List>();
}
/*
* Notice as things stand synchblocks cant have the use of a SootField
*/
public void inASTSynchronizedBlockNode(ASTSynchronizedBlockNode node){
Local local = node.getLocal();
addLocalUse(local,node);
}
/*
The key in a switch stmt can be a local or a SootField or a value
which can contain Locals or SootFields
Hence the some what indirect approach
*/
public void inASTSwitchNode(ASTSwitchNode node){
Value val = node.get_Key();
List<Value> localUses = new ArrayList<Value>();
List<Value> fieldUses = new ArrayList<Value>();
if(val instanceof Local){
localUses.add(val);
System.out.println("Added "+val+" to local uses for switch");
}
else if(val instanceof FieldRef){
fieldUses.add(val);
System.out.println("Added "+val+" to field uses for switch");
}
else{
List useBoxes = val.getUseBoxes();
List<Value> localsOrFieldRefs= getUsesFromBoxes(useBoxes);
Iterator<Value> it = localsOrFieldRefs.iterator();
while(it.hasNext()){
Value temp = it.next();
if(temp instanceof Local){
localUses.add(temp);
System.out.println("Added "+temp+" to local uses for switch");
}
else if(temp instanceof FieldRef){
fieldUses.add(temp);
System.out.println("Added "+temp+" to field uses for switch");
}
}
}
//localuses stores Locals used
Iterator<Value> it = localUses.iterator();
while(it.hasNext()){
Local local = (Local)it.next();
addLocalUse(local,node);
}//end of going through all locals uses in switch key
//fieldUses stores FieldRef
it = fieldUses.iterator();
while(it.hasNext()){
FieldRef field = (FieldRef)it.next();
SootField sootField = field.getField();
addFieldUse(sootField,node);
}//end of going through all FieldRef uses in switch key
}
public void inASTStatementSequenceNode(ASTStatementSequenceNode node){
List<Object> statements = node.getStatements();
Iterator<Object> it = statements.iterator();
while(it.hasNext()){
AugmentedStmt as = (AugmentedStmt)it.next();
Stmt s = as.get_Stmt();
//in the case of stmtts in a stmtt sequence each stmt is considered an entity
//compared to the case where these stmts occur within other constructs
//where the node is the entity
checkStatementUses(s,s);
}
}
/*
* The init of a for loop can use a local/Sootfield
* The condition of a for node can use a local/SootField
* The update in a for loop can use a local/SootField
*
*/
public void inASTForLoopNode(ASTForLoopNode node){
//checking uses in init
List<Object> init = node.getInit();
Iterator<Object> it = init.iterator();
while(it.hasNext()){
AugmentedStmt as = (AugmentedStmt)it.next();
Stmt s = as.get_Stmt();
checkStatementUses(s,node);
}
//checking uses in condition
ASTCondition cond = node.get_Condition();
checkConditionalUses(cond,node);
//checking uses in update
List<Object> update = node.getUpdate();
it = update.iterator();
while(it.hasNext()){
AugmentedStmt as = (AugmentedStmt)it.next();
Stmt s = as.get_Stmt();
checkStatementUses(s,node);
}
}
public void checkStatementUses(Stmt s,Object useNodeOrStatement){
List useBoxes = s.getUseBoxes();
//remeber getUsesFromBoxes returns both Locals and FieldRefs
List<Value> uses= getUsesFromBoxes(useBoxes);
Iterator<Value> it = uses.iterator();
while(it.hasNext()){
Value temp = it.next();
if(temp instanceof Local){
addLocalUse((Local)temp,useNodeOrStatement);
}
else if(temp instanceof FieldRef){
FieldRef field = (FieldRef)temp;
SootField sootField = field.getField();
addFieldUse(sootField,useNodeOrStatement);
}
}
}
/*
* This method gets a list of all uses of locals/Sootfield in the condition
* and stores a use by this node
*/
public void checkConditionalUses(ASTCondition cond,ASTNode node){
List<Value> useList = getUseList(cond);
//System.out.println("FOR NODE with condition:"+cond+"USE list is:"+useList);
//FOR EACH USE
Iterator<Value> it = useList.iterator();
while(it.hasNext()){
Value temp = it.next();
if(temp instanceof Local){
addLocalUse((Local)temp,node);
}
else if(temp instanceof FieldRef){
FieldRef field = (FieldRef)temp;
SootField sootField = field.getField();
addFieldUse(sootField,node);
}
}//end of going through all locals uses in condition
}
/*
* The condition of an if node can use a local
*
*/
public void inASTIfNode(ASTIfNode node){
ASTCondition cond = node.get_Condition();
checkConditionalUses(cond,node);
}
/*
* The condition of an ifElse node can use a local
*
*/
public void inASTIfElseNode(ASTIfElseNode node){
ASTCondition cond = node.get_Condition();
checkConditionalUses(cond,node);
}
/*
* The condition of a while node can use a local
*
*/
public void inASTWhileNode(ASTWhileNode node){
ASTCondition cond = node.get_Condition();
checkConditionalUses(cond,node);
}
/*
* The condition of a doWhile node can use a local
*
*/
public void inASTDoWhileNode(ASTDoWhileNode node){
ASTCondition cond = node.get_Condition();
checkConditionalUses(cond,node);
}
/*
* Given a unary/binary or aggregated condition this method is used
* to find the locals/SootFields used in the condition
* @param The condition to be checked for Local or FieldRef uses
* @return a list containing all Locals and FieldRefs used in this condition
*/
public List<Value> getUseList(ASTCondition cond){
ArrayList<Value> useList = new ArrayList<Value>();
if(cond instanceof ASTAggregatedCondition){
useList.addAll(getUseList(((ASTAggregatedCondition)cond).getLeftOp()));
useList.addAll(getUseList(((ASTAggregatedCondition)cond).getRightOp()));
return useList;
}
else if(cond instanceof ASTUnaryCondition){
//get uses from unary condition
List<Value> uses = new ArrayList<Value>();
Value val = ((ASTUnaryCondition)cond).getValue();
if(val instanceof Local || val instanceof FieldRef){
uses.add(val);
}
else{
List useBoxes = val.getUseBoxes();
uses= getUsesFromBoxes(useBoxes);
}
return uses;
}
else if(cond instanceof ASTBinaryCondition){
//get uses from binaryCondition
Value val = ((ASTBinaryCondition)cond).getConditionExpr();
List useBoxes = val.getUseBoxes();
return getUsesFromBoxes(useBoxes);
}
else{
throw new RuntimeException("Method getUseList in ASTUsesAndDefs encountered unknown condition type");
}
}
private void addLocalUse(Local local, Object obj){
Object temp = localsToUses.get(local);
List<Object> uses;
if(temp == null)
uses = new ArrayList<Object>();
else
uses = (ArrayList<Object>)temp;
//add local to useList
uses.add(obj);
//update mapping
localsToUses.put(local,uses);
}
private void addFieldUse(SootField field, Object obj){
Object temp = fieldsToUses.get(field);
List<Object> uses;
if(temp == null)
uses = new ArrayList<Object>();
else
uses = (ArrayList<Object>)temp;
// add field to useList
uses.add(obj);
//update mapping
fieldsToUses.put(field,uses);
}
/*
* Method is used to strip away boxes from the actual values
* only those are returned which are locals or FieldRefs
*/
private List<Value> getUsesFromBoxes(List useBoxes){
ArrayList<Value> toReturn = new ArrayList<Value>();
Iterator it = useBoxes.iterator();
while(it.hasNext()){
Value val =((ValueBox)it.next()).getValue();
if(val instanceof Local || val instanceof FieldRef)
toReturn.add(val);
}
//System.out.println("VALUES:"+toReturn);
return toReturn;
}
public List getUsesForField(SootField field){
Object temp = fieldsToUses.get(field);
if(temp == null)
return null;
else
return (List)temp;
}
public List getUsesForLocal(Local local){
Object temp = localsToUses.get(local);
if(temp == null)
return null;
else
return (List)temp;
}
}