Package dk.brics.string.java

Source Code of dk.brics.string.java.StatementTranslatorImpl

package dk.brics.string.java;

import java.util.ArrayList;
import java.util.List;

import soot.ArrayType;
import soot.Local;
import soot.RefType;
import soot.SootMethod;
import soot.Type;
import soot.Value;
import soot.ValueBox;
import soot.jimple.AddExpr;
import soot.jimple.AndExpr;
import soot.jimple.ArrayRef;
import soot.jimple.AssignStmt;
import soot.jimple.BreakpointStmt;
import soot.jimple.CastExpr;
import soot.jimple.DefinitionStmt;
import soot.jimple.DivExpr;
import soot.jimple.EnterMonitorStmt;
import soot.jimple.EqExpr;
import soot.jimple.ExitMonitorStmt;
import soot.jimple.FieldRef;
import soot.jimple.FloatConstant;
import soot.jimple.GeExpr;
import soot.jimple.GotoStmt;
import soot.jimple.IdentityStmt;
import soot.jimple.IfStmt;
import soot.jimple.InstanceFieldRef;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InstanceOfExpr;
import soot.jimple.IntConstant;
import soot.jimple.InterfaceInvokeExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.InvokeStmt;
import soot.jimple.LengthExpr;
import soot.jimple.LongConstant;
import soot.jimple.LookupSwitchStmt;
import soot.jimple.MulExpr;
import soot.jimple.NeExpr;
import soot.jimple.NegExpr;
import soot.jimple.NewArrayExpr;
import soot.jimple.NewExpr;
import soot.jimple.NewMultiArrayExpr;
import soot.jimple.NopStmt;
import soot.jimple.NullConstant;
import soot.jimple.OrExpr;
import soot.jimple.ParameterRef;
import soot.jimple.RemExpr;
import soot.jimple.RetStmt;
import soot.jimple.ReturnStmt;
import soot.jimple.ReturnVoidStmt;
import soot.jimple.ShlExpr;
import soot.jimple.ShrExpr;
import soot.jimple.SpecialInvokeExpr;
import soot.jimple.StaticFieldRef;
import soot.jimple.StaticInvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.StmtSwitch;
import soot.jimple.StringConstant;
import soot.jimple.SubExpr;
import soot.jimple.TableSwitchStmt;
import soot.jimple.ThrowStmt;
import soot.jimple.UshrExpr;
import soot.jimple.VirtualInvokeExpr;
import soot.jimple.XorExpr;
import dk.brics.automaton.Automaton;
import dk.brics.string.intermediate.ArrayAddAll;
import dk.brics.string.intermediate.ArrayAssignment;
import dk.brics.string.intermediate.ArrayCorrupt;
import dk.brics.string.intermediate.ArrayFromArray;
import dk.brics.string.intermediate.ArrayNew;
import dk.brics.string.intermediate.ArrayWriteArray;
import dk.brics.string.intermediate.ArrayWriteElement;
import dk.brics.string.intermediate.Hotspot;
import dk.brics.string.intermediate.ObjectAssignment;
import dk.brics.string.intermediate.ObjectCorrupt;
import dk.brics.string.intermediate.PrimitiveAssignment;
import dk.brics.string.intermediate.PrimitiveFromArray;
import dk.brics.string.intermediate.PrimitiveInit;
import dk.brics.string.intermediate.Return;
import dk.brics.string.intermediate.Statement;
import dk.brics.string.intermediate.StringAssignment;
import dk.brics.string.intermediate.StringBufferAssignment;
import dk.brics.string.intermediate.StringBufferCorrupt;
import dk.brics.string.intermediate.StringBufferInit;
import dk.brics.string.intermediate.StringFromArray;
import dk.brics.string.intermediate.StringInit;
import dk.brics.string.intermediate.Variable;
import dk.brics.string.intermediate.VariableType;
import dk.brics.string.stringoperations.Basic;

/**
* Translates Jimple-expressions and -statements into {@link Statement}s in intermediate form.
* <p/>
* This interface requires an implementation of the {@link IntermediateFactory} facade,
* which is currently provided by the {@link StatementTranslatorFacadeImpl}.
* <p/>
* Note that this class is also responsible for creating {@link Hotspot} statements for each
* <tt>ValueBox</tt> marked as a hotspot. {@link IntermediateFactory#isHotspot} defines what
* is a hotspot.
*/
public class StatementTranslatorImpl extends ExprAnswerVisitor<ValueBox, Variable> implements StmtSwitch, StatementTranslator {
 
  private IntermediateFactory factory;
  private MethodCallTranslator methodCallTranslator;
  private FieldReferenceTranslator fieldReferenceTranslator;

  public StatementTranslatorImpl(MethodCallTranslator methodCalls, FieldReferenceTranslator fields) {
    this.methodCallTranslator = methodCalls;
    this.fieldReferenceTranslator = fields;
  }
 
  private Variable makeVariable(VariableType type) {
    return factory.createVariable(type);
  }
  private void addStatement(Statement stm) {
    factory.addStatement(stm);
  }
 
  private VariableType getType(Type type) {
    return factory.fromSootType(type);
  }
 
  private void assignNull(Variable to) {
    switch (to.getType()) {
    case STRING:
      addStatement(new StringInit(to, Automatons.getNull()));
      break;
     
    case STRINGBUFFER:
      // make a string buffer with the empty language of possible strings
      Variable temp = makeVariable(VariableType.STRING);
      addStatement(new StringBufferInit(to, temp));
      break;
     
    case ARRAY:
      // make an array with the empty language of possible strings, by not writing any strings to it
      addStatement(new ArrayNew(to));
      break;
     
    case PRIMITIVE:
        assert false;
        break;
     
    default:
      break; // XXX add ObjectNull-statement?? this ensures that the variable is not an alias of another variable anymore
    }
  }
 
  private void assignValue(Variable to, Variable from) {
    // ignore uninteresting assignments
    if ((to.getType() == VariableType.NONE || to.getType() == VariableType.NULL) && (from.getType() == VariableType.NONE || from.getType() == VariableType.NULL))
      return;
   
    if (from.getType() == VariableType.NULL) {
      assignNull(to);
      return;
    }
   
    if (to.getType() == VariableType.NONE) {
        return;
    }
   
    // useful error checking
    if (to.getType().cannotBeAliasOf(from.getType()))
      throw new RuntimeException("Cannot assign from " + from.getType() + " to " + to.getType());
   
    switch (from.getType()) {
    case STRING:
      addStatement(new StringAssignment(to, from));
      break;
     
    case STRINGBUFFER:
      addStatement(new StringBufferAssignment(to, from));
      break;
     
    case ARRAY:
      addStatement(new ArrayAssignment(to, from));
      break;
     
    case PRIMITIVE:
        addStatement(new PrimitiveAssignment(to, from));
        break;
     
    default:
      addStatement(new ObjectAssignment(to, from));
    }
  }
 
  /**
   * Corrupts the object pointed to by the specified variable, if that
   * object is mutable.
   */
  private void corruptIfMutable(Variable var) {
    if (var.getType() == VariableType.NONE || var.getType() == VariableType.NULL) // we don't care if this object is corrupted
      return;
    switch (var.getType()) {
    case STRING:
    case PRIMITIVE:
      break;
    case STRINGBUFFER:
      addStatement(new StringBufferCorrupt(var));
      break;
    case ARRAY:
      addStatement(new ArrayCorrupt(var));
      break;
    default:
      addStatement(new ObjectCorrupt(var));
    }
  }
 
  private Variable makeAnyStringVariable() {
    Variable v = makeVariable(VariableType.STRING);
    addStatement(new StringInit(v, Basic.makeAnyString()));
    return v;
  }
  private Variable makeConstantStringVariable(String value) {
    Variable v = makeVariable(VariableType.STRING);
    addStatement(new StringInit(v, Automaton.makeString(value)));
    return v;
  }
    private Variable makeConstantCharVariable(char value) {
        Variable v = makeVariable(VariableType.STRING);
        addStatement(new StringInit(v, Automaton.makeChar(value)));
        return v;
    }
    private Variable makeAutomatonVariable(Automaton automaton) {
        Variable v = makeVariable(VariableType.STRING);
        addStatement(new StringInit(v, automaton));
        return v;
    }
 
