2016-09-08 08:50:45 +00:00
|
|
|
/*
|
|
|
|
* (C) Copyright 2016 The University of Sheffield.
|
|
|
|
*
|
|
|
|
* All rights reserved. This program and the accompanying materials
|
|
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
* which accompanies this distribution, and is available at
|
|
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-05-21 14:58:16 +00:00
|
|
|
package com.logicalhacking.dasca.crosslanguage.cg;
|
2016-09-08 08:50:45 +00:00
|
|
|
|
|
|
|
import com.ibm.wala.ipa.callgraph.CGNode
|
2017-05-21 14:58:16 +00:00
|
|
|
import com.logicalhacking.dasca.crosslanguage.builder.MergedCallGraph
|
2016-09-11 11:51:59 +00:00
|
|
|
import scala.collection.JavaConversions._
|
|
|
|
import com.ibm.wala.classLoader.CallSiteReference
|
2016-09-08 08:50:45 +00:00
|
|
|
|
2016-09-10 18:27:10 +00:00
|
|
|
object CallTreeBuilder {
|
2016-09-11 11:51:59 +00:00
|
|
|
|
2016-09-10 18:27:10 +00:00
|
|
|
def buildCallForest(cg: MergedCallGraph, sources: List[CGNode], sinks: List[CGNode]): List[CallTree] = {
|
2016-09-11 11:51:59 +00:00
|
|
|
buildCallForest(cg, 0, sources, sinks)
|
|
|
|
}
|
|
|
|
|
|
|
|
def buildCallForest(cg: MergedCallGraph, bound: Integer, sources: List[CGNode], sinks: List[CGNode]): List[CallTree] = {
|
|
|
|
return sources.map { src => buildCallTree(cg, bound, src, sinks) }.filterNot { x => null == x }
|
2016-09-10 18:27:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def buildCallTree(cg: MergedCallGraph, root: CGNode, sinks: List[CGNode]): CallTree = {
|
2016-09-11 11:51:59 +00:00
|
|
|
buildCallTree(cg, 0, root, sinks)
|
2016-09-10 18:27:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-11 11:51:59 +00:00
|
|
|
def buildCallTree(cg: MergedCallGraph, bound: Integer, root: CGNode, sinks: List[CGNode]): CallTree = {
|
|
|
|
build(cg, List[CGNode](), sinks, bound, 0, root)
|
|
|
|
}
|
|
|
|
|
|
|
|
private def build(cg: MergedCallGraph, visited: List[CGNode], sinks: List[CGNode], bound: Integer,
|
|
|
|
depth: Integer, root: CGNode): CallTree = {
|
|
|
|
if (bound > 0 && bound < depth) {
|
|
|
|
if (null == sinks) {
|
|
|
|
return new CallTree(root)
|
|
|
|
} else {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Base case
|
2016-09-13 11:05:00 +00:00
|
|
|
// root is one of the sinks (i.e., root is part of the analysed project and, thus, the
|
|
|
|
// call graph
|
|
|
|
if (sinks.contains(root))
|
|
|
|
return new CallTree(root)
|
|
|
|
|
|
|
|
// root is only part of the call sites iterator (i.e., defined outside of the analysis
|
|
|
|
// scope
|
2016-09-11 11:51:59 +00:00
|
|
|
val it = root.iterateCallSites()
|
|
|
|
var m = null: CallSiteReference
|
|
|
|
var children = List[CGNode]()
|
|
|
|
while (it.hasNext()) {
|
|
|
|
m = it.next()
|
|
|
|
children = children.union(sinks.filter { x => x.getMethod.getName().equals(m.getDeclaredTarget().getName()) })
|
|
|
|
}
|
|
|
|
if (!children.isEmpty) {
|
|
|
|
return new CallTree(root, children.map { x => new CallTree(x) })
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recursive case
|
|
|
|
val targetNodes = cg.getAllPossibleTargetNodes(root).filterNot { n => visited.contains(n) }
|
|
|
|
if (targetNodes.isEmpty) {
|
|
|
|
return null
|
2016-09-10 18:27:10 +00:00
|
|
|
} else {
|
2016-09-11 11:51:59 +00:00
|
|
|
val children = targetNodes.toList.map { x => build(cg, root :: (visited ++ targetNodes), sinks, bound, depth + 1, x) }
|
|
|
|
.filterNot { x => (null == x) }
|
|
|
|
if (children.isEmpty || null == children) {
|
2016-09-10 18:27:10 +00:00
|
|
|
return null
|
2016-09-11 11:51:59 +00:00
|
|
|
//return new CallTree(root, children)
|
2016-09-10 18:27:10 +00:00
|
|
|
} else {
|
|
|
|
return new CallTree(root, children)
|
2016-09-08 08:50:45 +00:00
|
|
|
}
|
2016-09-10 18:27:10 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-08 08:50:45 +00:00
|
|
|
}
|