All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.RefType Maven / Gradle / Ivy

package soot;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 1997 - 1999 Raja Vallee-Rai
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.util.ArrayDeque;

import soot.util.Switch;

/**
 * A class that models Java's reference types. RefTypes are parametrized by a class name. Two RefType are equal iff they are
 * parametrized by the same class name as a String.
 */

@SuppressWarnings("serial")
public class RefType extends RefLikeType implements Comparable {
  public RefType(Singletons.Global g) {
    className = "";
  }

  public static RefType v() {
    return G.v().soot_RefType();
  }

  /** the class name that parameterizes this RefType */
  private String className;

  public String getClassName() {
    return className;
  }

  private volatile SootClass sootClass;
  private AnySubType anySubType;

  private RefType(String className) {
    if (className.startsWith("[")) {
      throw new RuntimeException("Attempt to create RefType whose name starts with [ --> " + className);
    }
    if (className.indexOf("/") >= 0) {
      throw new RuntimeException("Attempt to create RefType containing a / --> " + className);
    }
    if (className.indexOf(";") >= 0) {
      throw new RuntimeException("Attempt to create RefType containing a ; --> " + className);
    }
    this.className = className;
  }

  /**
   * Create a RefType for a class.
   *
   * @param className
   *          The name of the class used to parametrize the created RefType.
   * @return a RefType for the given class name.
   */
  public static RefType v(String className) {
    RefType rt = Scene.v().getRefTypeUnsafe(className);
    if (rt == null) {
      rt = new RefType(className);
      return Scene.v().getOrAddRefType(rt);
    }
    return rt;
  }

  public int compareTo(RefType t) {
    return this.toString().compareTo(t.toString());
  }

  /**
   * Create a RefType for a class.
   *
   * @param c
   *          A SootClass for which to create a RefType.
   * @return a RefType for the given SootClass..
   */
  public static RefType v(SootClass c) {
    return v(c.getName());
  }

  /**
   * Get the SootClass object corresponding to this RefType.
   *
   * @return the corresponding SootClass
   */
  public SootClass getSootClass() {
    if (sootClass == null) {
      // System.out.println( "wrning: "+this+" has no sootclass" );
      sootClass = SootResolver.v().makeClassRef(className);
    }
    return sootClass;
  }

  public boolean hasSootClass() {
    return sootClass != null;
  }

  public void setClassName(String className) {
    this.className = className;
  }

  /**
   * Set the SootClass object corresponding to this RefType.
   *
   * @param sootClass
   *          The SootClass corresponding to this RefType.
   */
  public void setSootClass(SootClass sootClass) {
    this.sootClass = sootClass;
  }

  /**
   * 2 RefTypes are considered equal if they are parametrized by the same class name String.
   *
   * @param t
   *          an object to test for equality. @ return true if t is a RefType parametrized by the same name as this.
   */
  public boolean equals(Object t) {
    return ((t instanceof RefType) && className.equals(((RefType) t).className));
  }

  public String toString() {
    return className;
  }

  /**
   * Returns a textual representation, quoted as needed, of this type for serialization, e.g. to .jimple format
   */
  @Override
  public String toQuotedString() {
    return Scene.v().quotedNameOf(className);
  }

  public int hashCode() {
    return className.hashCode();
  }

  public void apply(Switch sw) {
    ((TypeSwitch) sw).caseRefType(this);
  }

  /** Returns the least common superclass of this type and other. */
  public Type merge(Type other, Scene cm) {
    if (other.equals(UnknownType.v()) || this.equals(other)) {
      return this;
    }

    if (!(other instanceof RefType)) {
      throw new RuntimeException("illegal type merge: " + this + " and " + other);
    }

    {
      // Return least common superclass

      SootClass thisClass = cm.getSootClass(this.className);
      SootClass otherClass = cm.getSootClass(((RefType) other).className);
      SootClass javalangObject = cm.getObjectType().getSootClass();

      ArrayDeque thisHierarchy = new ArrayDeque<>();
      ArrayDeque otherHierarchy = new ArrayDeque<>();

      // Build thisHierarchy
      {
        SootClass sootClass = thisClass;

        // This should never be null, so we could also use "while
        // (true)"; but better be safe than sorry.
        while (sootClass != null) {
          thisHierarchy.addFirst(sootClass);
          if (sootClass == javalangObject) {
            break;
          }

          sootClass = sootClass.getSuperclassUnsafe();
          if (sootClass == null) {
            sootClass = javalangObject;
          }
        }
      }

      // Build otherHierarchy
      {
        SootClass sootClass = otherClass;

        // This should never be null, so we could also use "while
        // (true)"; but better be safe than sorry.
        while (sootClass != null) {
          otherHierarchy.addFirst(sootClass);
          if (sootClass == javalangObject) {
            break;
          }

          sootClass = sootClass.getSuperclassUnsafe();
          if (sootClass == null) {
            sootClass = javalangObject;
          }
        }
      }

      // Find least common superclass
      {
        SootClass commonClass = null;

        while (!otherHierarchy.isEmpty() && !thisHierarchy.isEmpty()
            && otherHierarchy.getFirst() == thisHierarchy.getFirst()) {
          commonClass = otherHierarchy.removeFirst();
          thisHierarchy.removeFirst();
        }

        if (commonClass == null) {
          throw new RuntimeException("Could not find a common superclass for " + this + " and " + other);
        }

        return commonClass.getType();
      }
    }

  }

  public Type getArrayElementType() {
    if (className.equals("java.lang.Object") || className.equals("java.io.Serializable")
        || className.equals("java.lang.Cloneable")) {
      return RefType.v("java.lang.Object");
    }
    throw new RuntimeException("Attempt to get array base type of a non-array");
  }

  public AnySubType getAnySubType() {
    return anySubType;
  }

  public void setAnySubType(AnySubType anySubType) {
    this.anySubType = anySubType;
  }

  public boolean isAllowedInFinalCode() {
    return true;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy