Package dk.brics.xact.analysis.soot

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

package dk.brics.xact.analysis.soot;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import soot.Hierarchy;
import soot.Immediate;
import soot.Local;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.ValueBox;
import soot.jimple.ClassConstant;
import soot.jimple.Constant;
import soot.jimple.NullConstant;
import soot.jimple.StringConstant;
import soot.jimple.toolkits.annotation.nullcheck.NullnessAnalysis;
import soot.tagkit.AnnotationStringElem;
import soot.tagkit.AnnotationTag;
import soot.tagkit.VisibilityAnnotationTag;
import soot.tagkit.VisibilityParameterAnnotationTag;
import soot.util.StringTools;
import dk.brics.misc.Origin;
import dk.brics.xact.analysis.ErrorHandler;
import dk.brics.xact.analysis.XMLAnalysisException;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
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.Variable;
import dk.brics.xact.analysis.flowgraph.statements.AnalyzeStm;
import dk.brics.xact.operations.XMLValidator;

/**
* Context for producing flow graph statements.
* This is simple storage with no actual functionality.
*/
public class TranslatorContext {
 
  /**
   * Current class.
   */
  private SootClass current_class;

  /**
   * Current method.
   */
  private SootMethod current_method;
 
  /**
   * Current source line.
   */
  private int current_line;
 
  /**
   * Current source origin.
   */
  private Origin current_origin;
 

  /**
   * Map from Soot field/local/dummy variable descriptor strings to flow graph variables.
   */
  private Map<String,Variable> var_map = new HashMap<String,Variable>();
 
  /**
   * Class hierarchy.
   */
  private Hierarchy hierarchy;
 
  /**
   * Serial number for created variables.
   */
  private int var_id = 0;
 
  private Variable nothing;
 
  /**
   * Namespace map.
   */
  private Map<String,String> namespaces = new HashMap<String,String>();
 
  private Map<String,Variable> field_map = new HashMap<String,Variable>();
 
  private FlowGraph graph;
  private Map<SootMethod, Method> methods = new HashMap<SootMethod, Method>();
 
  private Map<SootField, SchemaType> fieldSchemaTypes = new HashMap<SootField, SchemaType>();
 
  private NullnessAnalysis nullness;
  private StringConstantAnalysis stringConstants;
  private ArrayConstantAnalysis arrayConstants;
  private Unit currentUnit;

  private Map<Statement,ValueBox> stringHotspots1 = new HashMap<Statement, ValueBox>();;
  private Map<Statement,ValueBox> stringHotspots2 = new HashMap<Statement, ValueBox>();;
  private Map<Statement,String> nodeStmNamespaces = new HashMap<Statement, String>();
 
  private ErrorHandler errors;
 
  private Map<ValueBox,AnalyzeStm> expr2hotspot = new HashMap<ValueBox,AnalyzeStm>();
 
  /**
   * Returns the map from soot expression hotspots to
   * their corresponding statements in the flow graph.
   * @return modifiable map backed by this object
   */
  public Map<ValueBox,AnalyzeStm> getHotspotMap() {
    return expr2hotspot;
  }
 
  /**
   * Marks that the specified soot expression hotspot is being
   * modelled by the specified analyze statement.
   * @param expr a hotspot expression
   * @param stm the corresponding statement in the flow graph
   */
  public void putHotspot(ValueBox expr, AnalyzeStm stm) {
    expr2hotspot.put(expr, stm);
  }
 
  public ValueBox getStringHotspot1(Statement s) {
    return stringHotspots1.get(s);
  }
  public ValueBox getStringHotspot2(Statement s) {
    return stringHotspots2.get(s);
  }
  public String getNamespace(Statement s) {
    return nodeStmNamespaces.get(s);
  }
  public void setStringHotspot(Statement stm, ValueBox box) {
    stringHotspots1.put(stm, box);
  }
  public void setStringHotspot(Statement stm, ValueBox box1, ValueBox box2) {
    stringHotspots1.put(stm, box1);
    stringHotspots2.put(stm, box2);
  }
  public void setStringHotspot(Statement stm, ValueBox box1, ValueBox box2, String namespace) {
    stringHotspots1.put(stm, box1);
    stringHotspots2.put(stm, box2);
    nodeStmNamespaces.put(stm, namespace);
  }
 
  /**
   * Constructs a new translator context.
   */
  public TranslatorContext(FlowGraph g, ErrorHandler errors) {
    this.graph = g;
    this.errors = errors;
    hierarchy = new Hierarchy();
    nothing = new Variable(getNextVarID(), true);
    this.namespaces = g.getNamespaces();
  }
 
  public ErrorHandler getErrors() {
        return errors;
    }
 
  public void setCurrentUnit(Unit unit) {
    this.currentUnit = unit;
  }
 
  public void setNullness(NullnessAnalysis nullness) {
    this.nullness = nullness;
  }
  public void setStringConstants(StringConstantAnalysis stringConstants) {
    this.stringConstants = stringConstants;
  }
  public void setArrayConstants(ArrayConstantAnalysis arrayConstants) {
    this.arrayConstants = arrayConstants;
  }
  public boolean maybeNull(Value v) {
    if (v instanceof NullConstant)
      return true;
    if (v instanceof Constant)
      return false;
    return !nullness.isAlwaysNonNullBefore(currentUnit, (Immediate)v);
  }
  public boolean maybeNonNull(Value v) {
    if (v instanceof NullConstant)
      return false;
    if (v instanceof Constant)
      return true;
    return !nullness.isAlwaysNullBefore(currentUnit, (Immediate)v);
  }
  public boolean definitelyNull(Value v) {
    if (v instanceof NullConstant)
      return true;
    if (v instanceof Constant)
      return false;
    return nullness.isAlwaysNullBefore(currentUnit, (Immediate)v);
  }
  public boolean definitelyNonNull(Value v) {
    if (v instanceof NullConstant)
      return false;
    if (v instanceof Constant)
      return true;
    return nullness.isAlwaysNonNullBefore(currentUnit, (Immediate)v);
  }


  public Variable getNothing() {
    return nothing;
  }
 
  public Method getMethod(SootMethod method) {
    return methods.get(method);
  }
  public void setMethod(SootMethod sm, Method method) {
    methods.put(sm, method);
  }
 
  /**
   * Returns the next fresh variable ID.
   */
  public int getNextVarID() {
    return var_id++;
  }

  /**
   * Sets the current class.
   */
  public void setCurrentClass(SootClass c) {
    current_origin = null;
    current_class = c;
  }
 
  /**
   * Returns the current class.
   */
  public SootClass getCurrentClass() {
    return current_class;
  }

  /**
   * Sets the current method.
   */
  public void setCurrentSootMethod(SootMethod m) {
    current_origin = null;
    current_method = m;
    var_map.clear();
  }
 
  /**
   * Returns the current method.
   */
  public SootMethod getCurrentSootMethod() {
    return current_method;
  }
  public Method getCurrentMethod() {
    return getMethod(current_method);
  }
 
  /**
   * Returns the current origin.
   */
  public Origin getCurrentOrigin() {
    if (current_origin == null) {
      if (current_class == null || current_method == null)
        return new Origin("???", -1, 0);
      current_origin = new Origin(current_class.getName() + "." + current_method.getName(), current_line, 0);
    }
    return current_origin;
  }
 
  /**
   * Returns the current line number.
   */
  public int getCurrentLine() {
    return current_line;
  }
 
  /**
   * Sets the current line number.
   */
  public void setCurrentLine(int line) {
    current_origin = null;
    current_line = line;
  }
 

  /**
   * Returns the class hierarchy.
   */
  public Hierarchy getHierarchy() {
    return hierarchy;
  }
 
