package ai.actions;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import ai.JavaAIPlugin;
import ai.Utils;
import ai.cfg.CFGVertice;
import ai.cfg.InterestingCodeFragment;
import ai.cfg.MethodCFGBuilder;
import ai.cfg.MethodControlFlowGraph;
import ai.cfg.MethodFinder;
import ai.domain.AbstractSemanticsIntf;
import ai.domain.DomainIntf;
import ai.domain.bool.Bool;
import ai.domain.boolintv.BoolIntvSemantics;
import ai.domain.boxes.BoxesWideningFactory;
import ai.domain.boxes.IntegerBoxes;
import ai.domain.boxes.IntegerBoxesHelper;
import ai.domain.boxes.IntegerBoxesSemantics;
import ai.domain.generic.NonRelationalDomain;
import ai.domain.generic.ProductDomain;
import ai.domain.interval.Interval;
import ai.plugin.preferences.PreferenceConstants;
/**
* Our sample action implements workbench action delegate. The action proxy will
* be created by the workbench and shown in the UI. When the user tries to use
* the action, this delegate will be created and execution will be delegated to
* it.
*
* @see IWorkbenchWindowActionDelegate
*/
public class AnalyseBoxesAction implements IWorkbenchWindowActionDelegate {
{
BasicConfigurator.configure();
Logger logger = Logger.getRootLogger();
logger.setLevel(Level.ERROR);
}
private IWorkbenchWindow window;
private ITreeSelection selection;
/**
* The constructor.
*/
public AnalyseBoxesAction() {
}
private static class ComparisonResults {
// private final List<CFGVertice> boxesBetter = new
// LinkedList<CFGVertice>();
// private final List<CFGVertice> intvBeter = new
// LinkedList<CFGVertice>();
// private final List<CFGVertice> uncomparable = new
// LinkedList<CFGVertice>();
private int boxesBetter = 0;
private int intvBetter = 0;
private int uncomparable = 0;
private int totalCount = 0;
public void boxesBetter(CFGVertice vertice) {
totalCount += 1;
boxesBetter += 1;
}
public void intvBetter(CFGVertice vertice) {
totalCount += 1;
intvBetter += 1;
}
public void uncomparable(CFGVertice vertice) {
totalCount += 1;
uncomparable += 1;
}
public void equal(CFGVertice vertice) {
totalCount += 1;
}
public String toString() {
StringBuilder builder = new StringBuilder("Comparison Results:\n");
builder.append("TOTAL: " + totalCount + "\n");
builder.append("BOXES BETTER: " + boxesBetter + "\n");
builder.append("INTV BETTER: " + intvBetter + "\n");
builder.append("UNCOMPARABLE: " + uncomparable + "\n");
return builder.toString();
}
}
/**
* The action has been activated. The argument of the method represents the
* 'real' action sitting in the workbench UI.
*
* @see IWorkbenchWindowActionDelegate#run
*/
public void run(IAction action) {
if (selection == null) {
MessageDialog.openInformation(window.getShell(), "Information", "No input files selected");
return;
}
int count = 0;
ComparisonResults comparisonResults = new ComparisonResults();
//read configuration
String boxesWideningDescription = JavaAIPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.P_BOXES_THRESHOLDS);
int timeoutSeconds = JavaAIPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.P_TIMEOUT);
IntegerBoxesSemantics semantics = new IntegerBoxesSemantics(boxesWideningDescription);
BoolIntvSemantics intv = new BoolIntvSemantics();
AnalysisErrorHandler aeh = new AnalysisErrorHandler();
try {
List<ICompilationUnit> allTasks = Utils.getSelectedIcu(selection);
for (ICompilationUnit icu : allTasks) {
count += processIcu(icu, semantics, intv, comparisonResults, aeh, timeoutSeconds);
}
} catch (JavaModelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.err.println("NON TRIVIAL POINTS: " + count);
System.err.println(comparisonResults);
}
private static <DI extends DomainIntf<DI>> Map<CFGVertice, DI> findNonTrivials(Map<CFGVertice, DI> analysisResult) {
Map<CFGVertice, DI> result = new HashMap<CFGVertice, DI>();
for (Map.Entry<CFGVertice, DI> entry : analysisResult.entrySet()) {
if (!entry.getValue().isTop())
result.put(entry.getKey(), entry.getValue());
}
return result;
}
private static <DI extends DomainIntf<DI>, DI2 extends DomainIntf<DI2>> int processIcu(ICompilationUnit icu,
AbstractSemanticsIntf<DI> semantics, AbstractSemanticsIntf<DI2> another, ComparisonResults results,
AnalysisErrorHandler aeh, int timeoutSeconds) {
Logger logger = Logger.getRootLogger();
logger.setLevel(Level.ERROR);
CompilationUnit cu = Utils.parse(icu);
int count = 0;
for (InterestingCodeFragment codeFragment: MethodFinder.findMethods(cu)) {
if (Prefs.ONLY_METHOD != null && !codeFragment.getUniqueName().equals(Prefs.ONLY_METHOD))
continue;
// build graph
MethodControlFlowGraph graph;
try {
graph = MethodCFGBuilder.buildCFG(codeFragment);
} catch (RuntimeException e) {
System.err.println("Error building graph for:" + codeFragment.getUniqueName());
e.printStackTrace(System.err);
throw e;
}
if (graph == null)
continue;
System.err.println("Built graph for: " + codeFragment.getUniqueName());
// analyse
Map<CFGVertice, DI> res = ExecutionUtils.analyseOne(graph, semantics, aeh, codeFragment, timeoutSeconds);
Map<CFGVertice, DI2> resAnother = ExecutionUtils.analyseOne(graph, another, aeh, codeFragment, timeoutSeconds*1000);
if (res == null || resAnother == null) // could have been timeout??
continue;
Map<CFGVertice, DI> nonTrivialPoints = findNonTrivials(res);
Map<CFGVertice, DI2> nonTrivialPoints2 = findNonTrivials(resAnother);
System.err.println("Analysed: " + codeFragment.getUniqueName());
System.err.println("Found1 " + nonTrivialPoints.size() + " non-trivial points");
System.err.println("Found2 " + nonTrivialPoints2.size() + " non-trivial points");
// compare results
for (Map.Entry<CFGVertice, DI> entry : res.entrySet()) {
CFGVertice key = entry.getKey();
DI value = entry.getValue();
compare(key, value, resAnother.get(key), results);
}
count += nonTrivialPoints.size();
}
return count;
}
private static <DI extends DomainIntf<DI>, DI2 extends DomainIntf<DI2>> void compare(CFGVertice vertice, DI value1,
DI2 value2, ComparisonResults cr) {
ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> boolIntv = (ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>>) value2;
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> boxes = (ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>) value1;
// compare both
if (boolIntv.isBottom()) {
if (!boxes.isBottom())
cr.intvBetter(vertice);
else
cr.equal(vertice);
return;
}
if (boxes.isBottom()) {
cr.boxesBetter(vertice);
return;
}
IntegerBoxes intvBox = IntegerBoxesHelper.fromIntervalBox(boolIntv.getRight());
IntegerBoxes boxesBox = boxes.getRight();
// compare
if (boxesBox.equals(intvBox)) {
cr.equal(vertice);
return;
}
if (boxesBox.leq(intvBox)) {
cr.boxesBetter(vertice);
return;
}
if (intvBox.leq(boxesBox)) {
cr.intvBetter(vertice);
return;
}
cr.uncomparable(vertice);
}
/**
* Selection in the workbench has been changed. We can change the state of
* the 'real' action here if we want, but this can only happen after the
* delegate has been created.
*
* @see IWorkbenchWindowActionDelegate#selectionChanged
*/
public void selectionChanged(IAction action, ISelection selection) {
if (selection instanceof ITreeSelection) {
this.selection = (ITreeSelection) selection;
}
}
/**
* We can use this method to dispose of any system resources we previously
* allocated.
*
* @see IWorkbenchWindowActionDelegate#dispose
*/
public void dispose() {
}
/**
* We will cache window object in order to be able to provide parent shell
* for the message dialog.
*
* @see IWorkbenchWindowActionDelegate#init
*/
public void init(IWorkbenchWindow window) {
this.window = window;
}
}