package dk.brics.xact.analysis.soot;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import soot.ArrayType;
import soot.Local;
import soot.NullType;
import soot.RefLikeType;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Type;
import soot.Value;
import soot.ValueBox;
import soot.jimple.ArrayRef;
import soot.jimple.AssignStmt;
import soot.jimple.BreakpointStmt;
import soot.jimple.CastExpr;
import soot.jimple.DefinitionStmt;
import soot.jimple.EnterMonitorStmt;
import soot.jimple.ExitMonitorStmt;
import soot.jimple.FieldRef;
import soot.jimple.GotoStmt;
import soot.jimple.IdentityStmt;
import soot.jimple.IfStmt;
import soot.jimple.InstanceFieldRef;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InterfaceInvokeExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.InvokeStmt;
import soot.jimple.LookupSwitchStmt;
import soot.jimple.NewArrayExpr;
import soot.jimple.NewExpr;
import soot.jimple.NewMultiArrayExpr;
import soot.jimple.NopStmt;
import soot.jimple.NullConstant;
import soot.jimple.ParameterRef;
import soot.jimple.RetStmt;
import soot.jimple.ReturnStmt;
import soot.jimple.ReturnVoidStmt;
import soot.jimple.SpecialInvokeExpr;
import soot.jimple.StaticFieldRef;
import soot.jimple.StaticInvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.TableSwitchStmt;
import soot.jimple.ThisRef;
import soot.jimple.ThrowStmt;
import soot.jimple.VirtualInvokeExpr;
import dk.brics.automaton.Automaton;
import dk.brics.misc.Origin;
import dk.brics.xact.ToXMLable;
import dk.brics.xact.XML;
import dk.brics.xact.XMLTemplateException;
import dk.brics.xact.analysis.Debug;
import dk.brics.xact.analysis.ErrorType;
import dk.brics.xact.analysis.XMLAnalysisException;
import dk.brics.xact.analysis.config.Configuration;
import dk.brics.xact.analysis.flowgraph.Entity;
import dk.brics.xact.analysis.flowgraph.Method;
import dk.brics.xact.analysis.flowgraph.SchemaType;
import dk.brics.xact.analysis.flowgraph.Statement;
import dk.brics.xact.analysis.flowgraph.TemplateConstant;
import dk.brics.xact.analysis.flowgraph.Variable;
import dk.brics.xact.analysis.flowgraph.statements.AnalyzeStm;
import dk.brics.xact.analysis.flowgraph.statements.AnalyzeStm.Kind;
import dk.brics.xact.analysis.flowgraph.statements.ArrayReadStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayWriteStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayWriteStringStm;
import dk.brics.xact.analysis.flowgraph.statements.CallStm;
import dk.brics.xact.analysis.flowgraph.statements.CastStm;
import dk.brics.xact.analysis.flowgraph.statements.CheckStm;
import dk.brics.xact.analysis.flowgraph.statements.ConcatStm;
import dk.brics.xact.analysis.flowgraph.statements.ConstStm;
import dk.brics.xact.analysis.flowgraph.statements.CopyStm;
import dk.brics.xact.analysis.flowgraph.statements.EmptyStm;
import dk.brics.xact.analysis.flowgraph.statements.EscapeStm;
import dk.brics.xact.analysis.flowgraph.statements.GapifyStm;
import dk.brics.xact.analysis.flowgraph.statements.GetStm;
import dk.brics.xact.analysis.flowgraph.statements.InsertStm;
import dk.brics.xact.analysis.flowgraph.statements.NodeStm;
import dk.brics.xact.analysis.flowgraph.statements.PlugStm;
import dk.brics.xact.analysis.flowgraph.statements.RemoveStm;
import dk.brics.xact.analysis.flowgraph.statements.SetStm;
import dk.brics.xact.analysis.flowgraph.statements.UnknownStm;
import dk.brics.xact.analysis.flowgraph.statements.ValidateStm;
import dk.brics.xact.analysis.flowgraph.statements.VarStm;
import dk.brics.xact.operations.XMLParser;
public class Translator extends ExprAnswerVisitor<Object,Variable> implements soot.jimple.StmtSwitch {
private TranslatorContext context;
private ControlFlowBuilder cfg;
private Configuration config;
private TemplateConstant emptyConstant = new TemplateConstant("", new HashMap<String,String>(), new Origin("<emptyConstant>", -1, -1));
/**
* True if the current statement is an InvokeStmt, meaning that the return-value of the
* invocation is ignored by the program. It is only used for generating error messages.
*/
private boolean invokeResultIsDiscarded;
/**
* When an invocation expression is being translated, this holds the name of the method
* being invoked. It is only used for generating error messages.
*/
private String invokedMethodName;
private Variable makevar() {
return new Variable(context.getNextVarID(), false);
}
public Translator(TranslatorContext context, Configuration config) {
this.context = context;
this.config = config;
this.cfg = new ControlFlowBuilder(context.getFlowGraph(), context.getCurrentOrigin());
emptyConstant.setXML(XML.parseTemplate(""));
}
@SuppressWarnings("unused")
private void error(Entity s, ErrorType type, String message, Object ... args) {
context.getErrors().error(s.getOrigin(), type, message, args);
}
private void error(ErrorType type, String message, Object ... args) {
context.getErrors().error(context.getCurrentOrigin(), type, message, args);
}
public StatementPair translateStmt(Stmt stmt) {
invokeResultIsDiscarded = false;
// add hotspots
for (ValueBox box : stmt.getUseBoxes()) {
if (config.getHotspots().contains(box)) {
addHotspotStatement(box);
}
}
stmt.apply(this);
return cfg.finish();
}
private void addHotspotStatement(ValueBox box) {
AnalyzeStm stm = new AnalyzeStm(Kind.HOTSPOT, makevar(), translateExpr(box.getValue()), null, context.getCurrentOrigin());
cfg.addStatement(stm);
context.putHotspot(box, stm);
}
public Variable translateExpr(Value expr) {
Variable v = applyTo(expr, null);
assert v != null;
return v;
}
/**
* Currently same as {@link #translateExpr(Value)}.
*/
private Variable translateOrEmptyIfNull(Value expr) {
return translateExpr(expr);
}
private <T extends Statement> T addStringStatement(T stm, ValueBox box) {
context.setStringHotspot(stm, box);
return stm;
}
private <T extends Statement> T addStringStatement(T stm, ValueBox box1, ValueBox box2, String namespace) {
context.setStringHotspot(stm, box1, box2, namespace);
return stm;
}
private Variable getLocal(Value v) {
return context.getLocal(((Local)v).getName());
}
@Override
public Variable caseLocal(Local v, Object question) {
return context.getLocal(v.getName());
}
@Override
public Variable caseParameterRef(ParameterRef v, Object question) {
Method method = context.getCurrentMethod();
return assumeTypeAnnotation(method.getParameterType(v.getIndex()), method.getParameter(v.getIndex()));
}
@Override
public Variable caseStaticFieldRef(StaticFieldRef v, Object question) {
return assumeTypeAnnotation(context.getFieldSchemaType(v.getField()), context.getField(v.getField()));
}
@Override
public Variable caseInstanceFieldRef(InstanceFieldRef v, Object question) {
return assumeTypeAnnotation(context.getFieldSchemaType(v.getField()), context.getField(v.getField()));
}
@Override
public Variable caseNullConstant(NullConstant v, Object question) {
Variable dest = makevar();
//cfg.addStatement(new EmptyStm(dest, false, context.getCurrentOrigin()));
TemplateConstant cnst = new TemplateConstant("", new HashMap<String,String>(), context.getCurrentOrigin());
cnst.setXML(parseXML(cnst.getTemplate(), context.getCurrentOrigin()));
cfg.addStatement(new ConstStm(dest, cnst, context.getCurrentOrigin()));
return dest;
}
@Override
public Variable caseArrayRef(ArrayRef v, Object question) {
Variable dest = makevar();
cfg.addStatement(new ArrayReadStm(dest, translateExpr(v.getBase()), context.getCurrentOrigin()));
return dest;
}
@Override
public Variable caseCastExpr(CastExpr v, Object question) {
return translateExpr(v.getOp());
}
@Override
public Variable caseNewArrayExpr(NewArrayExpr v, Object question) {
Variable var = makevar();
cfg.addStatement(new ConstStm(var, emptyConstant, context.getCurrentOrigin()));
return var;
}
@Override
public Variable caseNewMultiArrayExpr(NewMultiArrayExpr v, Object question) {
Variable var = makevar();
cfg.addStatement(new ConstStm(var, emptyConstant, context.getCurrentOrigin()));
return var;
}
@Override
public Variable caseNewExpr(NewExpr v, Object question) {
Variable var = makevar();
cfg.addStatement(new EmptyStm(var, false, context.getCurrentOrigin()));
return var;
}
@Override
public Variable caseSpecialInvokeExpr(SpecialInvokeExpr v, Object question) {
return handleInvoke(v);
}
@Override
public Variable caseStaticInvokeExpr(StaticInvokeExpr v, Object question) {
return handleInvoke(v);
}
@Override
public Variable caseVirtualInvokeExpr(VirtualInvokeExpr v, Object question) {
return handleInvoke(v);
}
@Override
public Variable caseInterfaceInvokeExpr(InterfaceInvokeExpr v, Object question) {
return handleInvoke(v);
}
@Override
public Variable defaultExpr(Object v, Object question) {
return makevar();
}
private Variable handleInvoke(InvokeExpr v) {
this.invokedMethodName = v.getMethod().getName();
Variable var = handleHardcodedInvoke(v);
if (var != null) {
return var;
}
Variable[] arguments = new Variable[v.getArgCount()];
for (int i=0; i<v.getArgCount(); i++) {
arguments[i] = translateExpr(v.getArg(i));
}
// check annotation restrictions
if (v.getMethod().getDeclaringClass().isApplicationClass()) {
for (int i=0; i<arguments.length; i++) {
checkTypeAnnotation(context.getMethod(v.getMethod()).getParameterType(i), arguments[i]);
}
}
var = makevar();
cfg.startBranch();
for (SootMethod target : getTargets(v)) {
// non-application classes are handled as extern calls below, so ignore them here
if (!target.getDeclaringClass().isApplicationClass())
continue; // XXX will resolveAbstractDispatch actually return non-concrete targets?
// handle call to application method
Method method = context.getMethod(target);
cfg.addStatement(new CallStm(var, method, arguments, context.getCurrentOrigin()));
cfg.useBranch();
}
if (config.canCallExtern(v)) {
for (int i=0; i<arguments.length; i++) {
if (!isImmutableType(v.getArg(i).getType())) {
cfg.addStatement(new EscapeStm(arguments[i], context.getCurrentOrigin()));
}
}
cfg.useBranch();
}
cfg.endBranch();
// handle constructors of ToXMLable classes
if (v.getMethod().getName().equals("<init>")) {
handleConstructorInvocation((SpecialInvokeExpr)v);
}
// apply type annotation to result
if (v.getMethod().getDeclaringClass().isApplicationClass()) {
return assumeTypeAnnotation(context.getMethod(v.getMethod()).getReturnType(), var);
} else {
return var;
}
}
/**
* Returns true if the specified type is an immutable variant of a type
* that would otherwise be subject to escape. XML types are not considered
* by this method, as they are always immutable. Only collection
* types should be considered.
* <p/>
* Only NodeList is currently considered immutable by this method.
*/
private boolean isImmutableType(Type type) {
if (type instanceof ArrayType) {
return false;
} else if (type instanceof RefType) {
RefType t = (RefType)type;
if (t.getClassName().equals("dk.brics.xact.NodeList"))
return true;
return false;
} else {
return true;
}
}
private void handleConstructorInvocation(SpecialInvokeExpr v) {
// only constructors of a subtype of ToXMLable need attention
if (!context.isSubtypeOf(v.getMethod().getDeclaringClass(), "dk.brics.xact.ToXMLable"))
return;
// ignore super() and this() invocations
SootMethod currentMethod = context.getCurrentSootMethod();
if (!currentMethod.isStatic() && v.getBase().equals(currentMethod.getActiveBody().getThisLocal())) {
return;
}
// find the toXML() method
SootClass createdClass = v.getMethod().getDeclaringClass();
SootMethod toxmlMethod = context.getHierarchy().resolveConcreteDispatch(createdClass, Scene.v().getMethod("<dk.brics.xact.ToXMLable: dk.brics.xact.XML toXML()>"));
Variable base = getLocal(v.getBase());
// toXML() defined in external code?
if (!toxmlMethod.getDeclaringClass().isApplicationClass()) {
// ask config to resolve it
String typename = config.resolveToXML(toxmlMethod);
if (typename == null) {
cfg.addStatement(new UnknownStm(base, context.getCurrentOrigin()));
} else {
cfg.addStatement(new ValidateStm(base, null, context.parseSchemaType(typename, context.getCurrentOrigin()), context.getCurrentOrigin()));
}
return;
}
// assign base to the result of the ToXML method
cfg.addStatement(new CallStm(base, context.getMethod(toxmlMethod), new Variable[0], context.getCurrentOrigin()));
}
@SuppressWarnings("unchecked")
@Override
public Variable caseThisRef(ThisRef v, Object question) {
Variable var = makevar();
SootClass currentClass = context.getCurrentClass();
if (config.hasExternalSubtypes(currentClass)) {
cfg.addStatement(new UnknownStm(var, context.getCurrentOrigin()));
return var;
}
cfg.startBranch();
for (SootMethod m : (List<SootMethod>)context.getHierarchy().resolveAbstractDispatch(currentClass, Scene.v().getMethod("<dk.brics.xact.ToXMLable: dk.brics.xact.XML toXML()>"))) {
if (!m.getDeclaringClass().isApplicationClass())
continue;// skip non-app classes since the config says the class has no extern subtypes
cfg.addStatement(new CallStm(var, context.getMethod(m), new Variable[0], context.getCurrentOrigin()));
}
cfg.endBranch();
return var;
}
@SuppressWarnings("unchecked")
private List<SootMethod> getTargets(InvokeExpr v) {
if (v instanceof VirtualInvokeExpr || v instanceof InterfaceInvokeExpr) {
Value base = ((InstanceInvokeExpr)v).getBase();
if (base.getType() instanceof ArrayType) {
// Array methods are implemented in java.lang.Object.
// (Cloneable and Serializable declare no methods)
return Collections.singletonList(v.getMethod());
} else {
SootClass cl = ((RefType)base.getType()).getSootClass();
return context.getHierarchy().resolveAbstractDispatch(cl, v.getMethod());
}
} else {
return Collections.singletonList(v.getMethod());
}
}
/*
* **********************************
* STATEMENTS
* **********************************
*/
public void caseInvokeStmt(InvokeStmt s) {
invokeResultIsDiscarded = true;
translateExpr(s.getInvokeExpr());
}
public void caseAssignStmt(AssignStmt s) {
assignment(s);
}
public void caseIdentityStmt(IdentityStmt s) {
assignment(s);
}
private void assignment(DefinitionStmt s) {
Variable right = translateExpr(s.getRightOp());
if (s.getLeftOp() instanceof ArrayRef) {
// A[X] = B
ArrayRef array = (ArrayRef)s.getLeftOp();
if (((ArrayType)array.getBase().getType()).getElementType() instanceof RefLikeType) {
Variable left = context.getLocal(((Local)array.getBase()).getName());
cfg.addStatement(new ArrayWriteStm(left, right, context.getCurrentOrigin()));
// also write possible strings we can get from converting the argument using toString()
cfg.addStatement(addStringStatement(new ArrayWriteStringStm(left, null, context.getCurrentOrigin()), s.getRightOpBox()));
} else {
// ignore..
}
} else if (s.getLeftOp() instanceof FieldRef) {
// A.field = B
SootField sootField = ((FieldRef)s.getLeftOp()).getField();
Variable field = context.getField(sootField);
checkTypeAnnotation(context.getFieldSchemaType(sootField), right);
cfg.startBranch();
cfg.addStatement(new VarStm(field, right, context.getCurrentOrigin()));
cfg.useBranch();
cfg.useBranch(); // <-- second branch is empty for weak update
cfg.endBranch();
} else if (s.getLeftOp() instanceof Local) {
// var = B
Variable left = context.getLocal(((Local)s.getLeftOp()).getName());
cfg.addStatement(new VarStm(left, right, context.getCurrentOrigin()));
} else {
throw new RuntimeException("Unexpected assignment to " + s.getLeftOp().getClass());
}
}
private void checkTypeAnnotation(SchemaType annotation, Variable var) {
if (annotation == null)
return;
cfg.addStatement(new AnalyzeStm(AnalyzeStm.Kind.TYPEANNOTATION, makevar(), var, annotation, context.getCurrentOrigin()));
}
private Variable assumeTypeAnnotation(SchemaType annotation, Variable var) {
if (annotation == null)
return var;
Variable result = makevar();
cfg.addStatement(new ValidateStm(result, null, annotation, context.getCurrentOrigin()));
return result;
}
public void caseReturnStmt(ReturnStmt s) {
Variable result = translateExpr(s.getOp());
checkTypeAnnotation(context.getCurrentMethod().getReturnType(), result);
cfg.addStatement(new VarStm(context.getCurrentMethod().getReturnVar(), result, context.getCurrentOrigin()));
}
public void caseReturnVoidStmt(ReturnVoidStmt s) {
}
public void caseBreakpointStmt(BreakpointStmt s) {
}
public void caseEnterMonitorStmt(EnterMonitorStmt s) {
}
public void caseExitMonitorStmt(ExitMonitorStmt s) {
}
public void caseGotoStmt(GotoStmt s) {
}
public void caseIfStmt(IfStmt s) {
}
public void caseLookupSwitchStmt(LookupSwitchStmt s) {
}
public void caseNopStmt(NopStmt s) {
}
public void caseRetStmt(RetStmt s) {
}
public void caseTableSwitchStmt(TableSwitchStmt s) {
}
public void caseThrowStmt(ThrowStmt s) {
}
public void defaultCase(Object s) {
}
/*
* **********************************
* HARDCODED INVOCATIONS
* **********************************
*/
private Variable hardcodeResult;
private Variable handleHardcodedInvoke(InvokeExpr expr) {
SootClass clazz = expr.getMethod().getDeclaringClass();
String cl = clazz.getName();
String sig = expr.getMethod().getSignature().intern();
String sub = expr.getMethod().getSubSignature();
String subsig = sub.substring(sub.indexOf(' ')+1).intern(); //sig.substring(sig.indexOf(':')+2, sig.length()-1).intern();
String methodName = expr.getMethod().getName().intern();
hardcodeResult= null;
Value base = expr instanceof InstanceInvokeExpr ? ((InstanceInvokeExpr)expr).getBase() : null;
if (cl.equals("dk.brics.xact.XML")) {
if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML analyze(java.lang.String)>") {
putAnalyze(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML append(java.lang.Object)>") {
putInsert(InsertStm.Kind.APPEND, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), true);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML appendContent(java.lang.Object)>") {
putInsert(InsertStm.Kind.APPENDCONTENT, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), true);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML appendContent(java.lang.String,java.lang.Object)>") {
putInsert(InsertStm.Kind.APPENDCONTENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1), true);
} else if (sig=="<dk.brics.xact.XML: int byteLength(java.lang.String)>") {
putNop();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML close()>") {
putClose(((InstanceInvokeExpr)expr).getBase());
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML concat(java.lang.Iterable)>") {
putConcat(expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML concat(java.lang.Object[])>") {
putConcat(expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML gapify(java.lang.String,java.lang.String)>") {
putGapify(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArg(1), null);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML gapify(java.lang.String,java.lang.String,java.lang.String)>") {
putGapify(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArg(1), expr.getArg(2));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.NodeList get(java.lang.String)>") {
putGet(GetStm.Kind.GET, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.Element getElement(java.lang.String)>") {
putGet(GetStm.Kind.GETELEMENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.NodeList getElements(java.lang.String)>") {
putGet(GetStm.Kind.GETELEMENTS, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.Element getFirstElement()>") {
putGet(GetStm.Kind.GETFIRSTELEMENT, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML getNextSibling()>") {
putGet(GetStm.Kind.GETNEXTSIBLING, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: java.lang.Number getNumber()>") {
putCheck(CheckStm.Kind.GETNUMBER, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: java.lang.Number getNumber(java.lang.String)>") {
putCheck(CheckStm.Kind.GETNUMBER, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: java.lang.String getString()>") {
putCheck(CheckStm.Kind.GETSTRING, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: java.lang.String getString(java.lang.String)>") {
putCheck(CheckStm.Kind.GETSTRING, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: java.util.List getStrings(java.lang.String)>") {
putCheck(CheckStm.Kind.GETSTRING, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: java.util.Map getNamespaceMap()>") {
putUnknown();
} else if (sig=="<dk.brics.xact.XML: java.util.Map getThreadNamespaceMap()>") {
putUnknown();
} else if (sig=="<dk.brics.xact.XML: boolean has(java.lang.String)>") {
putCheck(CheckStm.Kind.HAS, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML insertAfter(java.lang.String,java.lang.Object)>") {
putInsert(InsertStm.Kind.INSERTAFTER, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1), true);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML insertBefore(java.lang.String,java.lang.Object)>") {
putInsert(InsertStm.Kind.INSERTBEFORE, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1), true);
} else if (sig=="<dk.brics.xact.XML: void loadXMLSchema(java.lang.String)>") {
putNop();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseDocument(InputStream)>") {
putUnknown();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseDocument(InputStream,java.lang.String,dk.brics.misc.Origin)>") {
putUnknown();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseDocument(java.lang.String)>") {
putUnknown();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseDocument(java.net.URL)>") {
putUnknown();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseTemplate(java.io.InputStream,dk.brics.misc.Origin)>") {
putConst(context.getConstantString(expr.getArg(0)), context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseTemplate(java.lang.String)>") {
putConst(context.getConstantString(expr.getArg(0)), context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseTemplate(java.lang.String,dk.brics.misc.Origin)>") {
putConst(context.getConstantString(expr.getArg(0)), context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseTemplateResource(java.lang.Class,java.lang.String)>") {
String packageName = context.getModifiedPackageNameFromClassConstant(expr.getArg(0));
String name = context.getConstantString(expr.getArg(1));
putConst(context.getResourceString(packageName + "/" + name), new Origin(name, 0, 0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML parseTemplateResource(java.lang.String)>") {
String name = context.getConstantString(expr.getArg(0));
putConst(context.getResourceString(name), new Origin(name, 0, 0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML plugList(java.lang.String,java.lang.Iterable)>") {
putPlugList(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML plug(java.lang.String,java.lang.Object)>") {
putPlug(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML plugWrap(java.lang.String,java.lang.Iterable)>") {
putPlugWrap(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML prepend(java.lang.Object)>") {
putInsert(InsertStm.Kind.PREPEND, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), true);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML prependContent(java.lang.Object)>") {
putInsert(InsertStm.Kind.PREPENDCONTENT, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), true);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML prependContent(java.lang.String,java.lang.Object)>") {
putInsert(InsertStm.Kind.PREPENDCONTENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1), true);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML remove(java.lang.String)>") {
putRemove(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML set(dk.brics.xact.AttrNode)>") {
putInsert(InsertStm.Kind.SETATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), false);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML set(dk.brics.xact.NamespaceDecl)>") {
putVar(base);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML set(java.lang.String,dk.brics.xact.AttrNode)>") {
putInsert(InsertStm.Kind.SETATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1), false);
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML set(java.lang.String,java.lang.Object)>") {
putSet(SetStm.Kind.SET, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML setContent(java.lang.Object)>") {
putSet(SetStm.Kind.SETCONTENT, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML setContent(java.lang.String,java.lang.Object)>") {
putSet(SetStm.Kind.SETCONTENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArg(0), expr.getArgBox(1));
} else if (sig=="<dk.brics.xact.XML: java.lang.String toDocument()>") {
putCheck(CheckStm.Kind.TODOCUMENT, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: void toDocument(OutputStream, java.lang.String)>") {
putCheck(CheckStm.Kind.TODOCUMENT, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: java.lang.String toDocument(java.lang.String)>") {
putCheck(CheckStm.Kind.TODOCUMENT, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: java.lang.String toDocument(dk.brics.xact.operations.XMLIndentation)>") {
putCheck(CheckStm.Kind.TODOCUMENT, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.XML: java.lang.String toTemplate()>") {
putNop();
} else if (sig=="<dk.brics.xact.XML: java.lang.String toTemplate(java.lang.String)>") {
putNop();
} else if (sig=="<dk.brics.xact.XML: java.lang.String toTemplate(dk.brics.xact.operations.XMLIndentation)>") {
putNop();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML toXML()>") {
putVar(translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML toXML(java.lang.Object)>") {
putVar(getVariableFromObjectExp(expr.getArgBox(0)));
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.XML validate(java.lang.String)>") {
putValidate(((InstanceInvokeExpr)expr).getBase(), expr.getArg(0));
} else if (sig=="<dk.brics.xact.XML: java.lang.String getAttribute(java.lang.String)>") {
putNop(); // TODO add CheckStm for getAttribute
} else if (sig=="<dk.brics.xact.XML: java.lang.String getAttribute(java.lang.String,java.lang.String)>") {
putNop();
} else if (sig=="<dk.brics.xact.XML: dk.brics.xact.Element getElementByID(java.lang.String)>") {
putGetElementById(base, expr.getArg(0));
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.AttrNode")) {
if (sig=="<dk.brics.xact.AttrNode: dk.brics.xact.AttrNode copy(dk.brics.xact.AttrNode)>") {
putCopy(CopyStm.Kind.ATTRNODE, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.AttrNode: java.lang.String getExpandedName()>") {
putNop();
} else if (sig=="<dk.brics.xact.AttrNode: java.lang.String getLocalName()>") {
putNop();
} else if (sig=="<dk.brics.xact.AttrNode: java.lang.String getNamespace()>") {
putNop();
} else if (sig=="<dk.brics.xact.AttrNode: dk.brics.xact.AttrNode getNextAttr()>") {
putGet(GetStm.Kind.GETNEXTATTR, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.AttrNode: dk.brics.xact.Attribute getNextAttribute()>") {
putGet(GetStm.Kind.GETNEXTATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), null);
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.Attribute")) {
if (sig=="<dk.brics.xact.Attribute: void <init>(java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.ATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), expr.getArgBox(1), null, null, null, null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.Attribute: void <init>(java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), expr.getArgBox(1), null, null, null, null, null, context.getConstantOrigin(expr.getArg(2)));
} else if (sig=="<dk.brics.xact.Attribute: void <init>(java.lang.String,java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.ATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), expr.getArgBox(2), null, null, null, null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.Attribute: void <init>(java.lang.String,java.lang.String,java.lang.String,dk.brics.xact.AttrNode,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), expr.getArgBox(2), null, null, null, null, expr.getArgBox(3), context.getConstantOrigin(expr.getArg(4)));
} else if (sig=="<dk.brics.xact.Attribute: void <init>(java.lang.String,java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), expr.getArgBox(2), null, null, null, null, null, context.getConstantOrigin(expr.getArg(3)));
} else if (sig=="<dk.brics.xact.Attribute: dk.brics.xact.Attribute copy(dk.brics.xact.AttrNode)>") {
putCopy(CopyStm.Kind.ATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.Attribute: java.lang.String getValue()>") {
putNop();
} else if (sig=="<dk.brics.xact.Attribute: java.lang.String toString()>") {
putNop();
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.AttributeGap")) {
if (sig=="<dk.brics.xact.AttributeGap: void <init>(java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), null, null, null, expr.getArg(1), null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.AttributeGap: void <init>(java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), null, null, null, expr.getArg(1), null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.AttributeGap: void <init>(java.lang.String,java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), null, null, null, expr.getArg(1), null, null, context.getConstantOrigin(expr.getArg(2)));
} else if (sig=="<dk.brics.xact.AttributeGap: void <init>(java.lang.String,java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), null, null, null, expr.getArg(1), expr.getArg(2), null, context.getConstantOrigin(expr.getArg(3)));
} else if (sig=="<dk.brics.xact.AttributeGap: void <init>(java.lang.String,java.lang.String,java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), null, null, null, expr.getArg(2), expr.getArg(3), null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.AttributeGap: void <init>(java.lang.String,java.lang.String,java.lang.String,java.lang.String,dk.brics.xact.AttrNode,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), null, null, null, expr.getArg(2), expr.getArg(3), expr.getArgBox(4), context.getConstantOrigin(expr.getArg(5)));
} else if (sig=="<dk.brics.xact.AttributeGap: void <init>(java.lang.String,java.lang.String,java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), null, null, null, expr.getArg(2), expr.getArg(3), null, context.getConstantOrigin(expr.getArg(4)));
} else if (sig=="<dk.brics.xact.AttributeGap: dk.brics.xact.AttributeGap copy(dk.brics.xact.AttrNode)>") {
putCopy(CopyStm.Kind.ATTRIBUTEGAP, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.AttributeGap: java.lang.String getGap()>") {
putNop();
} else if (sig=="<dk.brics.xact.AttributeGap: java.lang.String getType()>") {
putNop();
} else if (sig=="<dk.brics.xact.AttributeGap: java.lang.String toString()>") {
putNop();
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.Comment")) {
if (sig=="<dk.brics.xact.Comment: void <init>(java.lang.String)>") {
putNode(NodeStm.Kind.COMMENT, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, null, null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.Comment: void <init>(java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.COMMENT, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, null, null, null, context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.Comment: void <init>(java.lang.String,dk.brics.xact.XML,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.COMMENT, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, null, null, expr.getArgBox(1), context.getConstantOrigin(expr.getArg(2)));
} else if (sig=="<dk.brics.xact.Comment: dk.brics.xact.Comment copy(dk.brics.xact.XML)>") {
putCopy(CopyStm.Kind.COMMENT, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.Comment: java.lang.String getValue()>") {
putNop();
} else if (sig=="<dk.brics.xact.Comment: java.lang.String toString()>") {
putNop();
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.Element")) {
if (sig=="<dk.brics.xact.Element: void <init>(java.lang.String)>") {
putNode(NodeStm.Kind.ELEMENT, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), null, null, null, null, null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.Element: void <init>(java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ELEMENT, ((InstanceInvokeExpr)expr).getBase(), null, expr.getArgBox(0), null, null, null, null, null, null, context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.Element: void <init>(java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.ELEMENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), null, null, null, null, null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.Element: void <init>(java.lang.String,java.lang.String,dk.brics.xact.AttrNode,dk.brics.xact.XML,dk.brics.xact.NamespaceDecl,dk.brics.xact.XML,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ELEMENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), null, expr.getArgBox(2), expr.getArgBox(3), null, null, expr.getArgBox(5), context.getConstantOrigin(expr.getArg(6)));
} else if (sig=="<dk.brics.xact.Element: void <init>(java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.ELEMENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), null, null, null, null, null, null, context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.Element: dk.brics.xact.Element copy(dk.brics.xact.AttrNode,dk.brics.xact.XML,dk.brics.xact.XML)>") {
putCopy(CopyStm.Kind.ELEMENT, ((InstanceInvokeExpr)expr).getBase(), expr.getArgBox(0), expr.getArgBox(1), expr.getArgBox(2));
} else if (sig=="<dk.brics.xact.Element: dk.brics.xact.Element copy(dk.brics.xact.XML)>") {
putCopy(CopyStm.Kind.ELEMENT, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.Element: java.lang.String getExpandedName()>") {
putNop();
} else if (sig=="<dk.brics.xact.Element: dk.brics.xact.AttrNode getFirstAttr()>") {
putGet(GetStm.Kind.GETFIRSTATTR, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.Element: dk.brics.xact.Attribute getFirstAttribute()>") {
putGet(GetStm.Kind.GETFIRSTATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.Element: dk.brics.xact.XML getFirstChild()>") {
putGet(GetStm.Kind.GETFIRSTCHILD, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.Element: dk.brics.xact.NamespaceDecl getFirstNamespaceDecl()>") {
putNop();
} else if (sig=="<dk.brics.xact.Element: java.lang.String getLocalName()>") {
putNop();
} else if (sig=="<dk.brics.xact.Element: java.lang.String getNamespace()>") {
putNop();
} else if (sig=="<dk.brics.xact.Element: java.lang.String toString()>") {
putNop();
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.ProcessingInstruction")) {
if (sig=="<dk.brics.xact.ProcessingInstruction: void <init>(java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.PROCESSINGINSTRUCTION, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, null, null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.ProcessingInstruction: void <init>(java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.PROCESSINGINSTRUCTION, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, null, null, null, context.getConstantOrigin(expr.getArg(2)));
} else if (sig=="<dk.brics.xact.ProcessingInstruction: void <init>(java.lang.String,java.lang.String,dk.brics.xact.XML,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.PROCESSINGINSTRUCTION, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, null, null, expr.getArgBox(2), context.getConstantOrigin(expr.getArg(3)));
} else if (sig=="<dk.brics.xact.ProcessingInstruction: dk.brics.xact.ProcessingInstruction copy(dk.brics.xact.XML)>") {
putCopy(CopyStm.Kind.PROCESSINGINSTRUCTION, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.ProcessingInstruction: java.lang.String getData()>") {
putNop();
} else if (sig=="<dk.brics.xact.ProcessingInstruction: java.lang.String getTarget()>") {
putNop();
} else if (sig=="<dk.brics.xact.ProcessingInstruction: java.lang.String toString()>") {
putNop();
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.TemplateGap")) {
if (sig=="<dk.brics.xact.TemplateGap: void <init>(java.lang.String)>") {
putNode(NodeStm.Kind.TEMPLATEGAP, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, expr.getArg(0), null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.TemplateGap: void <init>(java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.TEMPLATEGAP, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, expr.getArg(0), null, null, context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.TemplateGap: void <init>(java.lang.String,java.lang.String)>") {
putNode(NodeStm.Kind.TEMPLATEGAP, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, expr.getArg(0), expr.getArg(1), null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.TemplateGap: void <init>(java.lang.String,java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.TEMPLATEGAP, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, expr.getArg(0), expr.getArg(1), null, context.getConstantOrigin(expr.getArg(2)));
} else if (sig=="<dk.brics.xact.TemplateGap: void <init>(java.lang.String,java.lang.String,dk.brics.xact.XML,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.TEMPLATEGAP, ((InstanceInvokeExpr)expr).getBase(), null, null, null, null, null, expr.getArg(0), expr.getArg(1), expr.getArgBox(2), context.getConstantOrigin(expr.getArg(3)));
} else if (sig=="<dk.brics.xact.TemplateGap: dk.brics.xact.TemplateGap copy(dk.brics.xact.XML)>") {
putCopy(CopyStm.Kind.TEMPLATEGAP, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.TemplateGap: java.lang.String getGap()>") {
putNop();
} else if (sig=="<dk.brics.xact.TemplateGap: java.lang.String getType()>") {
putNop();
} else if (sig=="<dk.brics.xact.TemplateGap: java.lang.String toString()>") {
putNop();
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.TempNode")) {
if (sig=="<dk.brics.xact.TempNode: dk.brics.xact.TempNode copy(dk.brics.xact.XML)>") {
putCopy(CopyStm.Kind.TEMPNODE, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.TempNode: dk.brics.xact.XML getNextSibling()>") {
putGet(GetStm.Kind.GETNEXTSIBLING, ((InstanceInvokeExpr)expr).getBase(), null);
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.Text")) {
if (sig=="<dk.brics.xact.Text: void <init>(java.lang.String)>") {
putNode(NodeStm.Kind.TEXT, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0), null, null, null, null, null, context.getCurrentOrigin());
} else if (sig=="<dk.brics.xact.Text: void <init>(java.lang.String,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.TEXT, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0), null, null, null, null, null, context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.Text: void <init>(java.lang.String,dk.brics.xact.XML,dk.brics.misc.Origin)>") {
putNode(NodeStm.Kind.TEXT, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0), null, null, null, null, expr.getArgBox(1), context.getConstantOrigin(expr.getArg(1)));
} else if (sig=="<dk.brics.xact.Text: dk.brics.xact.Text copy(dk.brics.xact.XML)>") {
putCopy(CopyStm.Kind.TEXT, ((InstanceInvokeExpr)expr).getBase(), null, null, expr.getArgBox(0));
} else if (sig=="<dk.brics.xact.Text: java.lang.String toString()>") {
putNop();
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.Node")) {
if (sig=="<dk.brics.xact.Node: dk.brics.xact.Attribute asAttribute()>") {
putCast(CastStm.Kind.ASATTRIBUTE, translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.Node: dk.brics.xact.Comment asComment()>") {
putCast(CastStm.Kind.ASCOMMENT, translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.Node: dk.brics.xact.Element asElement()>") {
putCast(CastStm.Kind.ASELEMENT, translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.Node: dk.brics.xact.NamespaceDecl asNamespaceDecl()>") {
putCast(CastStm.Kind.ASNSDECL, translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.Node: dk.brics.xact.ProcessingInstruction asProcessingInstruction()>") {
putCast(CastStm.Kind.ASPI, translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.Node: dk.brics.xact.Text asText()>") {
putCast(CastStm.Kind.ASTEXT, translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.Node: dk.brics.misc.Origin getOrigin()>") {
putNop();
} else if (sig=="<dk.brics.xact.Node: boolean isAttribute()>") {
putCheck(CheckStm.Kind.ISATTRIBUTE, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.Node: boolean isComment()>") {
putNop();
} else if (sig=="<dk.brics.xact.Node: boolean isElement()>") {
putCheck(CheckStm.Kind.ISELEMENT, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.Node: boolean isNamespaceDecl()>") {
putNop();
} else if (sig=="<dk.brics.xact.Node: boolean isProcessingInstruction()>") {
putNop();
} else if (sig=="<dk.brics.xact.Node: boolean isText()>") {
putCheck(CheckStm.Kind.ISTEXT, ((InstanceInvokeExpr)expr).getBase(), null);
} else if (sig=="<dk.brics.xact.Node: java.lang.String toString()>") {
putNop();
} else if (sig=="<dk.brics.xact.Node: void visitBy(dk.brics.xact.NodeVisitor)>") {
putNop(); //throw new UnsupportedOperationException("NodeVisitor analysis not implemented"); // TODO: analyze NodeVisitors
} else
throw new RuntimeException("Unexpected operation: " + sig);
} else if (cl.equals("dk.brics.xact.NodeList")) {
if (sig=="<dk.brics.xact.NodeList: void <init>(java.lang.Iterable)>") {
putCopyArray(base,expr.getArg(0));
} else if (sig=="<dk.brics.xact.NodeList: dk.brics.xact.XML concat()>") {
putConcat(((InstanceInvokeExpr)expr).getBaseBox());
} else if (sig=="<dk.brics.xact.NodeList: dk.brics.xact.Node get(int)>") {
putVar(translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.NodeList: boolean isEmpty()>") {
putNop();
} else if (sig=="<dk.brics.xact.NodeList: java.util.Iterator iterator()>") {
putVar(translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.NodeList: int size()>") {
putNop();
} else if (sig=="<dk.brics.xact.NodeList: java.lang.String toString()>") {
putNop();
} else if (sig=="<dk.brics.xact.NodeList: dk.brics.xact.XML toXML()>") {
putVar(translateExpr(((InstanceInvokeExpr)expr).getBase()));
} else if (sig=="<dk.brics.xact.NodeList: void visitBy(dk.brics.xact.NodeVisitor)>") {
putNop();//throw new UnsupportedOperationException("NodeVisitor analysis not implemented"); // TODO: analyze NodeVisitors
} else
throw new RuntimeException("Unexpected operation: " + sig);
}
else if (cl.equals("java.util.Arrays")) {
if (subsig=="asList(java.lang.Object[])") {
putVar(translateExpr(expr.getArg(0)));
}
else if (methodName == "binarySearch" || methodName == "deepEquals"
|| methodName == "deepHashCode" || methodName == "deepToString" || methodName == "equals"
|| methodName == "hashCode" || methodName == "sort" || methodName == "toString") {
putNop(); // (note: subsequent calls to equals() etc will be handled by external callability)
}
else if (subsig == "copyOf(java.lang.Object[],int)"
|| subsig == "copyOfRange(java.lang.Object[],int,int)"
|| subsig == "copyOf(java.lang.Object[],int,java.lang.Class)"
|| subsig == "copyOfRange(java.lang.Object[],int,int)") {
putCopyOfArray(expr.getArg(0));
}
else if (subsig == "fill(java.lang.Object[],int,int,java.lang.Object)") {
putArrayWrite(expr.getArg(0), expr.getArgBox(3));
}
else if (subsig == "fill(java.lang.Object[],java.lang.Object)") {
putArrayWrite(expr.getArg(0), expr.getArgBox(1));
}
}
else if (cl.equals("java.util.Collections")) {
if (subsig == "addAll(java.util.Collection,java.lang.Object[])") {
putArrayAddAll(expr.getArg(0), expr.getArgBox(1));
}
else if (subsig == "asLifoQueue(java.util.Deque)") {
putVar(expr.getArg(0));
}
else if (subsig == "binarySearch(java.util.List,java.lang.Object)"
|| subsig == "binarySearch(java.util.List,java.lang.Object,java.lang.Object)"
|| subsig == "disjoint(java.util.Collection,java.util.Collection)"
|| subsig == "frequency(java.util.Collection,java.lang.Object)"
|| subsig == "indexOfSubList(java.util.List,java.util.List)"
|| subsig == "lastIndexOfSubList(java.util.List,java.util.List)"
|| subsig == "reverse(java.util.List)"
|| subsig == "rotate(java.util.List,int)"
|| subsig == "shuffle(java.util.List)"
|| subsig == "shuffle(java.util.List,java.util.Random)"
|| subsig == "sort(java.util.List)"
|| subsig == "sort(java.util.List,java.util.Comparator)"
|| subsig == "swap(java.util.List,int,int)") {
putNop();
}
else if (subsig == "checkedCollection(java.util.Collection,java.lang.Class)"
|| subsig == "checkedList(java.util.List,java.lang.Class)"
|| subsig == "checkedSet(java.util.Set,java.lang.Class)"
|| subsig == "checkedSortedSet(java.util.SortedSet,java.lang.Class)"
|| subsig == "synchronizedCollection(java.util.Collection)"
|| subsig == "synchronizedList(java.util.List)"
|| subsig == "synchronizedSet(java.util.Set)"
|| subsig == "synchronizedSortedSet(java.util.SortedSet)"
|| subsig == "unmodifiableCollection(java.util.Collection)"
|| subsig == "unmodifiableList(java.util.List)"
|| subsig == "unmodifiableSet(java.util.Set)"
|| subsig == "unmodifiableSortedSet(java.util.SortedSet)") {
putVar(expr.getArg(0));
}
else if (subsig == "copy(java.util.List,java.util.List)") {
putArrayAddAll(expr.getArg(0), expr.getArgBox(1));
}
else if (subsig == "fill(java.util.List,java.lang.Object)") {
putArrayWrite(expr.getArg(0), expr.getArgBox(1));
}
else if (subsig == "max(java.util.Collection)"
|| subsig == "max(java.util.Collection,java.util.Comparator)"
|| subsig == "min(java.util.Collection)"
|| subsig == "min(java.util.Collection,java.util.Comparator)") {
putArrayRead(expr.getArg(0));
}
else if (subsig == "nCopies(int,java.lang.Object)") {
putNewArrayWithElement(expr.getArgBox(1));
}
else if (subsig == "replaceAll(java.util.List,java.lang.Object,java.lang.Object)") {
putArrayWrite(expr.getArg(0), expr.getArgBox(2));
}
else if (subsig == "singleton(java.lang.Object)"
|| subsig == "singletonList(java.lang.Object)") {
putNewArrayWithElement(expr.getArgBox(0));
}
else if (subsig == "emptyList()" || subsig == "emptySet()") {
putNewArray();
}
}
else if (context.isSubtypeOf(clazz, "java.util.Iterator")) {
if (subsig == "next()" || subsig == "previous()") {
putArrayRead(base);
} else if (subsig == "add(java.lang.Object)" || subsig == "set(java.lang.Object)") {
putArrayWrite(base, expr.getArgBox(0));
} else if (methodName == "<init>") {
putUnknown(base);
} else if (subsig == "hasNext()" || subsig == "hasPrevious()"
|| subsig == "nextIndex()" || subsig == "previousIndex()" || subsig == "remove()") {
putNop();
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.lang.Iterable")) {
if (subsig == "iterator()") {
putVar(base);
}
else if (subsig == "<init>()" && config.isNormalCollection(cl)) {
putNewArray(base);
}
else if (methodName == "<init>") {
// unknown constructor of a collection
putUnknown(base);
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.Collection")) {
if (subsig == "add(java.lang.Object)") { // Collection.add()
putArrayWrite(base, expr.getArgBox(0));
}
else if (subsig == "addAll(java.util.Collection)") {
putArrayAddAll(base, expr.getArgBox(0));
}
else if (subsig == "clear()"
|| subsig == "contains(java.lang.Object)"
|| subsig == "containsAll(java.util.Collection)"
|| subsig == "equals(java.lang.Object)"
|| subsig == "hashCode()"
|| subsig == "isEmpty()"
|| subsig == "remove(java.lang.Object)"
|| subsig == "removeAll(java.util.Collection)"
|| subsig == "retainAll(java.util.Collection)"
|| subsig == "size()") {
putNop();
}
else if (subsig == "toArray()") {
putVar(base);
}
else if (subsig == "toArray(java.lang.Object[])") {
putSpecialToArray(base, expr.getArg(0));
}
else if (subsig == "clone()") {
putVar(base);
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.List")) {
if (subsig == "listIterator()"
|| subsig == "listIterator(int)") {
putVar(base);
}
else if (subsig == "add(int,java.lang.Object)") {
putArrayWrite(base, expr.getArgBox(1));
}
else if (subsig == "addAll(int,java.util.Collection)") {
putArrayAddAll(base, expr.getArgBox(1));
}
else if (subsig == "get(int)") {
putArrayRead(base);
}
else if (subsig == "subList(int,int)") {
putVar(base);
}
else if (subsig == "set(int,java.lang.Object)") {
putArrayReadAndWrite(base, expr.getArgBox(0));
}
else if (subsig == "remove(int)") {
putArrayRead(base);
}
else if (subsig == "indexOf(java.lang.Object)" || subsig == "lastIndexOf(java.lang.Object)") {
putNop();
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.Queue")) {
if (subsig == "element()"
|| subsig == "peek()"
|| subsig == "poll()") {
putArrayRead(base);
}
else if (subsig == "offer(java.lang.Object)") {
putArrayWrite(base, expr.getArgBox(0));
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.Deque")) {
if (subsig == "descendingIterator()") {
putVar(base);
}
else if (subsig == "addFirst(java.lang.Object)"
|| subsig == "addLast(java.lang.Object)"
|| subsig == "offerFirst(java.lang.Object)"
|| subsig == "offerLast(java.lang.Object)"
|| subsig == "push(java.lang.Object)") {
putArrayWrite(base, expr.getArgBox(0));
}
else if (subsig == "getFirst()"
|| subsig == "getLast()"
|| subsig == "peekFirst()"
|| subsig == "peekLast()"
|| subsig == "pollFirst()"
|| subsig == "pollLast()"
|| subsig == "pop()"
|| subsig == "removeFirst()"
|| subsig == "removeLast()") {
putArrayRead(base);
}
else if (subsig == "removeFirstOccurence(java.lang.Object)"
|| subsig == "removeLastOccurence(java.lang.Object)") {
putNop();
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.SortedSet")) {
if (subsig == "comparator()") {
putNop();
}
else if (subsig == "first()" || subsig == "last()") {
putArrayRead(base);
}
else if (subsig == "headSet(java.lang.Object)"
|| subsig == "tailSet(java.lang.Object)"
|| subsig == "subSet(java.lang.Object,java.lang.Object)") {
putVar(base);
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.Map")) {
if (subsig == "clear()"
|| subsig == "containsKey(java.lang.Object)"
|| subsig == "containsValue(java.lang.Object)"
|| subsig == "isEmpty()"
|| subsig == "size()") {
putNop();
}
else if (subsig == "entrySet()"
|| subsig == "values()") {
putVar(base);
}
else if (subsig == "keySet()") {
// if keySet escapes then unknown code can remove
// element from the map, but not add new ones
// in case someone uses XML as key, he is screwed
putUnknown();
}
else if (subsig == "put(java.lang.Object,java.lang.Object)") {
putArrayReadAndWrite(base, expr.getArgBox(1));
}
else if (subsig == "putAll(java.util.Map)") {
putArrayAddAll(base, expr.getArgBox(0));
}
else if (subsig == "get(java.lang.Object)"
|| subsig == "remove(java.lang.Object)") {
putArrayRead(base);
}
else if (subsig == "<init>()" && config.isNormalCollection(cl)) {
putNewArray(base);
}
else if (subsig == "<init>(java.util.Map)" && config.isNormalCollection(cl)) {
putCopyArray(base, expr.getArg(0));
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.Map$Entry")) {
if (subsig == "getKey()") {
putUnknown();
}
else if (subsig == "getValue()") {
putArrayRead(base);
}
else if (subsig == "setValue(java.lang.Object)") {
putArrayReadAndWrite(base, expr.getArgBox(0));
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.SortedMap")) {
if (subsig == "comparator()") {
putNop();
}
else if (subsig == "firstKey()"
|| subsig == "lastKey()") {
putUnknown(); // key could be XML, so it is unsound to use nop
}
else if (subsig == "headMap(java.lang.Object)"
|| subsig == "subMap(java.lang.Object,java.lang.Object)"
|| subsig == "tailMap(java.lang.Object)") {
putVar(base);
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.NavigableMap")) {
if (subsig == "ceilingEntry(java.lang.Object)"
|| subsig == "firstEntry()"
|| subsig == "floorEntry(java.lang.Object)"
|| subsig == "descendingMap()"
|| subsig == "headMap(java.lang.Object,boolean)"
|| subsig == "higherEntry(java.lang.Object)"
|| subsig == "lastEntry()"
|| subsig == "lowerEntry(java.lang.Object)"
|| subsig == "pollFirstEntry()"
|| subsig == "pollLastEntry()"
|| subsig == "subMap(java.lang.Object,boolean,java.lang.Object,boolean)"
|| subsig == "tailMap(java.lang.Object,boolean)") {
putVar(base);
}
else if (subsig == "ceilingKey(java.lang.Object)"
|| subsig == "descendingKeySet()"
|| subsig == "floorKey(java.lang.Object)"
|| subsig == "higherKey(java.lang.Object)"
|| subsig == "lowerKey(java.lang.Object)"
|| subsig == "navigableKeySet()") {
putUnknown();
}
}
if (hardcodeResult == null && context.isSubtypeOf(clazz, "java.util.concurrent.ConcurrentMap")) {
if (subsig == "putIfAbsent(java.lang.Object,java.lang.Object)") {
putArrayReadAndWrite(base, expr.getArgBox(1));
}
else if (subsig == "remove(java.lang.Object,java.lang.Object)") {
putNop();
}
else if (subsig == "replace(java.lang.Object,java.lang.Object,java.lang.Object)") {
putArrayWrite(base, expr.getArgBox(2));
}
else if (subsig == "replace(java.lang.Object,java.lang.Object)") {
putArrayReadAndWrite(base, expr.getArgBox(1));
}
}
return hardcodeResult;
}
private void putCopyOfArray(Value arg) {
hardcodeResult = translateExpr(arg);
cfg.startBranch();
cfg.addStatement(new ConstStm(hardcodeResult, emptyConstant, context.getCurrentOrigin()));
cfg.useBranch();
cfg.useBranch();
cfg.endBranch();
}
private void putCopyArray(Value base, Value arg) {
hardcodeResult = context.getNothing();
cfg.addStatement(new VarStm(context.getLocal(((Local)base).getName()), translateExpr(arg), context.getCurrentOrigin()));
}
private void putSpecialToArray(Value base, Value arg) {
hardcodeResult = makevar();
cfg.startBranch();
cfg.addStatement(new VarStm(hardcodeResult, translateExpr(base), context.getCurrentOrigin()));
cfg.useBranch();
cfg.addStatement(new VarStm(hardcodeResult, translateExpr(arg), context.getCurrentOrigin()));
cfg.useBranch();
cfg.endBranch();
}
private void putArrayAddAll(Value dest, ValueBox source) {
hardcodeResult = context.getNothing();
Variable array = translateExpr(dest);
Variable src = translateExpr(source.getValue());
cfg.startBranch();
cfg.useBranch();
cfg.addStatement(new VarStm(array, src, context.getCurrentOrigin()));
cfg.useBranch();
cfg.endBranch();
}
private void putArrayWrite(Value dest, ValueBox source) {
hardcodeResult = context.getNothing();
Variable array = translateExpr(dest);
Variable src = translateExpr(source.getValue());
cfg.addStatement(new ArrayWriteStm(array, src, context.getCurrentOrigin()));
cfg.addStatement(addStringStatement(new ArrayWriteStringStm(array, null, context.getCurrentOrigin()), source));
}
private void putArrayRead(Value from) {
hardcodeResult = makevar();
cfg.addStatement(new ArrayReadStm(hardcodeResult, translateExpr(from), context.getCurrentOrigin()));
}
private void putArrayReadAndWrite(Value arrayValue, ValueBox source) {
hardcodeResult = makevar();
Variable array = translateExpr(arrayValue);
Variable src = translateExpr(source.getValue());
cfg.addStatement(new ArrayReadStm(hardcodeResult, array, context.getCurrentOrigin()));
cfg.addStatement(new ArrayWriteStm(array, src, context.getCurrentOrigin()));
cfg.addStatement(addStringStatement(new ArrayWriteStringStm(array, null, context.getCurrentOrigin()), source));
}
private void putNewArray(Value base) {
hardcodeResult = context.getNothing(); // constructors return void
cfg.addStatement(new EmptyStm(translateExpr(base), true, context.getCurrentOrigin()));
}
private void putNewArray() {
hardcodeResult = makevar();
cfg.addStatement(new EmptyStm(hardcodeResult, true, context.getCurrentOrigin()));
}
private void putNewArrayWithElement(ValueBox item) {
hardcodeResult = makevar();
cfg.addStatement(new ArrayWriteStm(hardcodeResult, translateExpr(item.getValue()), context.getCurrentOrigin()));
cfg.addStatement(addStringStatement(new ArrayWriteStringStm(hardcodeResult, null, context.getCurrentOrigin()), item));
}
private void putNop() {
hardcodeResult = makevar();//context.getNothing();
}
/**
* Generates a VarStm.
*/
private void putVar(Variable source) {
//cfg.addStatement(new VarStm(translateExpr(dest), source, dest instanceof ArrayRef, context.getCurrentOrigin()));
hardcodeResult = source;
}
/**
* Generates a VarStm.
*/
public void putVar(Value source) {
//cfg.addStatement(new VarStm(dest, translateExpr(source), weak, context.getCurrentOrigin()));
hardcodeResult = translateExpr(source);
}
/**
* Generates a ConstStm.
*/
private void putConst(String template, Origin origin) {
hardcodeResult = makevar();
TemplateConstant cnst = new TemplateConstant(template, context.getNamespaces(), origin);
XML x = parseXML(cnst.getTemplate(), origin);
if (x != null) {
cnst.setXML(x);
cfg.addStatement(new ConstStm(hardcodeResult,
cnst,
origin));
} else {
// error recovery: just let result be undefined (ie bottom)
}
}
private XML parseXML(String str, Origin origin) {
try {
return XMLParser.parse(new ByteArrayInputStream(str.getBytes("UTF-8")), "UTF-8", true, context.getNamespaces(), origin);
} catch (XMLTemplateException ex) {
error(ErrorType.MALFORMED_XML_CONSTANT, ex.getMessage());
return null;
} catch (IOException ex) {
throw new XMLAnalysisException(ex, origin);
}
}
/**
* Generates an UnknownStm.
*/
private void putUnknown() {
hardcodeResult = makevar();
cfg.addStatement(new UnknownStm(hardcodeResult, context.getCurrentOrigin()));
}
private void putUnknown(Value var) {
hardcodeResult = translateExpr(var);
cfg.addStatement(new UnknownStm(hardcodeResult, context.getCurrentOrigin()));
}
/**
* Issues a warning if the return-value of the invocation is not stored in a variable.
* @see ErrorType#DISCARDED_RESULT
*/
private void checkDiscardedResult() {
if (invokeResultIsDiscarded) {
error(ErrorType.DISCARDED_RESULT, "Result of %s statement is never used.", invokedMethodName);
}
}
/**
* Generates a PlugStm for a normal plug operation.
*/
private void putPlug(Value base, Value gap, ValueBox source) {
hardcodeResult = makevar();
cfg.addStatement(addStringStatement(new PlugStm(PlugStm.Kind.PLUG,
hardcodeResult,
translateExpr(base),
context.getConstantString(gap),
null,
getVariableFromObjectExp(source),
context.getCurrentOrigin()), source));
checkDiscardedResult();
}
/**
* Generates a PlugStm for a multi-plug operation.
*/
private void putPlugList(Value base, Value gap, ValueBox source) {
hardcodeResult = makevar();
cfg.addStatement(new PlugStm(PlugStm.Kind.PLUGMULTI,
hardcodeResult,
translateExpr(base),
context.getConstantString(gap),
Automaton.makeEmpty(), // <-- string source is set in ArrayTransformer, not as a hotspot
translateExpr(source.getValue()),
context.getCurrentOrigin()));
checkDiscardedResult();
}
/**
* Generates a PlugStm for a plug-wrap operation.
*/
private void putPlugWrap(Value base, Value gap, ValueBox source) {
hardcodeResult = makevar();
cfg.addStatement(new PlugStm(PlugStm.Kind.PLUGWRAP,
hardcodeResult,
translateExpr(base),
context.getConstantString(gap),
Automaton.makeEmpty(),
translateExpr(source.getValue()),
context.getCurrentOrigin()));
checkDiscardedResult();
}
/**
* Generates a PlugStm for a close operation.
*/
private void putClose(Value base) {
hardcodeResult = makevar();
cfg.addStatement(new PlugStm(PlugStm.Kind.CLOSE, hardcodeResult, translateExpr(base),
null, null, null, context.getCurrentOrigin()));
checkDiscardedResult();
}
/**
* Generates a GapifyStm.
*/
private void putGapify(Value base, Value xpath, Value gap, Value type) {
SchemaType schema;
if (type != null) {
schema = context.parseSchemaType(context.getConstantString(type), context.getCurrentOrigin());
} else {
schema = null;
}
cfg.addStatement(new GapifyStm(hardcodeResult = makevar(), translateExpr(base),
context.getConstantString(xpath), context.getConstantString(gap), schema, context.getCurrentOrigin()));
checkDiscardedResult();
}
/**
* Generates an AnalyzeStm.
*/
private void putAnalyze(Value base, Value type) {
SchemaType schema = context.parseSchemaType(context.getConstantString(type), context.getCurrentOrigin());
cfg.addStatement(new AnalyzeStm(AnalyzeStm.Kind.ANALYZECALL, hardcodeResult = makevar(), translateExpr(base),
schema,
context.getCurrentOrigin()));
}
/**
* Generates an ValidateStm.
*/
private void putValidate(Value base, Value type) {
SchemaType schema = context.parseSchemaType(context.getConstantString(type), context.getCurrentOrigin());
cfg.addStatement(new ValidateStm(hardcodeResult = makevar(), translateExpr(base),
schema,
context.getCurrentOrigin()));
}
/**
* Generates an InsertStm.
*/
private void putInsert(InsertStm.Kind kind, Value base, Value xpath, ValueBox source, boolean convertObjects) {
Statement stm;
cfg.addStatement(stm = new InsertStm(kind, hardcodeResult = makevar(), translateExpr(base),
xpath!=null ? context.getConstantString(xpath) : null,
convertObjects ? null : Automaton.makeEmpty(),
convertObjects ? getVariableFromObjectExp(source) : translateExpr(source.getValue()),
context.getCurrentOrigin()));
if (convertObjects) {
addStringStatement(stm, source);
}
checkDiscardedResult();
}
/**
* Generates a SetStm.
*/
private void putSet(SetStm.Kind kind, Value base, Value xpath, ValueBox source) {
cfg.addStatement(addStringStatement(new SetStm(kind, hardcodeResult = makevar(), translateExpr(base),
xpath!=null ? context.getConstantString(xpath) : null,
null,
getVariableFromObjectExp(source), context.getCurrentOrigin()), source));
checkDiscardedResult();
}
/**
* Generates a RemoveStm.
*/
private void putRemove(Value base, Value xpath) {
cfg.addStatement(new RemoveStm(hardcodeResult = makevar(), translateExpr(base),
context.getConstantString(xpath), context.getCurrentOrigin()));
checkDiscardedResult();
}
/**
* Generates a GetStm.
*/
private void putGet(GetStm.Kind kind, Value base, Value xpath) {
cfg.addStatement(new GetStm(kind, hardcodeResult = makevar(), translateExpr(base),
xpath!=null ? context.getConstantString(xpath) : null, context.getCurrentOrigin()));
checkDiscardedResult();
}
/**
* Generates a GetStm.
*/
private void putGetElementById(Value base, Value id) {
error(ErrorType.UNSUPPORTED_OPERATION,
"getElementByID is not supported by the analysis");
// TODO: Make a new GetStm.Kind that implements getElementByID.
// The regular expression evaluator is not precise enough to
// be useful.
putUnknown();
// String idString = context.getConstantString(id);
// if (!XMLNavigator.isValidXPathString(idString)) {
// error(ErrorType.OTHER, "%s is not a valid ID string", idString);
// } else {
// String xpath = "node()//node()[@id='" + idString + "']";
// cfg.addStatement(new GetStm(
// GetStm.Kind.GETELEMENT,
// hardcodeResult = makevar(),
// translateExpr(base),
// xpath,
// context.getCurrentOrigin()));
// checkDiscardedResult();
// }
}
/**
* Generates a CopyStm.
*/
private void putCopy(CopyStm.Kind kind, Value base, ValueBox firstchild, ValueBox firstattr, ValueBox nextnode) {
cfg.addStatement(new CopyStm(kind, hardcodeResult = makevar(), translateExpr(base),
firstchild!=null ? translateOrEmptyIfNull(firstchild.getValue()) : null,
firstattr!=null ? translateOrEmptyIfNull(firstattr.getValue()) : null,
nextnode!=null ? translateOrEmptyIfNull(nextnode.getValue()) : null,
context.getCurrentOrigin()));
checkDiscardedResult();
}
/**
* Generates a ConcatStm.
*/
private void putConcat(ValueBox source) {
ArrayConstantInfo info = context.getConstantArray(source.getValue());
if (info.contents != null) {
// we know exactly how this array is structured
// use append statements instead to preserve non-emptiness and sequence order
Variable var = makevar();
// check if array was not initialized completely
for (int i=0; i<info.contents.length; i++) {
if (info.contents[i] == null || info.contents[i].getValue() instanceof NullConstant) {
// concat() definitely throws NullPointerException
// just return uninitialized variable
hardcodeResult = var;
return;
}
}
cfg.addStatement(new ConstStm(var,
emptyConstant,
context.getCurrentOrigin()));
for (int i=0; i<info.contents.length; i++) {
Variable var2 = makevar();
Variable val = translateExpr(info.contents[i].getValue());
Statement stm;
cfg.addStatement(stm = new InsertStm(InsertStm.Kind.APPEND,
var2,
var,
null,
Automaton.makeEmpty(),
val,
context.getCurrentOrigin()));
addStringStatement(stm, info.contents[i]);
var = var2;
}
hardcodeResult = var;
} else {
cfg.addStatement(new ConcatStm(hardcodeResult = makevar(),
Automaton.makeEmpty(), // string source is set in ArrayTransformer
translateExpr(source.getValue()),
context.getCurrentOrigin()));
}
checkDiscardedResult();
}
/**
* Generates a NodeStm.
*/
private void putNode(NodeStm.Kind kind, Value result, ValueBox namespace, ValueBox localname, ValueBox value,
ValueBox firstattr, ValueBox firstchild, Value gap, Value type, ValueBox nextnode, Origin origin) {
//Automaton name = localname!= null ? context.getAutomatonFromStringExp(localname) : null;
String ns = namespace!=null ? context.getConstantString(namespace.getValue()) : null;
//if (ns!=null && name!=null)
// name = Automaton.makeString('{' + ns + '}').concatenate(name);
hardcodeResult = context.getLocal(((Local)result).getName());
cfg.addStatement(addStringStatement(new NodeStm(kind, hardcodeResult,
null,
null,
firstchild!=null ? translateOrEmptyIfNull(firstchild.getValue()) : null,
firstattr!=null ? translateOrEmptyIfNull(firstattr.getValue()) : null,
gap!=null ? context.getConstantString(gap) : null,
type!=null ? context.getConstantString(type) : null,
nextnode!=null ? translateOrEmptyIfNull(nextnode.getValue()) : null,
origin),
localname,
value,
ns));
}
/**
* Generates a CastStm.
*/
private void putCast(CastStm.Kind kind, Variable source) {
cfg.addStatement(new CastStm(kind, hardcodeResult = makevar(), source, context.getCurrentOrigin()));
}
/**
* Generates a CheckStm.
*/
private void putCheck(CheckStm.Kind kind, Value base, Value xpath) {
cfg.addStatement(new CheckStm(kind,
translateExpr(base),
xpath!=null ? context.getConstantString(xpath) : null,
context.getCurrentOrigin()));
hardcodeResult = context.getNothing();
}
/**
* Returns a flow graph variable representing the possible XML values of the given Soot expression.
* For every subclass of the declared class type of the expression:
* if the subclass is an XML type, an assignment is added from the value to the new variable;
* if the subclass implements {@link ToXMLable}, an assignment is added from
* a call to <code>toXML</code> on the value to the new variable.
* Returns null is the input type is <code>NullType</code>.
*/
public Variable getVariableFromArrayExp(ValueBox b) {
Type t = b.getValue().getType();
while (t instanceof ArrayType)
t = ((ArrayType) t).getElementType();
return getVarFromObjectExpByType(b, t);
}
public Variable getVariableFromIterableExp(ValueBox b) {
return getVarFromObjectExpByType(b, RefType.v("java.lang.Object"));
}
public Variable getVariableFromObjectExp(ValueBox b) {
return getVarFromObjectExpByType(b, b.getValue().getType());
}
public Variable getVarFromObjectExpByType(ValueBox b, Type t) {
if (t instanceof RefType) {
Variable var = new Variable(context.getNextVarID(), false);
Debug.println(15, true, " created variable for " + b.getValue() + ": " + var);
cfg.startBranch();
// make an empty branch leaving the variable undefined.
// this case covers when a text node is plugged in
cfg.useBranch();
// plug in as XML if it is an XML node
// boolean xml = context.isSubtypeOf(t, "dk.brics.xact.XML");
// if (t.equals(RefType.v("java.lang.Object")) || xml) {
cfg.addStatement(new VarStm(var, translateExpr(b.getValue()), context.getCurrentOrigin()));
cfg.useBranch();
// }
// if not XML, call appropriate toXML methods.
// XXX a proper type analysis will upgrade both performance and precision here
// if (!xml) {
// for (SootClass sc : context.getSubclassesOfIncluding((RefType)t)) {
// if (implementsToXMLable(sc)) {
// Variable v = convertToXML(sc);
// cfg.addStatement(new VarStm(var, v, context.getCurrentOrigin()));
// cfg.useBranch();
// }
// }
// }
cfg.endBranch();
return var;
} else if (t instanceof NullType) {
return null;
} else if (t instanceof ArrayType) {
return context.getNothing(); // used in a place where arrays are not accepted
} else {
throw new RuntimeException("RefType expected"); // unreachable
}
}
public boolean implementsToXMLable(SootClass sc) {
if (sc.getName().equals("java.lang.Object"))
return false;
return sc.implementsInterface("dk.brics.xact.ToXMLable") || implementsToXMLable(sc.getSuperclass());
}
}