Package dk.brics.xact.analysis.soot

Source Code of dk.brics.xact.analysis.soot.Translator

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());
  }


}
TOP

Related Classes of dk.brics.xact.analysis.soot.Translator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.