  /**
   * Returns a variable that may contain any non-corrupt value of the specified type.
   */
  private Variable getAnyValueOf(VariableType type) {
    if (type == VariableType.NONE)
      return getNothing();
    Variable v = makeVariable(type);
    assignAnyValue(v);
    return v;
  }
 
  /**
   * Assigns an unknown value to the specified variable.
   */
  private void assignAnyValue(Variable v) {
    switch (v.getType()) {
    case STRING:
      addStatement(new StringInit(v, Basic.makeAnyString()));
      break;
    case STRINGBUFFER:
      addStatement(new StringBufferInit(v, makeAnyStringVariable()));
      break;
    case ARRAY:
      addStatement(new ArrayNew(v));
      addStatement(new ArrayWriteElement(v, makeAnyStringVariable()));
      break;
    case PRIMITIVE:
        addStatement(new PrimitiveInit(v, Automaton.makeAnyChar()));
        break;
    default:
      // no initialization necessary of uncertain objects
    }
  }
 
  /**
   * Returns a variable of type <tt>NONE</tt>.
   */
  private Variable getNothing() {
    return factory.getNothing();
  }
 
  /**
   * Translates the expression contained in the specified value box, and returns
   * a variable holding the result. This should always be used instead of <tt>applyTo</tt>
   * directly, since this also takes care of creating hotspots.
   * @param box the jimple expression to translate
   * @return a variable holding the result
   */
  private Variable translateExpression(ValueBox box) {
    Variable result = applyTo(box.getValue(), box);
   
    if (factory.isHotspot(box)) {
        factory.addHotspot(result, box);
    }
   
    factory.setExpressionVariable(box, result);
   
    return result;
  }
 
  /* (non-Javadoc)
   * @see dk.brics.string.java.StatementTranslator#translateStatement(soot.jimple.Stmt, dk.brics.string.java.IntermediateFactory)
   */
  public void translateStatement(Stmt statement, IntermediateFactory factory) {
    this.factory = factory;
    statement.apply(this);
  }
 
  //
  //    VISITOR METHODS
  //
 
  @Override
  public Variable caseLocal(Local v, ValueBox box) {
    return factory.getLocal(v);
  }
 
  @Override
  public Variable caseArrayRef(ArrayRef v, ValueBox box) {
    // read something from an array
    Variable arrayObject = translateExpression(v.getBaseBox());
    VariableType innerType = getType(v.getType());
   
    if (innerType == VariableType.NONE)
      return getNothing();
   
    Variable result = makeVariable(innerType);
    switch (innerType) {
    case STRINGBUFFER:
      addStatement(new StringBufferCorrupt(result));
      break;
     
    case ARRAY:
      addStatement(new ArrayFromArray(result, arrayObject));
      break;
     
    case PRIMITIVE:
        addStatement(new PrimitiveFromArray(result, arrayObject));
        break;
     
    default:
      addStatement(new StringFromArray(result, arrayObject));
    }
   
    return result;
  }
 
  @Override
  public Variable caseCastExpr(CastExpr v, ValueBox box) {
    Variable operand = translateExpression(v.getOpBox());
    VariableType castTo = getType(v.getCastType());
   
    // whatever comes out of the cast must satisfy both the operand's type and the casted type
    VariableType resultType = operand.getType().greatestLowerBound(castTo);
    if (resultType == VariableType.NONE) {
      return getNothing();
    }
   
    // if a primitive cast is performed, assume nothing about the result
//    if (castTo == VariableType.PRIMITIVE) {
//      if (v.getOp().getType().equals(v.getCastType())) {
//        return operand;
//      } else {
//        return getAnyValueOf(VariableType.PRIMITIVE);
//      }
//    }
   
    // upgrade the result to the casted type
    // other parts of the translation can use the additional information
    Variable result;
    if (resultType == operand.getType()) {
      result = operand;
    } else {
      result = factory.createVariable(resultType);
      assignValue(result, operand);
    }
   
    return result;
  }
 
  @Override
  public Variable caseInterfaceInvokeExpr(InterfaceInvokeExpr v, ValueBox box) {
    return invokeExpr(v, box);
  }
 
  @Override
  public Variable caseVirtualInvokeExpr(VirtualInvokeExpr v, ValueBox box) {
    return invokeExpr(v, box);
  }
 
  @Override
  public Variable caseSpecialInvokeExpr(SpecialInvokeExpr v, ValueBox box) {
    Variable callee = translateExpression(v.getBaseBox());

    // evaluate all arguments
    List<Variable> arguments = new ArrayList<Variable>();
    for (int i=0; i<v.getArgCount(); i++) {
      arguments.add(translateExpression(v.getArgBox(i)));
    }
   
    // if the called class could not be found (ie a phantom class), treat it as a corrupt call
    if (v.getMethodRef().declaringClass().isPhantom()) {
        return handlePhantomInvocation(v, arguments);
    }
   
        SootMethod method = v.getMethod();
   
    // Is this a constructor call?
    if (method.getName().equals("<init>")) {
      return handleConstructor(v, callee, arguments);
    }
   
    // try to handle it as an abstract method call. even though we know the exact target,
    // this is the correct thing to do according to the MethodCallTranslator interface.
    Variable result = methodCallTranslator.translateAbstractMethodCall(v, method, callee, arguments, factory);
    if (result != null)
      return result;
   
    // Otherwise just handle it as a normal call with only one possible target
    result = makeVariable(getType(v.getMethod().getReturnType()));
    handleInvocationTarget(result, v, method, callee, arguments);
   
        // if the called method was annotated, use the static type instead
        Automaton staticType = factory.getMethodReturnType(v.getMethod());
        if (staticType != null)
            return makeAutomatonVariable(staticType);
        else
            return result;
  }
 
  private Variable handleConstructor(SpecialInvokeExpr expr, Variable callee, List<Variable> arguments) {
    if (methodCallTranslator.translateConstructorCall(expr, callee, arguments, factory)) {
      return getNothing();
    }
    // Do some worst-case handling otherwise
    // corrupt callee and all arguments
    corruptIfMutable(callee);
    for (Variable arg : arguments) {
      corruptIfMutable(arg);
    }
    return getNothing();
  }
 
  private Variable invokeExpr(InstanceInvokeExpr v, ValueBox box) {
        // evaluate all arguments
        List<Variable> arguments = new ArrayList<Variable>();
        for (int i=0; i<v.getArgCount(); i++) {
            arguments.add(translateExpression(v.getArgBox(i)));
        }
       
        // if we are calling a phantom method, just corrupt everything involved
      if (v.getMethodRef().declaringClass().isPhantom()) {
          return handlePhantomInvocation(v, arguments);
      }
   
      SootMethod method = v.getMethod();
    Variable callee = translateExpression(v.getBaseBox());
   
    // Special case: clone() on an array or collection
    if (method.getName().equals("clone") && method.getParameterCount() == 0 && callee.getType() == VariableType.ARRAY) {
      return handleArrayClone(callee);
    }
   
    // try to translate the abstract call
    Variable r2 = methodCallTranslator.translateAbstractMethodCall(v, v.getMethod(), callee, arguments, factory);
    if (r2 != null)
      return r2;
   
    // find the possible implementations that get called
    List<SootMethod> targets = factory.getTargetsOf(v);
   
    if (targets.size() == 0) {
        // try to translate the abstract method call. A resolver could know something useful.
        Variable result = methodCallTranslator.translateMethodCall(v, method, callee, arguments, factory);
       
        if (result != null)
            return result;
    }
       
        // create a variable with the result
        VariableType returnType = getType(method.getReturnType());
        Variable result = makeVariable(returnType);
       
        // split the control-flow graph for each possible target
    factory.startBranch();
   
    // if no targets can be seen, we will assume it is a corrupting call (externally implemented)
    // TODO: Externally extended/implemented classes should be made more explicit with a strategy interface
    // TODO: Resolvers never get a chance to resolve this type of method call.
    //       For example, HttpServletRequest.getRequestURI() because its implementation is dynamically loaded.
    if (targets.size() == 0) {
      handleCorruptInvocation(result, callee.getType(), callee, arguments);
      factory.useBranch();
    }
   
    for (SootMethod target : targets) {
      handleInvocationTarget(result, v, target, callee, arguments);
      factory.useBranch();
    }
   
    factory.endBranch();
   
    // if the called method was annotated, use the static type instead
        Automaton staticType = factory.getMethodReturnType(v.getMethod());
    if (staticType != null)
        return makeAutomatonVariable(staticType);
    else
        return result;
  }
 
  /**
   * Creates statements for an invocation to a known method implementation.
   * @param result where to store the result (has type <tt>NONE</tt> if method returns <tt>void</tt>).
   * @param v the invocation expression
   * @param target method implementation being called; may differ from <tt>v.getMethod()</tt>.
   * @param callee variable holding the object being called on
   * @param arguments variables holding the method call's arguments
   */
  private void handleInvocationTarget(Variable result, InstanceInvokeExpr v, SootMethod target, Variable callee, List<Variable> arguments) {
    Variable goodResult = methodCallTranslator.translateMethodCall(v, target, callee, arguments, factory);
    if (goodResult != null) {
      assignValue(result, goodResult);
    } else {
      // if the method declaring the method might be an interesting mutable type,
      // corrupt the callee
      VariableType declaringClass = factory.fromSootType(target.getDeclaringClass().getType());
      handleCorruptInvocation(result, declaringClass, callee, arguments);
    }
  }
 
  /**
   * Creates statements corresponding to an invocation to an unknown method, thus corrupting every variable involved.
   * @param result where to store the (corrupt) result
   * @param declaringClass the type of the class declaring the method (on a best-known basis)
   * @param callee variable holding the object being called on
   * @param arguments variables holding the method call's arguments
   */
  private void handleCorruptInvocation(Variable result, VariableType declaringClass, Variable callee, List<Variable> arguments) {
    if (declaringClass.mightBeUsefulMutable()) {
      corruptIfMutable(callee);
    }
   
    // corrupt all arguments
    for (Variable arg : arguments) {
      corruptIfMutable(arg);
    }
   
    // give the result any corrupt value
    assignAnyValue(result);
    corruptIfMutable(result);
  }
 
  private Variable handlePhantomInvocation(InvokeExpr exp, List<Variable> arguments) {
      Variable result = makeVariable(getType(exp.getType()));
      for (Variable arg : arguments) {
          corruptIfMutable(arg);
      }
        assignAnyValue(result);
        corruptIfMutable(result);
      return result;
  }
 
  /**
   * Creates statements that simulate <tt>String[].clone()</tt>.
   * <p/>
   * Cannot currently be handled by method call translators, because it is
   * really <tt>Object.clone()</tt> being called, followed by a typecast (which is invisible in Java).
   */
  private Variable handleArrayClone(Variable callee) {
    Variable result = factory.createVariable(VariableType.ARRAY);
    factory.addStatement(new ArrayAddAll(result, callee));
    return result;
  }
 
  @Override
  public Variable caseNewExpr(NewExpr v, ValueBox box) {
    return makeVariable(getType(v.getBaseType()));
  }
 
  @Override
  public Variable caseNewArrayExpr(NewArrayExpr v, ValueBox box) {
    return handleArrayNew(v.getBaseType());
  }
 
  @Override
  public Variable caseNewMultiArrayExpr(NewMultiArrayExpr v, ValueBox box) {
    return handleArrayNew(v.getBaseType());
  }
   
