/* 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
*/
/**
* CHANGE LOG:
* November 21st, 2005: Reasoning about correctness of implementation.
* November 22nd, 2005: Found bug in process_DoWhile while implementing ReachingCopies..
* see method for details
* January 30th, 2006: Found bug in handling of breaks inside the ASTTryNode while implementing
* MustMayinitialize...see ASTTryNode method for details
* January 30th, 2006: Found bug in handling of switchNode while implementing MustMayInitialize
* NEEDS THOROUGH TESTING!!!
*
*/
/**
* TODO:
* Refactor the class into a top level class and a forward analysis subclass
* Write the backwards flow analysis
*
* THOROUGH TESTING OF BUG FOUND ON 30th January
*/
package soot.dava.toolkits.base.AST.structuredAnalysis;
import soot.*;
import java.util.*;
import soot.jimple.*;
import soot.dava.internal.AST.*;
import soot.dava.internal.SET.*;
import soot.dava.internal.asg.*;
import soot.dava.internal.javaRep.*;
/*
* This class is meant to be extended to write structred analyses.
* The analysis is invoked by invoking the process method sending it
* the body to be analyzed and the input flowset
* Currently support is available only for a forward flow analysis.
* This should soon be refactored to include backwards flow analysis
* (Nomair 16th November 2005)
*/
public abstract class StructuredAnalysis{
public static boolean DEBUG = false;
public static boolean DEBUG_IF = false;
public static boolean DEBUG_WHILE = false;
public static boolean DEBUG_STATEMENTS = false;
public static boolean DEBUG_TRY = false;
/*
public static boolean DEBUG = true;
public static boolean DEBUG_IF = true;
public static boolean DEBUG_WHILE = true;
public static boolean DEBUG_STATEMENTS = true;
public static boolean DEBUG_TRY = true;
/*
/**
* Whenever an abrupt edge is encountered the flow set is
* added into a the break or continue list and a NOPATH
* object is returned
*/
DavaFlowSet NOPATH = emptyFlowSet();
public int MERGETYPE; //the confluence operator
//the three types of operators
final int UNDEFINED=0;
final int UNION=1;
final int INTERSECTION=2;
//storing before and after sets for each stmt or ASTNode
HashMap<Object, Object> beforeSets,afterSets;
public StructuredAnalysis(){
beforeSets = new HashMap<Object, Object>();
afterSets = new HashMap<Object, Object>();
MERGETYPE=UNDEFINED;
//invoke user defined function which makes sure that you have the merge operator set
setMergeType();
//System.out.println("MergeType is"+MERGETYPE);
if(MERGETYPE == UNDEFINED)
throw new RuntimeException("MERGETYPE UNDEFINED");
}
/*
* This method should be used to set the variable MERGETYPE
* use StructuredAnalysis.UNION for union
* use StructuredAnalysis.INTERSECTION for intersection
*/
public abstract void setMergeType();
/*
* Returns the flow object corresponding to the initial values for
* the catch statements
*/
public abstract Object newInitialFlow();
/*
* Returns an empty flow set object
* Notice this has to be a DavaFlowSet or a set extending DavaFlowSet (hopefully constantpropagationFlowSET??)
*/
public abstract DavaFlowSet emptyFlowSet();
/**
* Make a clone of the flowset
* The implementor should know when they want a shallow or deep clone
*/
public abstract Object cloneFlowSet(Object flowSet);
/**
* Specific stmts within AST Constructs are processed through this
* method. It will be invoked everytime a stmt is encountered
*/
public abstract Object processStatement(Stmt s, Object input);
/**
* To have maximum flexibility in analyzing conditions the analysis API
* breaks down the aggregated conditions to simple unary or binary conditions
* user defined code can then deal with each condition separatly.
* To be able to deal with entire aggregated conditions the user should
* wite their own implementation of the method processCondition
*/
public abstract Object processUnaryBinaryCondition(ASTUnaryBinaryCondition cond,Object input);
/**
* To deal with the local used for synch blocks
*/
public abstract Object processSynchronizedLocal(Local local,Object input);
/**
* Deal with the key in the switch construct
*/
public abstract Object processSwitchKey(Value key,Object input);
public void print(Object toPrint){
System.out.println(toPrint.toString());
}
/**
* This implementation breaks down the aggregated condition to the terminal conditions
* which all have type ASTUnaryBinaryCondition. Once these are obtained the
* abstract method processUnaryBinaryCondition is invoked.
* For aggregated conditions the merging is done in a depth first order of the
* condition tree.
*/
public Object processCondition(ASTCondition cond,Object input){
if(cond instanceof ASTUnaryBinaryCondition){
return processUnaryBinaryCondition((ASTUnaryBinaryCondition)cond,input);
}
else if (cond instanceof ASTAggregatedCondition){
ASTCondition left = ((ASTAggregatedCondition)cond).getLeftOp();
Object output1 = processCondition(left,input);
ASTCondition right = ((ASTAggregatedCondition)cond).getRightOp();
Object output2 = processCondition(right,output1);
return merge(output1,output2);
}
else{
throw new RuntimeException("Unknown ASTCondition found in structred flow analysis");
}
}
/*
* The parameter body contains the body to be analysed
* It can be an ASTNode, a Stmt, an augmentedStmt or a list of ASTNodes
* The input is any data that is gathered plus any info needed for making
* decisions during the analysis
*/
public Object process(Object body, Object input){
if(!(input instanceof DavaFlowSet))
throw new RuntimeException("process method of StructuredAnalysis invoked with non DavaFlowSet object");
if(body instanceof ASTNode){
beforeSets.put(body,input);
Object temp=processASTNode((ASTNode)body,input);
afterSets.put(body,temp);
return temp;
}
else if(body instanceof Stmt){
beforeSets.put(body,input);
Object result=processAbruptStatements((Stmt)body,(DavaFlowSet)input);
afterSets.put(body,result);
return result;
}
else if (body instanceof AugmentedStmt){
AugmentedStmt as = (AugmentedStmt)body;
Stmt s = as.get_Stmt();
beforeSets.put(s,input);
Object result=processAbruptStatements(s,(DavaFlowSet)input);
afterSets.put(s,result);
return result;
}
else if (body instanceof List){
//this should always be a list of ASTNodes
Iterator it = ((List)body).iterator();
Object result=input;
while(it.hasNext()){
Object temp = it.next();
if(!(temp instanceof ASTNode))
throw new RuntimeException("Body sent to be processed by "+
"StructuredAnalysis contains a list which does not have ASTNodes");
else{
/*
As we are simply going through a list of ASTNodes
The output of the previous becomes the input of the next
*/
beforeSets.put(temp,result);
result= processASTNode((ASTNode)temp,result);
afterSets.put(temp,result);
}
}//end of going through list
//at this point the result var contains the result of processing the List
return result;
}
else{
throw new RuntimeException("Body sent to be processed by "+
"StructuredAnalysis is not a valid body");
}
}
/*
* This method internally invoked by the process method decides which ASTNode
* specialized method to call
*/
public Object processASTNode(ASTNode node, Object input){
if(node instanceof ASTDoWhileNode){
return processASTDoWhileNode((ASTDoWhileNode)node,input);
}
else if(node instanceof ASTForLoopNode){
return processASTForLoopNode((ASTForLoopNode)node,input);
}
else if(node instanceof ASTIfElseNode){
return processASTIfElseNode((ASTIfElseNode)node,input);
}
else if(node instanceof ASTIfNode){
return processASTIfNode((ASTIfNode)node,input);
}
else if(node instanceof ASTLabeledBlockNode){
return processASTLabeledBlockNode((ASTLabeledBlockNode)node,input);
}
else if(node instanceof ASTMethodNode){
return processASTMethodNode((ASTMethodNode)node,input);
}
else if(node instanceof ASTStatementSequenceNode){
return processASTStatementSequenceNode((ASTStatementSequenceNode)node,input);
}
else if(node instanceof ASTSwitchNode){
return processASTSwitchNode((ASTSwitchNode)node,input);
}
else if(node instanceof ASTSynchronizedBlockNode){
return processASTSynchronizedBlockNode((ASTSynchronizedBlockNode)node,input);
}
else if(node instanceof ASTTryNode){
return processASTTryNode((ASTTryNode)node,input);
}
else if(node instanceof ASTWhileNode){
return processASTWhileNode((ASTWhileNode)node,input);
}
else if(node instanceof ASTUnconditionalLoopNode){
return processASTUnconditionalLoopNode((ASTUnconditionalLoopNode)node,input);
}
else{
throw new RuntimeException("processASTNode called using unknown node type");
}
}
/**
* This method is called from the specialized ASTNodes.
* The purpose was to deal with different ASTNodes with similar structure in one
* go. The method will deal with retrieve the body of the ASTNode which are known
* to have only one subBody
*/
public final Object processSingleSubBodyNode(ASTNode node, Object input){
//get the subBodies
List<Object> subBodies = node.get_SubBodies();
if(subBodies.size()!=1){
throw new RuntimeException("processSingleSubBodyNode called with a node without one subBody");
}
//we know there is only one
List subBody = (List)subBodies.get(0);
return process(subBody,input);
}
/**
* returns label on the ASTNode
* null if the ASTNode cannot hold a label or if the label is null
*/
public String getLabel(ASTNode node){
if(node instanceof ASTLabeledNode){
Object temp = ((ASTLabeledNode)node).get_Label();
if(temp != null)
return temp.toString();
}
return null;
}
/**
* Whenever a statement has to be processed the first step is to invoke this method.
* This is to remove the tedious work of adding code to deal with abrupt control flow
* from the programmer of the analysis.
* The method invokes the processStatement method for all other statements
*
* A programmer can decide to override this method if they want to do something specific
*/
public Object processAbruptStatements(Stmt s, DavaFlowSet input){
if(s instanceof ReturnStmt || s instanceof RetStmt || s instanceof ReturnVoidStmt){
//dont need to remember this path
return NOPATH;
}
else if(s instanceof DAbruptStmt){
DAbruptStmt abStmt = (DAbruptStmt)s;
//see if its a break or continue
if(!(abStmt.is_Continue()|| abStmt.is_Break())){
//DAbruptStmt is of only two kinds
throw new RuntimeException("Found a DAbruptStmt which is neither break nor continue!!");
}
DavaFlowSet temp = NOPATH;
SETNodeLabel nodeLabel = abStmt.getLabel();
//System.out.println("here");
if(nodeLabel != null && nodeLabel.toString() != null){
//explicit abrupt stmt
if(abStmt.is_Continue())
temp.addToContinueList(nodeLabel.toString(),input);
else if (abStmt.is_Break())
temp.addToBreakList(nodeLabel.toString(),input);
else
throw new RuntimeException("Found abruptstmt which is neither break nor continue");
}
else{
//found implicit break/continue
if(abStmt.is_Continue())
temp.addToImplicitContinues(abStmt,input);
else if (abStmt.is_Break())
temp.addToImplicitBreaks(abStmt,input);
else
throw new RuntimeException("Found abruptstmt which is neither break nor continue");
}
return temp;
}
else{
/**************************************************************/
/******ALL OTHER STATEMENTS HANDLED BY PROGRAMMER**************/
/**************************************************************/
return processStatement(s,input);
}
}
/*
* Notice Right now the output of the processing of method bodies
* is returned as the output. This only works for INTRA procedural
* Analysis. For accomodating INTER procedural analysis one needs
* to have a return list of all possible returns (stored in the flowset)
* And merge Returns with the output of normal execution of the body
*/
//reasoned about this....seems right!!
public Object processASTMethodNode(ASTMethodNode node,Object input){
Object temp = processSingleSubBodyNode(node,input);
return temp;
}
public Object processASTStatementSequenceNode(ASTStatementSequenceNode node,Object input){
List<Object> statements = node.getStatements();
Iterator<Object> it = statements.iterator();
Object output = cloneFlowSet(input);//needed if there are no stmts
while(it.hasNext()){
AugmentedStmt as = (AugmentedStmt)it.next();
Stmt s = as.get_Stmt();
/*
Since we are processing a list of statements the output of
previous is input of next
*/
output=process(s,output);
if(DEBUG_STATEMENTS){
System.out.println("After Processing statement "+s +output.toString());;
}
}
return output;
}
//reasoned about this....seems right!!
public Object processASTLabeledBlockNode(ASTLabeledBlockNode node,Object input){
Object output1 = processSingleSubBodyNode(node,input);
//handle break
String label = getLabel(node);
return handleBreak(label,output1,node);
}
public Object processASTSynchronizedBlockNode(ASTSynchronizedBlockNode node,Object input){
input = processSynchronizedLocal(node.getLocal(),input);
Object output = processSingleSubBodyNode(node,input);
String label = getLabel(node);
return handleBreak(label,output,node);
}
//reasoned about this....seems right!!
public Object processASTIfNode(ASTIfNode node,Object input){
input = processCondition(node.get_Condition(),input);
Object output1 = processSingleSubBodyNode(node,input);
//merge with input which tells if the cond did not evaluate to true
Object output2 = merge(input,output1);
//handle break
String label = getLabel(node);
Object temp= handleBreak(label,output2,node);
if(DEBUG_IF){
System.out.println("Exiting if node"+temp.toString());;
}
return temp;
}
public Object processASTIfElseNode(ASTIfElseNode node,Object input){
//get the subBodies
List<Object> subBodies = node.get_SubBodies();
if(subBodies.size()!=2){
throw new RuntimeException("processASTIfElseNode called with a node without two subBodies");
}
//we know there is only two subBodies
List subBodyOne = (List)subBodies.get(0);
List subBodyTwo = (List)subBodies.get(1);
//process Condition
input = processCondition(node.get_Condition(),input);
//the current input flowset is sent to both branches
Object clonedInput = cloneFlowSet(input);
Object output1 = process(subBodyOne,clonedInput);
clonedInput = cloneFlowSet(input);
Object output2 = process(subBodyTwo,clonedInput);
Object temp=merge(output1,output2);
//notice we handle breaks only once since these are breaks to the same label or same node
String label = getLabel(node);
output1 = handleBreak(label,temp,node);
return output1;
}
public Object processASTWhileNode(ASTWhileNode node,Object input){
Object lastin=null;
Object initialInput = cloneFlowSet(input);
String label = getLabel(node);
Object output=null;
input = processCondition(node.get_Condition(),input);
if(DEBUG_WHILE)
System.out.println("Going int while (condition processed): "+input.toString());
do{
lastin = cloneFlowSet(input);
output = processSingleSubBodyNode(node,input);
//handle continue
output = handleContinue(label,output,node);
//merge with the initial input
input = merge(initialInput,output);
input = processCondition(node.get_Condition(),input);
} while(isDifferent(lastin,input));
//input contains the result of the fixed point
Object temp= handleBreak(label,input,node);
if(DEBUG_WHILE)
System.out.println("Going out of while: "+temp.toString());
return temp;
}
public Object processASTDoWhileNode(ASTDoWhileNode node, Object input){
Object lastin=null,output=null;
Object initialInput = cloneFlowSet(input);
String label = getLabel(node);
if(DEBUG_WHILE)
System.out.println("Going into do-while: "+initialInput.toString());
do{
lastin = cloneFlowSet(input);
output = processSingleSubBodyNode(node,input);
//handle continue
output = handleContinue(label,output,node);
output = processCondition(node.get_Condition(),output);
//merge with the initial input
input = merge(initialInput,output);
} while(isDifferent(lastin,input));
//output contains the result of the fixed point since do-while breaks of at the processing of cond
Object temp= handleBreak(label,output,node);
if(DEBUG_WHILE)
System.out.println("Going out of do-while: "+temp.toString());
return temp;
}
public Object processASTUnconditionalLoopNode(ASTUnconditionalLoopNode node,Object input){
//an unconditional loop behaves almost like a conditional While loop
Object initialInput = cloneFlowSet(input);
Object lastin=null;
if(DEBUG_WHILE)
System.out.println("Going into while(true): "+initialInput.toString());
String label = getLabel(node);
Object output=null;
do{
lastin = cloneFlowSet(input);
output = processSingleSubBodyNode(node,input);
//handle continue
output = handleContinue(label,output,node);
//merge this with the initial input
input = merge(initialInput,output);
} while(isDifferent(lastin,input));
//the output is not part of the set returned
//it is just used to retireve the set of breaklists stored for this label
Object temp = getMergedBreakList(label,output,node);
if(DEBUG_WHILE)
System.out.println("Going out of while(true): "+temp.toString());
return temp;
}
public Object processASTForLoopNode(ASTForLoopNode node,Object input){
List<Object> init = node.getInit();
Iterator<Object> it = init.iterator();
while(it.hasNext()){
AugmentedStmt as = (AugmentedStmt)it.next();
Stmt s = as.get_Stmt();
input = process(s,input);
}
//finished processing the init part of the for loop
Object initialInput = cloneFlowSet(input);
input = processCondition(node.get_Condition(),input);
Object lastin = null;
String label = getLabel(node);
Object output2=null;
do{
lastin = cloneFlowSet(input);
//process body
Object output1 = processSingleSubBodyNode(node,input);
//handle continues (Notice this is done before update!!!)
output1 = handleContinue(label,output1,node);
//notice that we dont merge with the initial output1 from processing singleSubBody
//the handlecontinue function takes care of it
//handle update
output2 = cloneFlowSet(output1);//if there is nothing in update
List<Object> update = node.getUpdate();
it = update.iterator();
while(it.hasNext()){
AugmentedStmt as = (AugmentedStmt)it.next();
Stmt s = as.get_Stmt();
/*
Since we are just going over a list of statements
the output of each statement is the input of the next
*/
output2 = process(s,output2);
}
//output2 is the final result
//merge this with the input
input = merge(initialInput,output2);
input = processCondition(node.get_Condition(),input);
}while(isDifferent(lastin,input));
//handle break
return handleBreak(label,input,node);
}
/*
* Notice ASTSwitch is horribly conservative....eg. if all cases break properly
* it will still merge with defaultOut which will be a NOPATH and bound to have empty or full sets
*/
public Object processASTSwitchNode(ASTSwitchNode node,Object input){
if(DEBUG)
System.out.println("Going into switch: "+input.toString());
List<Object> indexList = node.getIndexList();
Map<Object, List<Object>> index2BodyList = node.getIndex2BodyList();
Iterator<Object> it = indexList.iterator();
input=processSwitchKey(node.get_Key(),input);
Object initialIn = cloneFlowSet(input);
Object out = null;
Object defaultOut = null;
List<Object> toMergeBreaks = new ArrayList<Object>();
while (it.hasNext()) {//going through all the cases of the switch statement
Object currentIndex = it.next();
List body = index2BodyList.get( currentIndex);
//BUG FIX if body is null (fall through we shouldnt invoke process
//Reported by Steffen Pingel 14th Jan 2006 on the soot mailing list
if(body != null){
out=process(body,input);
// System.out.println("Breaklist for this out is"+out.getBreakList());
toMergeBreaks.add(cloneFlowSet(out));
if(currentIndex instanceof String){
//this is the default
defaultOut=out;
}
//the input to the next can be a fall through or directly input
input=merge(out,initialIn);
}//body was non null
}
//have to handle the case when no case matches. The input is the output
Object output=null;
if(out!=null){//just to make sure that there were some cases present
/*
* January 30th 2006, FOUND BUG
* The initialIn should only be merge with the out if there is no default
* in the list of switch cases
* If there is a default then there is no way that the initialIn is the actual
* result. Then its either the default or one of the outs!!!
*/
if(defaultOut!=null){
//there was a default
//System.out.println("DEFAULTSET");
//System.out.println("defaultOut is"+defaultOut);
//System.out.println("out is"+out);
output=merge(defaultOut,out);
}else{
//there was no default so no case might match
output = merge(initialIn,out);
}
}
else
output = initialIn;
//handle break
String label = getLabel(node);
//have to handleBreaks for all the different cases
List<Object> outList = new ArrayList<Object>();
//handling breakLists of each of the toMergeBreaks
it = toMergeBreaks.iterator();
while(it.hasNext()){
outList.add(handleBreak(label,it.next(),node));
}
//merge all outList elements. since these are the outputs with breaks handled
Object finalOut=output;
it = outList.iterator();
while(it.hasNext()){
finalOut = merge(finalOut,it.next());
}
if(DEBUG)
System.out.println("Going out of switch: "+finalOut.toString());
return finalOut;
}
public Object processASTTryNode(ASTTryNode node,Object input){
if(DEBUG_TRY)
System.out.println("TRY START is:"+input);
//System.out.println("SET beginning of tryBody is:"+input);
List<Object> tryBody = node.get_TryBody();
Object tryBodyOutput = process(tryBody,input);
//System.out.println("SET end of tryBody is:"+tryBodyOutput);
/*
By default take either top or bottom as the input to the catch statements
Which goes in depends on the type of analysis.
*/
Object inputCatch = newInitialFlow();
if(DEBUG_TRY)
System.out.println("TRY initialFLOW is:"+inputCatch);
List<Object> catchList = node.get_CatchList();
Iterator<Object> it = catchList.iterator();
List<Object> catchOutput = new ArrayList<Object>();
while (it.hasNext()) {
ASTTryNode.container catchBody = (ASTTryNode.container)it.next();
List body = (List)catchBody.o;
//list of ASTNodes
//result because of going through the catchBody
Object tempResult = process(body,cloneFlowSet(inputCatch));
//System.out.println("TempResult going through body"+tempResult);
catchOutput.add(tempResult);
}
//handle breaks
String label = getLabel(node);
/*
* 30th Jan 2005,
* Found bug in handling out breaks
* what was being done was that handleBreak was invoked using just handleBreak(label,tryBodyoutput,node)
* Now what it does is that it looks for the breakList stored in the tryBodyOutput node
* What might happen is that there might be some breaks in the catchOutput which would have gotten
* stored in the breakList of the respective catchoutput
*
* The correct way to handle this is create a list of handledBreak objects (in the outList)
* And then to merge them
*/
List<Object> outList = new ArrayList<Object>();
//handle breaks out of tryBodyOutput
outList.add(handleBreak(label,tryBodyOutput,node));
//System.out.println("After handling break from tryBodyOutput"+outList.get(0));
//handling breakLists of each of the catchOutputs
it = catchOutput.iterator();
while(it.hasNext()){
Object temp = handleBreak(label,it.next(),node);
if(DEBUG_TRY)
System.out.println("TRY handling breaks is:"+temp);
outList.add(temp);
}
//merge all outList elements. since these are the outputs with breaks handled
Object out=tryBodyOutput;
it = outList.iterator();
while(it.hasNext()){
out = merge(out,it.next());
}
if(DEBUG_TRY)
System.out.println("TRY after merge outList is:"+out);
//System.out.println("After handling break"+out);
it = catchOutput.iterator();
while(it.hasNext()){
out = merge(out,it.next());
}
if(DEBUG_TRY)
System.out.println("TRY END RESULT is:"+out);
return out;
}
/*
MERGETYPE var has to be set
0, means no type set
1, means union
2, means intersection
*/
public Object merge(Object obj1, Object obj2){
if(MERGETYPE==0)
throw new RuntimeException("Use the setMergeType method to set the type of merge used in the analysis");
if( !(obj1 instanceof DavaFlowSet) || !(obj2 instanceof DavaFlowSet) ){
/* if(obj1 instanceof DavaFlowSet)
System.out.println("obj1 is a davaflowset");
else
System.out.println("obj1 is NOT a davaflowset");
if(obj2 instanceof DavaFlowSet)
System.out.println("obj2 is a davaflowset");
else
System.out.println("obj2 is NOT a davaflowset"+obj2);
*/
throw new RuntimeException("merge not implemented for other flowSet types");
}
DavaFlowSet in1 = (DavaFlowSet)obj1;
DavaFlowSet in2 = (DavaFlowSet)obj2;
DavaFlowSet out;
if(in1 == NOPATH && in2 != NOPATH){
out = in2.clone();
out.copyInternalDataFrom(in1);
return out;
}
else if(in1 != NOPATH && in2 == NOPATH){
out = in1.clone();
out.copyInternalDataFrom(in2);
return out;
}
else if(in1 == NOPATH && in2 == NOPATH){
out = in1.clone();
out.copyInternalDataFrom(in2);
return out; //meaning return NOPATH
}
else{//both are not NOPATH
out = emptyFlowSet();
if(MERGETYPE==1)//union
((DavaFlowSet)obj1).union((DavaFlowSet)obj2, out);
else if(MERGETYPE==2)//intersection
((DavaFlowSet)obj1).intersection((DavaFlowSet)obj2, out);
else
throw new RuntimeException("Merge type value"+MERGETYPE+" not recognized");
out.copyInternalDataFrom(obj1);
out.copyInternalDataFrom(obj2);
return out;
}
}
public Object mergeExplicitAndImplicit(String label,DavaFlowSet output,List explicitSet, List implicitSet){
Object toReturn = output.clone();
if(label!=null){
//use the explicit list
/*
If there is no list associated with this label
or the list is empty
there no explicit merging to be done
*/
if(explicitSet != null && explicitSet.size()!=0){
//explicitSet is a list of DavaFlowSets
Iterator it = explicitSet.iterator();
//we know there is atleast one element
toReturn = merge(output,it.next());
while(it.hasNext()){
//merge this with toReturn
toReturn = merge(toReturn,it.next());
}
}//a non empty explicitSet was found
}//label not null could have explicit sets
//toReturn contains result of dealing with explicit stmts
//dealing with implicit set now
if(implicitSet != null){
//implicitSet is a list of DavaFlowSets
Iterator it = implicitSet.iterator();
while(it.hasNext()){
//merge this with toReturn
toReturn = merge(toReturn,it.next());
}
}
return toReturn;
}
/**
* Need to handleBreak stmts
* There can be explicit breaks (in which case label is non null)
* There can always be implicit breaks
* ASTNode is non null
*/
public Object handleBreak(String label,Object output,ASTNode node){
if( !(output instanceof DavaFlowSet) )
throw new RuntimeException("handleBreak is only implemented for DavaFlowSet type");
DavaFlowSet out = (DavaFlowSet)output;
//get the explicit list with this label from the breakList
List explicitSet = out.getBreakSet(label);
//System.out.println("\n\nExplicit set is"+explicitSet);
//getting the implicit list now
if(node ==null)
throw new RuntimeException("ASTNode sent to handleBreak was null");
List implicitSet = out.getImplicitlyBrokenSets(node);
//System.out.println("\n\nImplicit set is"+implicitSet);
//invoke mergeExplicitAndImplicit
return mergeExplicitAndImplicit(label,out,explicitSet,implicitSet);
}
/**
* Need to handleContinue stmts
* There can be explicit continues (in which case label is non null)
* There can always be implicit continues
* ASTNode is non null
*/
public Object handleContinue(String label,Object output,ASTNode node){
if( !(output instanceof DavaFlowSet) )
throw new RuntimeException("handleContinue is only implemented for DavaFlowSet type");
DavaFlowSet out = (DavaFlowSet)output;
//get the explicit list with this label from the continueList
List explicitSet = out.getContinueSet(label);
//getting the implicit list now
if(node ==null)
throw new RuntimeException("ASTNode sent to handleContinue was null");
List implicitSet = out.getImplicitlyContinuedSets(node);
//invoke mergeExplicitAndImplicit
return mergeExplicitAndImplicit(label,out,explicitSet,implicitSet);
}
/**
* Invoked from within the UnconditionalWhile processing method
* Need to handle both explicit and implicit breaks
*/
private Object getMergedBreakList(String label,Object output,ASTNode node){
if( !(output instanceof DavaFlowSet) )
throw new RuntimeException("getMergedBreakList is only implemented for DavaFlowSet type");
List breakSet = ((DavaFlowSet)output).getBreakSet(label);
Object toReturn = null;
if(breakSet ==null){
//there is no list associated with this label hence no merging to be done
//since this is a call from unconditional this means there should have been an implicit break
toReturn = NOPATH;
}
else if(breakSet.size()==0){
//list is empty for this label hence no merging to be done
//since this is a call from unconditional this means there should have been an implicit break
toReturn = NOPATH;
}
else{
//breakSet is a list of DavaFlowSets
Iterator it = breakSet.iterator();
//we know there is atleast one element
//making sure we dont send NOPATH
toReturn = it.next();
while(it.hasNext()){
//merge this with toReturn
toReturn = merge(toReturn,it.next());
}
}//a non empty breakSet was found
//dealing with implicit set now
List implicitSet = ((DavaFlowSet)output).getImplicitlyBrokenSets(node);
if(implicitSet != null){
//implicitSet is a list of DavaFlowSets
Iterator it = implicitSet.iterator();
//making sure that we dont send NOPATH
if(implicitSet.size()>0)
toReturn = it.next();
while(it.hasNext()){
//merge this with toReturn
toReturn = merge(toReturn,it.next());
}
}
return toReturn;
}
public boolean isDifferent(Object oldObj, Object newObj){
if(oldObj instanceof DavaFlowSet && newObj instanceof DavaFlowSet){
if (((DavaFlowSet)oldObj).equals(newObj) && ((DavaFlowSet)oldObj).internalDataMatchesTo(newObj)){
//set matches and breaks and continues also match
//System.out.println("NOT DIFFERENT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
return false;
}
else{
//System.out.println(oldObj);
//System.out.println(newObj);
//System.out.println("DIFFERENT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
return true;
}
}
else
throw new RuntimeException("isDifferent not implemented for other flowSet types");
}
/*
* The before set contains the before set of an ASTNode , a Stmt , and AugmentedStmt,
* Notice for instance for a for loop
* we will get a before set before the loop and an after set after the loop
*
* we dont have info about before set before executing a particular stmt
* that kind of info is available if you know which stmt u want e.g. the update stmt
*/
public Object getBeforeSet(Object beforeThis){
return beforeSets.get(beforeThis);
}
public Object getAfterSet(Object afterThis){
return afterSets.get(afterThis);
}
public void debug(String methodName, String debug){
if(DEBUG)
System.out.println("Class: StructuredAnalysis MethodName: "+ methodName+ " DEBUG: "+debug);
}
public void debug(String debug){
if(DEBUG)
System.out.println("Class: StructuredAnalysis DEBUG: "+debug);
}
}