  public Variable getLocal(String name) {
    Variable v = var_map.get(name);
    if (v == null) {
      v = new Variable(getNextVarID(), false);
      var_map.put(name, v);
    }
    return v;
  }
  public Variable getField(SootField field) {
    Variable v = field_map.get(field.getSignature());
    if (v == null) {
      v = new Variable(getNextVarID(), true);
      field_map.put(field.getSignature(), v);
    }
    return v;
  }
 
  /**
   * Returns true if the specified type can have @Type annotations.
   */
  public boolean isAnnotatableType(Type t) {
    return isSubtypeOf(t, "dk.brics.xact.Node");
  }

  /**
   * Expands a QName according to the current namespace declarations.
   */
  public String expandQName(String qname) {
    return XMLValidator.expandQName(qname, getNamespaces(), null, getCurrentOrigin());
  }
 
  public SchemaType getFieldSchemaType(SootField sf) {
    return fieldSchemaTypes.get(sf);
  }
 
  public void setFieldSchemaType(SootField sf, SchemaType type) {
    fieldSchemaTypes.put(sf, type);
  }
 
  /**
   * Returns the Type annotation for a field, or null if not present.
   */
  public String getTypeAnnotation(SootField sf) {
    String type = null;
    if (isAnnotatableType(sf.getType()) && sf.hasTag("VisibilityAnnotationTag"))
      type = getTypeAnnotation((VisibilityAnnotationTag)sf.getTag("VisibilityAnnotationTag"));
    return type;
  }

  /**
   * Returns the Type annotation for a method return, or null if not present.
   */
  public String getTypeAnnotation(SootMethod m) {
    String type = null;
    if (isAnnotatableType(m.getReturnType()) && m.hasTag("VisibilityAnnotationTag"))
      type = getTypeAnnotation((VisibilityAnnotationTag)m.getTag("VisibilityAnnotationTag"));
    //System.out.println("Found @Type("+type+") at return from "+m);
    return type;
  }
  /**
   * Returns the Type annotation for a method parameter, or null if not present.
   */
  public String getTypeAnnotationForParameter(SootMethod m, int parameter) {
    if (!isAnnotatableType(m.getParameterType(parameter)))
      return null;
    VisibilityParameterAnnotationTag tag = (VisibilityParameterAnnotationTag)m.getTag("VisibilityParameterAnnotationTag");
    if (tag == null)
      return null;
    return getTypeAnnotation(tag.getVisibilityAnnotations().get(parameter));
  }
 
  private String getTypeAnnotation(VisibilityAnnotationTag vat) {
    if (vat == null)
      return null;
    for (AnnotationTag at : vat.getAnnotations())
      if (at.getType().equals("Ldk/brics/xact/Type;"))
        return ((AnnotationStringElem)at.getElemAt(0)).getValue();
    return null;
  }
 
  /*public void putField(String name, Variable var) {
    field_map.put(name, var);
  }*/
 
  /**
   * Returns the namespace declaration map (from prefix to URI).
   */
  public Map<String,String> getNamespaces() {
    return namespaces;
  }

  public FlowGraph getFlowGraph() {
    return graph;
  }
 

  public List<SootClass> getSubclassesOfIncluding(RefType t) {
    SootClass cl = t.getSootClass();
    if (cl.isInterface())
      return hierarchy.getImplementersOf(cl);
    else
      return hierarchy.getSubclassesOfIncluding(cl);
  }
 
  public boolean implementsToXMLable(SootClass cl) {
    return !cl.isInterface() && hierarchy.getImplementersOf(Scene.v().getSootClass("dk.brics.xact.ToXMLable")).contains(cl);
  }
 
  private String unescapeStringConstant(StringConstant sc) {
    String unesc = StringTools.getUnEscapedStringOf(sc.toString());
    return unesc.substring(1, unesc.length()-1);
  }
 
  public boolean hasConstantString(Value v) {
    if (v instanceof StringConstant)
      return true;
    if (v instanceof Local)
      return stringConstants.getFlowBefore(currentUnit).containsKey(v);
    if (v instanceof NullConstant)
      return true;
    return false;
  }

  /**
   * Returns the string constant value for the given Soot value or null if it is a null constant.
   * @throws XMLAnalysisException if the value does not appear to be a constant string
   */
  public String getConstantString(Value v) {
    if (v==null)
      throw new RuntimeException("null value");
    if (v instanceof StringConstant) {
      StringConstant sc = (StringConstant)v;
      return unescapeStringConstant(sc);
    } else if (v instanceof Local) {
      StringConstant sc = stringConstants.getFlowBefore(currentUnit).get(v);
      if (sc != null) {
        return unescapeStringConstant(sc);
      }
    } else if (v instanceof NullConstant) {
      return null;
    }
    if (System.getProperty("dk.brics.xact.analysis.ignore-non-constant-string") != null) {
      return "NONCONSTANT";
    }
    throw new XMLAnalysisException("Constant string expected", getCurrentOrigin());
  }
 
  /**
   * Returns the information known about the specified array variable, if any.
   * @param v any value (UNKNOWN is simply returned for non-array variables)
   * @return an instance of ArrayConstantInfo (note that its contents may be null)
   * @see ArrayConstantInfo
   * @see ArrayConstantAnalysis
   */
  public ArrayConstantInfo getConstantArray(Value v) {
    if (!(v instanceof Local))
      return ArrayConstantInfo.UNKNOWN;
    Local local = (Local)v;
    ArrayConstantInfo info = arrayConstants.getFlowBefore(currentUnit).get(local);
    if (info != null)
      return info;
    else {
      // technically this is BOTTOM, but it doesn't really happen in practice so
      // just return TOP so the caller doesn't have to bother with null return values
      return ArrayConstantInfo.UNKNOWN;
    }
  }
 
  /**
   * Returns the origin constant value for the given Soot value.
   * @throws XMLAnalysisException if the value does not appear to be a constant origin
   */
  public Origin getConstantOrigin(Value v) {
    //return getCurrentOrigin();
    return new Origin("???", 0, 0); // TODO: getConstantOrigin
  }
 
  public String getModifiedPackageNameFromClassConstant(Value v) {
    if (v instanceof ClassConstant) {
      String s = ((ClassConstant)v).getValue();
      int lastSlash = s.lastIndexOf('/');
      if (lastSlash==-1)
        return "";
      else
        return s.substring(0, lastSlash);
    } else {
      throw new XMLAnalysisException("Class constant expected", getCurrentOrigin());
    }
  }
 
  /**
   * Retrieves a resource string using the current class loader.
   * Assumes UTF-8.
   */
  public String getResourceString(String name) {
    InputStream in = TranslatorContext.class.getClassLoader().getResourceAsStream(name);
    if (in == null)
      throw new XMLAnalysisException("Resource not found: " + name, getCurrentOrigin());
    BufferedReader reader = null;
    try {
      StringBuilder sb = new StringBuilder(1000);
          reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
          char[] cb = new char[1024];
          int len=0;
          while((len = reader.read(cb)) != -1)
              sb.append(cb, 0, len);
      return sb.toString();
    } catch (IOException e) {
      throw new XMLAnalysisException(e, getCurrentOrigin());
    } finally {
      try {
        if (reader != null)
          reader.close();
      } catch (IOException e) {
        throw new XMLAnalysisException(e, getCurrentOrigin());
      }
    }
  }
 
  /**
   * Returns true if the first argument is a subtype of the class or interface named by the second argument.
   */
  public boolean isSubtypeOf(SootClass a, String b) {
      return isSubtypeOf(a, Scene.v().getSootClass(b));
    }
 
  /**
   * Returns true if the first argument is a class or interface that is a subtype of the
   * class or interface named by the second argument.
   */
  public boolean isSubtypeOf(Type a, String b) {
    if (a instanceof RefType)
      return isSubtypeOf(((RefType)a).getSootClass(), Scene.v().getSootClass(b));
    else
      return false;
    }
 
  /**
   * Returns true if the first argument is a subtype of the second argument.
   */
  public boolean isSubtypeOf(SootClass a, SootClass b) {
      if (a.equals(b))
        return true;
      if (b.getType().equals(RefType.v("java.lang.Object")))
        return true;
      if (a.isInterface()) {
        return b.isInterface() && getHierarchy().isInterfaceSubinterfaceOf(a, b);
      }
      if (b.isInterface()) {
        return getHierarchy().getImplementersOf(b).contains(a);
      }
      return getHierarchy().isClassSubclassOf(a, b);
    }
 
 
 
 
  /**
   * Expands a QName map according to the current namespace declarations.
   */
  public Map<String,String> expandQNames(Map<String,String> qnames) {
    if (qnames == null)
      return null;
    Map<String,String> expanded = new HashMap<String,String>();
    for (Map.Entry<String,String> me : qnames.entrySet())
      expanded.put(me.getKey(), expandQName(me.getValue()));
    return expanded;
  }

 
  /**
   * Returns an automaton representing the possible string values of the given Soot string expression.
   */
  /*public Automaton getAutomatonFromStringExp(ValueBox b) {
    if (!isStringType(b))
      throw new XMLValidationException("String expression expected " + b, getCurrentOrigin());
    return getStringAnalysis().getAutomaton(b);
  }*/
 
  public static boolean isStringType(ValueBox b) {
    return b.getValue().getType().toString().indexOf("java.lang.String") == 0; // matches (arrays of) String
  }
 
  public SchemaType parseSchemaType(String annotation, Origin origin) {
    if (annotation == null)
      return null;
   
    XMLAnalysisException ex = new XMLAnalysisException("Malformed @Type argument '" + annotation + "'", getCurrentOrigin());
    annotation = annotation.trim();
    // make schema
    SchemaType schema;
    int leftbrack = annotation.indexOf('[');
    int rightbrack = annotation.lastIndexOf(']');
    if (leftbrack<0 != rightbrack<0)
      throw ex;
    if (leftbrack<0 || rightbrack<0) {
      // no gap annotations
      schema = new SchemaType(expandQName(annotation), origin);
    } else {
      // parse gap annotations
      String start = annotation.substring(0, leftbrack).trim();
      String gaps = annotation.substring(leftbrack+1, rightbrack).trim();
      String[] ga = gaps.split(",");
      if (ga.length==0)
        ga = new String[]{ gaps };
      // build gap info
      Collection<String> tgaps = new LinkedHashSet<String>();
      Collection<String> agaps = new LinkedHashSet<String>();
      Map<String,String> gap_types = new LinkedHashMap<String,String>();
      for (String g : ga) {
        g = g.trim();
        int space = g.indexOf(' ');
        if (space<0)
          throw ex;
        String gaptype = g.substring(0, space).trim();
        String gapname = g.substring(space+1).trim();
        Collection<String> set;
        if (gapname.startsWith("@")) { // attribute gap?
          gapname = gapname.substring(1);
          set = agaps;
        } else
          set = tgaps;
        set.add(gapname);
        gap_types.put(gapname, gaptype);
      }
      schema = new SchemaType(expandQName(start), tgaps, agaps, expandQNames(gap_types), origin);
    }
    return schema;
  }
 
  /**
   * Returns list of all classes extending or implementing the specified class or interface.
   * @param clazz a class or interface
   * @return an unmodifiable list
   */
  public List<SootClass> getSubtypesOfIncluding(SootClass clazz) {
    if (clazz.isInterface()) {
      return getHierarchy().getImplementersOf(clazz);
    } else {
      return getHierarchy().getSubclassesOfIncluding(clazz);
    }
  }
 
  /**
   * Returns list of all classes extending or implementing the specified class or interface.
   * @param type a class or interface
   * @return an unmodifiable list
   */
  public List<SootClass> getSubtypesOfIncluding(RefType type) {
    return getSubtypesOfIncluding(type.getSootClass());
  }
}
TOP

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

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.