    private Variable handleArrayNew(Type type) {
        if (getType(type) == VariableType.NONE// arrays of uninteresting types may be ignored
            return getNothing();
       
        // dig out the element type
        Type elementType = type;
        while (elementType instanceof ArrayType) {
            elementType = ((ArrayType)elementType).getElementType();
        }
       
        Variable var = makeVariable(VariableType.ARRAY);
        if (elementType instanceof RefType) {
            // object arrays are filled with null initially
            addStatement(new ArrayWriteElement(var, makeConstantStringVariable("null")));
        } else {
            // primitive arrays are filled zeros initially
            addStatement(new ArrayWriteElement(var, makeConstantCharVariable('\0')));
        }
        return var;
    }
 
  @Override
  public Variable caseNullConstant(NullConstant v, ValueBox box) {
    return makeVariable(VariableType.NULL);
  }
 
  @Override
  public Variable caseParameterRef(ParameterRef v, ValueBox box) {
      Automaton staticType = factory.getParameterType(v);
      if (staticType != null) {
          return makeAutomatonVariable(staticType);
      }
    return factory.getParameter(v);
  }
 
  @Override
  public Variable caseStaticInvokeExpr(StaticInvokeExpr v, ValueBox box) {
      Variable result = null;
     
      // find the static string return type, if it has one
      Automaton staticReturn = factory.getMethodReturnType(v.getMethod());
      if (staticReturn != null) {
          result = makeAutomatonVariable(staticReturn);
      }
     
    // evaluate all arguments
    List<Variable> arguments = new ArrayList<Variable>();
    for (int i=0; i<v.getArgCount(); i++) {
      arguments.add(translateExpression(v.getArgBox(i)));
    }
       
    // translate the method call (if possible)
    Variable goodResult = methodCallTranslator.translateStaticMethodCall(v, arguments, factory);
    if (result == null) {
        result = goodResult;
    }
    if (goodResult != null) {
      return result;
    }
   
    // Do some worst-case handling otherwise
    // corrupt all arguments
    for (Variable arg : arguments) {
      corruptIfMutable(arg);
    }
   
    // create a return-value that can have any value and is corrupt
    if (result == null) {
        result = getAnyValueOf(VariableType.OBJECT);
          corruptIfMutable(result);
    }
   
    return result;
  }
 
  @Override
  public Variable caseStringConstant(StringConstant v, ValueBox box) {
    return makeConstantStringVariable(v.value);
  }
 
  @Override
  public Variable caseIntConstant(IntConstant v, ValueBox question) {
      Variable result = makeVariable(VariableType.PRIMITIVE);
      if (v.value >= Character.MIN_VALUE && v.value <= Character.MAX_VALUE) {
          addStatement(new PrimitiveInit(result, Automaton.makeChar((char)v.value)));
      } else {
          addStatement(new PrimitiveInit(result, Automaton.makeAnyChar()));
      }
      return result;
  }
  @Override
  public Variable caseLongConstant(LongConstant v, ValueBox question) {
    Variable result = makeVariable(VariableType.PRIMITIVE);
      if (v.value >= Character.MIN_VALUE && v.value <= Character.MAX_VALUE) {
          addStatement(new PrimitiveInit(result, Automaton.makeChar((char)v.value)));
      } else {
          addStatement(new PrimitiveInit(result, Automaton.makeAnyChar()));
      }
      return result;
  }
 
  @Override
  public Variable caseInstanceFieldRef(InstanceFieldRef v, ValueBox box) {
    return handleFieldRef(v, box);
  }
 
  @Override
  public Variable caseStaticFieldRef(StaticFieldRef v, ValueBox box) {
      return handleFieldRef(v, box);
  }
 
  private Variable handleFieldRef(FieldRef v, ValueBox box) {
      VariableType type = factory.fromSootType(v.getType());
        if (type == VariableType.NONE)
            return getNothing();
       
        // if the field is @Type annotated, create a variable with its static type
        if (factory.fromSootType(v.getType()) == VariableType.STRING) {
            Automaton staticType = factory.getFieldType(v.getField());
            if (staticType != null) {
                return makeAutomatonVariable(staticType);
            }
        }
       
        Variable result = fieldReferenceTranslator.translateFieldRef(v, box, factory);
        if (result != null) {
            return result;
        }
       
        result = getAnyValueOf(type);
        corruptIfMutable(result);
        return result;
  }
 
  @Override
  public Variable caseEqExpr(EqExpr v, ValueBox question) {
      translateExpression(v.getOp1Box());
      translateExpression(v.getOp2Box());
      return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseNeExpr(NeExpr v, ValueBox question) {
      translateExpression(v.getOp1Box());
      translateExpression(v.getOp2Box());
      return getAnyValueOf(VariableType.PRIMITIVE);
  }
 
  @Override
  public Variable caseAddExpr(AddExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseSubExpr(SubExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseAndExpr(AndExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseDivExpr(DivExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseFloatConstant(FloatConstant v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseLengthExpr(LengthExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseInstanceOfExpr(InstanceOfExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseMulExpr(MulExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseOrExpr(OrExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseNegExpr(NegExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseRemExpr(RemExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseShlExpr(ShlExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseShrExpr(ShrExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseUshrExpr(UshrExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
  @Override
  public Variable caseXorExpr(XorExpr v, ValueBox question) {
    return getAnyValueOf(VariableType.PRIMITIVE);
  }
 
  @Override
  public Variable defaultExpr(Object v, ValueBox box) {
    return getNothing();
  }
 
 
  //
  //  STATEMENTS
  //

  public void caseAssignStmt(AssignStmt stmt) {
    assignment(stmt);
  }
  public void caseIdentityStmt(IdentityStmt stmt) {
    assignment(stmt);
  }
  public void assignment(DefinitionStmt stmt) {
    Variable result = translateExpression(stmt.getRightOpBox());
   
    if (result.getType() == VariableType.NONE) {
      return; // no need to track this object
    }
   
    // assign to a local variable?
    if (stmt.getLeftOp() instanceof Local) {
      Variable lefthandSide = factory.getLocal((Local)stmt.getLeftOp());
      assignValue(lefthandSide, result);
   
    // assign to a field?
    } else if (stmt.getLeftOp() instanceof FieldRef) {
      FieldRef ref = (FieldRef)stmt.getLeftOp();
     
      // delegate the translation
      fieldReferenceTranslator.translateFieldAssignment(ref, result, factory);
   
    // assign into an array slot?
    } else if (stmt.getLeftOp() instanceof ArrayRef) {
      ArrayRef left = (ArrayRef)stmt.getLeftOp();
      Value array = left.getBase();
      if (array instanceof Local) {
        Local arrayLocal = (Local)array;
        Variable arrayVariable = factory.getLocal(arrayLocal);
       
        switch (result.getType()) {
        case STRING:
        case PRIMITIVE:
          addStatement(new ArrayWriteElement(arrayVariable, result));
          break;
         
        case ARRAY:
          addStatement(new ArrayWriteArray(arrayVariable, result));
          break;
         
        default:
          corruptIfMutable(result);
          corruptIfMutable(arrayVariable);
          break;
        }
      } else {
        // we are probably storing a string into a field of type array
        // just ignore it; we don't track mutable arrays anyway
        corruptIfMutable(result);
      }
   
    // assign to what!?
    } else {
      throw new RuntimeException("Unknown left-hand side " + stmt.getClass().getCanonicalName());
    }
  }
 
  public void caseInvokeStmt(InvokeStmt stmt) {
    translateExpression(stmt.getInvokeExprBox());
  }
  public void caseReturnStmt(ReturnStmt stmt) {
    Variable returnValue = translateExpression(stmt.getOpBox());
    addStatement(new Return(returnValue));
  }
  public void caseReturnVoidStmt(ReturnVoidStmt stmt) {
    addStatement(new Return(getNothing()));
  }
 
  public void defaultCase(Object obj) {
  }
 
  /* ASSERTION-RELAVANT STATEMENTS */
  public void caseIfStmt(IfStmt stmt) {
      // translate this so assertions can use the expressions we evaluate
      translateExpression(stmt.getConditionBox());
    }
  public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
    translateExpression(stmt.getKeyBox());
  }
   
  /* IGNORED STATEMENTS */
  public void caseBreakpointStmt(BreakpointStmt stmt) {
  }
  public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
  }
  public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
  }
  public void caseGotoStmt(GotoStmt stmt) {
  }
  public void caseNopStmt(NopStmt stmt) {
  }
  public void caseRetStmt(RetStmt stmt) {
  }
  public void caseTableSwitchStmt(TableSwitchStmt stmt) {
  }
  public void caseThrowStmt(ThrowStmt stmt) {
  }
}
TOP

Related Classes of dk.brics.string.java.StatementTranslatorImpl

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.