incorporate changes from other branch
- basic compatibility with Java 7 (i.e., don't crash immediately) - Added utility class for converting call graphs to JSON. - add edgeExists CLI option to check if some edge exists in the call graph
This commit is contained in:
parent
883b5f2437
commit
b8477d2144
|
@ -37,6 +37,7 @@ import com.ibm.wala.ipa.callgraph.CallGraph;
|
|||
import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.util.collections.Iterator2Iterable;
|
||||
import com.ibm.wala.util.io.CommandLine;
|
||||
import com.ibm.wala.util.io.FileProvider;
|
||||
|
||||
|
@ -168,6 +169,13 @@ public class HTMLCGBuilder {
|
|||
if (parsedArgs.containsKey("reachable")) {
|
||||
reachableName = parsedArgs.getProperty("reachable");
|
||||
}
|
||||
|
||||
String srcNode = null, dstNode = null;
|
||||
if (parsedArgs.containsKey("edgeExists")) {
|
||||
String[] nodes = parsedArgs.getProperty("edgeExists").split(":");
|
||||
srcNode = nodes[0];
|
||||
dstNode = nodes[1];
|
||||
}
|
||||
// suppress debug output
|
||||
JavaScriptFunctionDotCallTargetSelector.WARN_ABOUT_IMPRECISE_CALLGRAPH = false;
|
||||
CGBuilderResult res = buildHTMLCG(src, timeout, true, AstTranslator.NEW_LEXICAL ? CGBuilderType.ONE_CFA_PRECISE_LEXICAL : CGBuilderType.ZERO_ONE_CFA);
|
||||
|
@ -183,5 +191,16 @@ public class HTMLCGBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (srcNode != null) {
|
||||
for (CGNode node : res.cg) {
|
||||
if (node.getMethod().getDeclaringClass().getName().toString().endsWith(srcNode)) {
|
||||
for (CGNode callee : Iterator2Iterable.make(res.cg.getSuccNodes(node))) {
|
||||
if (callee.getMethod().getDeclaringClass().getName().toString().endsWith(dstNode)) {
|
||||
System.out.println("EDGE EXISTS");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/******************************************************************************
|
||||
* Copyright (c) 2002 - 2012 IBM Corporation.
|
||||
* 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
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*****************************************************************************/
|
||||
package com.ibm.wala.cast.js.util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.cast.js.types.JavaScriptMethods;
|
||||
import com.ibm.wala.cast.loader.AstMethod;
|
||||
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
|
||||
import com.ibm.wala.cast.types.AstMethodReference;
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.MapUtil;
|
||||
import com.ibm.wala.util.collections.Util;
|
||||
import com.ibm.wala.util.functions.Function;
|
||||
|
||||
/**
|
||||
* Utility class to serialize call graphs as JSON objects.
|
||||
*
|
||||
* The serialised objects have the form
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "<callsite1>": [ "<callee1>", "<callee2>", ... ],
|
||||
* "<callsite2>": ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* where both call sites and callees are encoded as strings
|
||||
* of the form
|
||||
*
|
||||
* <pre>
|
||||
* "<filename>@<lineno>:<beginoff>-<endoff>"
|
||||
* </pre>
|
||||
*
|
||||
* Here, <code>filename</code> is the name of the containing
|
||||
* JavaScript file (not including its directory), and
|
||||
* <code>lineno</code>, <code>beginoff</code> and <code>endoff</code>
|
||||
* encode the source position of the call expression (for
|
||||
* call sites) or the function declaration/expression (for
|
||||
* callees) inside the file in terms of its starting line,
|
||||
* its starting offset (in characters from the beginning of the
|
||||
* file), and its end offset.
|
||||
*
|
||||
* @author mschaefer
|
||||
*/
|
||||
public class CallGraph2JSON {
|
||||
public static boolean IGNORE_HARNESS = true;
|
||||
|
||||
public static String serialize(CallGraph cg) {
|
||||
Map<String, Set<String>> edges = extractEdges(cg);
|
||||
return toJSON(edges);
|
||||
}
|
||||
|
||||
public static Map<String, Set<String>> extractEdges(CallGraph cg) {
|
||||
Map<String, Set<String>> edges = HashMapFactory.make();
|
||||
for(CGNode nd : cg) {
|
||||
if(!isRealFunction(nd.getMethod()))
|
||||
continue;
|
||||
AstMethod method = (AstMethod)nd.getMethod();
|
||||
|
||||
for(Iterator<CallSiteReference> iter = nd.iterateCallSites(); iter.hasNext();) {
|
||||
CallSiteReference callsite = iter.next();
|
||||
Set<IMethod> targets = Util.mapToSet(cg.getPossibleTargets(nd, callsite), new Function<CGNode, IMethod>() {
|
||||
@Override
|
||||
public IMethod apply(CGNode nd) {
|
||||
return nd.getMethod();
|
||||
}
|
||||
});
|
||||
serializeCallSite(method, callsite, targets, edges);
|
||||
}
|
||||
}
|
||||
return edges;
|
||||
}
|
||||
|
||||
public static void serializeCallSite(AstMethod method, CallSiteReference callsite, Set<IMethod> targets,
|
||||
Map<String, Set<String>> edges) {
|
||||
Set<String> targetNames = MapUtil.findOrCreateSet(edges, ppPos(method, method.getSourcePosition(callsite.getProgramCounter())));
|
||||
for(IMethod target : targets) {
|
||||
target = getCallTargetMethod(target);
|
||||
if(!isRealFunction(target))
|
||||
continue;
|
||||
targetNames.add(ppPos((AstMethod)target, ((AstMethod)target).getSourcePosition()));
|
||||
}
|
||||
}
|
||||
|
||||
private static IMethod getCallTargetMethod(IMethod method) {
|
||||
if(method.getName().equals(JavaScriptMethods.ctorAtom)) {
|
||||
method = method.getDeclaringClass().getMethod(AstMethodReference.fnSelector);
|
||||
if(method != null)
|
||||
return method;
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
public static boolean isRealFunction(IMethod method) {
|
||||
if(method instanceof AstMethod) {
|
||||
String methodName = method.getDeclaringClass().getName().toString();
|
||||
|
||||
// exclude synthetic DOM modelling functions
|
||||
if(methodName.contains("/make_node"))
|
||||
return false;
|
||||
|
||||
if(IGNORE_HARNESS && methodName.startsWith("Lprologue.js/") || methodName.startsWith("Lpreamble.js/"))
|
||||
return false;
|
||||
|
||||
return method.getName().equals(AstMethodReference.fnAtom);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String ppPos(AstMethod method, Position pos) {
|
||||
String file = pos.getURL().getFile();
|
||||
file = file.substring(file.lastIndexOf('/')+1);
|
||||
|
||||
int line = pos.getFirstLine(), start_offset = pos.getFirstOffset(), end_offset = pos.getLastOffset();
|
||||
return file + "@" + line + ":" + start_offset + "-" + end_offset;
|
||||
}
|
||||
|
||||
public static String toJSON(Map<String, Set<String>> map) {
|
||||
StringBuffer res = new StringBuffer();
|
||||
res.append("{\n");
|
||||
res.append(joinWith(Util.mapToSet(map.entrySet(), new Function<Map.Entry<String, Set<String>>, String>() {
|
||||
@Override
|
||||
public String apply(Map.Entry<String, Set<String>> e) {
|
||||
StringBuffer res = new StringBuffer();
|
||||
if(e.getValue().size() > 0) {
|
||||
res.append(" \"" + e.getKey() + "\": [\n");
|
||||
res.append(joinWith(Util.mapToSet(e.getValue(), new Function<String, String>() {
|
||||
@Override
|
||||
public String apply(String str) {
|
||||
return " \"" + str + "\"";
|
||||
}
|
||||
}), ",\n"));
|
||||
res.append("\n ]");
|
||||
}
|
||||
return res.length() == 0 ? null : res.toString();
|
||||
}
|
||||
}), ",\n"));
|
||||
res.append("\n}");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
private static String joinWith(Iterable<String> lst, String sep) {
|
||||
StringBuffer res = new StringBuffer();
|
||||
ArrayList<String> strings = new ArrayList<String>();
|
||||
for(String s : lst)
|
||||
if(s != null)
|
||||
strings.add(s);
|
||||
|
||||
boolean fst = true;
|
||||
for(String s : strings) {
|
||||
if(fst)
|
||||
fst = false;
|
||||
else
|
||||
res.append(sep);
|
||||
res.append(s);
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ public class LibraryVersionTest extends WalaTestCase {
|
|||
@Test public void testLibraryVersion() throws IOException {
|
||||
AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER);
|
||||
System.err.println("java library version is " + scope.getJavaLibraryVersion());
|
||||
Assert.assertTrue(scope.isJava16Libraries() || scope.isJava15Libraries()||scope.isJava14Libraries());
|
||||
Assert.assertTrue(scope.isJava17Libraries() || scope.isJava16Libraries() || scope.isJava15Libraries()||scope.isJava14Libraries());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ public class DataflowTest extends WalaTestCase {
|
|||
public static void beforeClass() throws Exception {
|
||||
|
||||
scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
|
||||
(new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), DataflowTest.class.getClassLoader());
|
||||
(new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), DataflowTest.class.getClassLoader());
|
||||
|
||||
try {
|
||||
cha = ClassHierarchy.make(scope);
|
||||
|
|
|
@ -411,6 +411,10 @@ public class AnalysisScope {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isJava17Libraries() throws IllegalStateException {
|
||||
return getJavaLibraryVersion().startsWith("1.7");
|
||||
}
|
||||
|
||||
public boolean isJava16Libraries() throws IllegalStateException {
|
||||
return getJavaLibraryVersion().startsWith("1.6");
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public final class ClassReader implements ClassConstants {
|
|||
if (magic != MAGIC) {
|
||||
throw new InvalidClassFileException(offset, "bad magic number: " + magic);
|
||||
}
|
||||
if (majorVersion < 45 || majorVersion > 50) {
|
||||
if (majorVersion < 45 || majorVersion > 51) {
|
||||
throw new InvalidClassFileException(offset, "unknown class file version: " + majorVersion + "." + minorVersion);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue