package dk.brics.jspointers.display; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Set; import dk.brics.jspointers.dataflow.DataflowGraph; import dk.brics.jspointers.dataflow.FlowNode; import dk.brics.jspointers.dataflow.IInvocation; import dk.brics.jspointers.lattice.contexts.NullContext; import dk.brics.jspointers.lattice.keys.Key; import dk.brics.jspointers.lattice.values.ApplyFunctionValue; import dk.brics.jspointers.lattice.values.CallFunctionValue; import dk.brics.jspointers.lattice.values.FunctionValue; import dk.brics.jspointers.lattice.values.NativeFunctionValue; import dk.brics.jspointers.lattice.values.UserFunctionValue; import dk.brics.jspointers.lattice.values.Value; import dk.brics.jspointers.solver.AnalysisResult; import dk.brics.jsutil.MultiMap; import dk.brics.jsutil.StringUtil; import dk.brics.tajs.flowgraph.Function; import dk.brics.tajs.flowgraph.nodes.CallNode; public class AnnotateJs { public static void annotateJavaScriptFile(String inputJsfile, String outputJsfile, DataflowGraph dataflow, AnalysisResult<Key,Set<Value>> result) throws IOException { MultiMap<Integer,IInvocation> linenr2callsites = new MultiMap<Integer, IInvocation>(); for (FlowNode node : dataflow.getNodes()) { if (node instanceof IInvocation) { IInvocation invoke = (IInvocation)node; CallNode call = dataflow.getCalls().getBackward(invoke); if (call.getSourceLocation().getFileName().equals(inputJsfile)) { linenr2callsites.add(call.getSourceLocation().getLineNumber(), invoke); } } } MultiMap<Key,Value> map = DisplayUtil.makeContextInsensitive(result); result = null; BufferedReader reader = null; BufferedWriter writer = null; DisplayUtil util = new DisplayUtil(map, dataflow); try { reader = new BufferedReader(new FileReader(inputJsfile)); writer = new BufferedWriter(new FileWriter(outputJsfile)); int linenr = 1; for (String line = reader.readLine(); line!=null; line=reader.readLine()) { writer.append(line); for (IInvocation callsite : linenr2callsites.getView(linenr)) { writer.append(" // CallTargets["); boolean first=true; for (Value val : util.getFunctionArgs(callsite)) { if (!(val instanceof FunctionValue)) continue; FunctionValue fval = (FunctionValue)val; if (!first) writer.append(", "); else first = false; writer.append(getFunctionName(fval, dataflow)); if (fval instanceof CallFunctionValue || fval instanceof ApplyFunctionValue) { // print called function (only one level, not recursively) writer.append("->{"); boolean innerFirst=true; for (Value subvalue : map.getView(callsite.getBase().getKey(NullContext.Instance))) { if (!(subvalue instanceof FunctionValue)) continue; FunctionValue subf = (FunctionValue)subvalue; if (!innerFirst) writer.append(","); else innerFirst=false; writer.append(getFunctionName(subf, dataflow)); } writer.append("}"); } } writer.append("]"); } writer.append("\n"); linenr++; } } finally { if (reader != null) reader.close(); if (writer != null) writer.close(); } } private static String getFunctionName(FunctionValue value, DataflowGraph dataflow) { if (value instanceof UserFunctionValue) { UserFunctionValue uf = (UserFunctionValue)value; Function callee = uf.getFunction(); if (dataflow.getHarnessFunctions().contains(callee)) { if (callee.getName() != null) return "native:" + callee.getName(); else return "native:" + StringUtil.removePathInfo(callee.getSourceLocation().getFileName()) + ":" + callee.getSourceLocation().getLineNumber(); } else { return ""+callee.getSourceLocation().getLineNumber(); } } else { NativeFunctionValue nf = (NativeFunctionValue)value; return "native:" + nf.getPrettyName(); } } }