/*
 * Menu: Indus > Mark Referred Allocation Sites
 * Script-Path: /Kaveri/monkey/ReferredAllocationSites.gm
 * Kudos: Venkatesh Prasad Ranganath (Santos Laboratory)
 * License: MPL 1.1
 * Job: UIJob
 * DOM: http://indus.projects.cis.ksu.edu/update/plugins/edu.ksu.cis.indus.kaveri
 * DOM: http://groovy-monkey.sourceforge.net/update/plugins/net.sf.groovyMonkey.dom
 * Include-Bundle: edu.ksu.cis.indus.kaveri
 */

 
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.resources.IMarker
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.ITextSelection;
import groovy.lang.Closure;
import java.util.Collection;
import edu.ksu.cis.indus.common.datastructures.Pair;
import edu.ksu.cis.indus.common.datastructures.Triple;
import edu.ksu.cis.indus.staticanalyses.dependency.IDependencyAnalysis;
import edu.ksu.cis.indus.tools.slicer.SlicerTool;
import edu.ksu.cis.indus.staticanalyses.flow.modes.sensitive.allocation.AllocationContext;
import soot.jimple.Stmt;
import soot.jimple.AssignStmt;
import soot.jimple.InstanceFieldRef;
import soot.jimple.ArrayRef;
import soot.RefType;
import soot.ArrayType;
def BANNER = "Calculating referring allocations for given variables..."
def SRC_MARK_DESC = "Referring source expression"
def DEST_MARK_DESC = "Referring allocation site"
def EMPTY_SELECTION_MSG = "There are no reference variables in the current selection."
def SOME_IN_BINARY_MSG = "There were some allocation sites in classes with no souce files."
def ENTITY_MSG = " allocation sites."
def INVALID_SELECTION_MSG = "Please select a line containing a reference variable in a Java file."
def EMPTY_RESULT_MSG = "There are no allocation sites for the reference variables in the current selection."
Collection getSrcExpressionsInSelection() {
	def r = slicer.getJimpleStmtsForSelection()
	def sootMethod = slicer.getJimpleMethodForSelection()
	def result = []
	r.each { stmt ->
		stmt.getUseAndDefBoxes().each { box ->
			def t = box.getValue().getType()
			if (t instanceof RefType || t instanceof ArrayType) {
				result << new Triple(box, stmt, sootMethod)
			}
		}
	}
	return result
}
Collection getAllocationSites(Collection exprs, NullProgressMonitor monitor) {
	def r = []
	def ofa = slicer.getOFAnalyzer()
	def ctxt = new AllocationContext()
	exprs.each { expr -> 
		if (monitor.isCanceled()) {
			return new HashSet(r)
		} 
		ctxt.setRootMethod(expr.getThird())
		ctxt.setStmt(expr.getSecond())
		def first = expr.getFirst()
		def value = first.getValue()
		if (value instanceof InstanceFieldRef || value instanceof ArrayRef) {
			ctxt.setProgramPoint(value.getBaseBox())
			receivers = ofa.getValues(value.getBase(), ctxt)
			if (value instanceof InstanceFieldRef) {
				r += ofa.getValues(value.getField(), receivers)
			} else {
				r += ofa.getValues(value.getBase().getType(), receivers)
			}
		} else {
			ctxt.setProgramPoint(first)
			r += ofa.getValues(value, ctxt)
		}		
	}
	return new HashSet(r)
}
Collection getDestExprs(Collection exprs, NullProgressMonitor monitor) {
	def allocs = getAllocationSites(exprs, monitor)
	def r = []
	slicer.getCallGraph().getReachableMethods().each { sm ->
		if (monitor.isCanceled()) {
			return new HashSet(r)
		} 
		if (sm.isConcrete() && sm.hasActiveBody()) {
			sm.getActiveBody().getUnits().each { stmt -> 
				stmt.getUseAndDefBoxes().each { box -> 
					if (allocs.contains(box.getValue())) {
						r << new Pair(stmt, sm)
					}
				}
			}
		}						
	}
	return new HashSet(r)
}
void bookmarkSelection(message, ts) {
    def selection = slicer.getSelection()
    m = slicer.getSelectionContainingFile().createMarker(IMarker.BOOKMARK)
    m.setAttribute(IMarker.MESSAGE, "[" + ts + "] " + message)
    m.setAttribute(IMarker.LINE_NUMBER, selection.getStartLine() + 1) // text editor uses 0-offset addressing for lines
}
boolean validSelectionExists() {
	def f = slicer.getSelectionContainingFile()
	def s = slicer.getSelection()
	def n = f.getName()
	return s instanceof ITextSelection && (n.indexOf(".java") == (n.size() - 5))
}
if (slicer.getSlicerTool().isStable()) {
	def monitor = new NullProgressMonitor()
	monitor.beginTask(BANNER, IProgressMonitor.UNKNOWN)
	if (!monitor.isCanceled()) {
		if (validSelectionExists()) {
			def ts = slicer.getCounter()
			bookmarkSelection(SRC_MARK_DESC, ts)
			def srcExprs = getSrcExpressionsInSelection()
			if (srcExprs.isEmpty()) {
				slicer.displayDialog(EMPTY_SELECTION_MSG)
			} else {
				def i = 0
				def b = true
				def destExprs = getDestExprs(srcExprs, monitor)
				if (!destExprs.isEmpty()) {
					destExprs.each { destExpr ->
						if (monitor.isCanceled()) {
							return
						}
						b &= slicer.createMarkerForSootStmtMethod(destExpr, DEST_MARK_DESC, ts)
						i++
					}
				}
				if (i == 0) {
					slicer.displayDialog(EMPTY_RESULT_MSG)
				} else {
					def msg = 'There were total of ' + i + ENTITY_MSG
					if (!b) {
						msg += SOME_IN_BINARY_MSG
					}
					slicer.displayDialog(msg)
					window.getActivePage().showView("org.eclipse.ui.views.BookmarkView")
				}
			}
		} else {
			slicer.displayDialog(INVALID_SELECTION_MSG)
		}
	}
	monitor.done()
} else {
	slicer.displayDialog("Please run the slicer before executing this script.")
}