/* * (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 * */ package com.logicalhacking.dasca.crosslanguage.cg; import com.ibm.wala.ipa.callgraph.CGNode import com.logicalhacking.dasca.crosslanguage.builder.MergedCallGraph import scala.collection.JavaConversions._ import com.ibm.wala.classLoader.CallSiteReference object CallTreeBuilder { def buildCallForest(cg: MergedCallGraph, sources: List[CGNode], sinks: List[CGNode]): List[CallTree] = { 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 } } def buildCallTree(cg: MergedCallGraph, root: CGNode, sinks: List[CGNode]): CallTree = { buildCallTree(cg, 0, root, sinks) } 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 // 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 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 } else { 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) { return null //return new CallTree(root, children) } else { return new CallTree(root, children) } } } }