001// "Ppt" stands for "Program point" (but is easier to type).
002
003package daikon;
004
005import daikon.inv.Invariant; // for emptyInvList
006import java.io.Serializable;
007import java.util.ArrayList;
008import java.util.Comparator;
009import java.util.List;
010import java.util.StringJoiner;
011import org.checkerframework.checker.initialization.qual.UnknownInitialization;
012import org.checkerframework.checker.interning.qual.UsesObjectEquals;
013import org.checkerframework.checker.lock.qual.GuardSatisfied;
014import org.checkerframework.checker.nullness.qual.Nullable;
015import org.checkerframework.dataflow.qual.Pure;
016import org.checkerframework.dataflow.qual.SideEffectFree;
017
018// Types of Ppt (program point) objects:
019//  Ppt:  abstract base class
020//  PptTopLevel:  pointed to by top-level PptMap object.  Contains all variables
021//    and all data for those variables.
022//  PptConditional:  contains only value tuples satisfying some condition.
023//    Probably doesn't make sense for parent to be a PptSlice.
024//  PptSlice:  contains a subset of variables.  Probably doesn't contain its
025//    own data structure with all the values, but depends on its parent
026//    (which may be any type of Ppt except a PptSlice, which wouldn't
027//    make good sense).
028// Originally, both PptConditional and PptSlice were called "Views"; but
029// presently (6/2002), only Slices are called Views.
030
031// Ppt is an abstract base class rather than an interface in part because
032// interfaces cannot declare member variables.  I suspect that using
033// members directly will be more efficient than calling accessor
034// functions such as num_vars() and var_info_iterator().
035
036// The common interface for all Ppt objects.
037@UsesObjectEquals
038public abstract class Ppt implements Serializable {
039  static final long serialVersionUID = 20040914L;
040
041  // Not final:  modified by PptTopLevel.addVarInfos (which is called by
042  // Daikon.create_orig_vars and PptTopLevel.create_derived_variables)
043  // and also by PptSlice0.makeFakePrestate.
044  public VarInfo[] var_infos;
045
046  protected Ppt(VarInfo[] var_infos) {
047    this.var_infos = var_infos;
048  }
049
050  // The "name" and "ppt_name" fields were moved to PptTopLevel:  they take
051  // up too much space in PptSlice objects.
052  // This is safe if the receiver is @UnknownInitialization(PptTopLevel.class) OR
053  // @UnknownInitialization(PptSlice.class), but annotations cannot express that.
054  public abstract String name(@GuardSatisfied @UnknownInitialization(PptTopLevel.class) Ppt this);
055
056  /** Trim the collections used in this Ppt. */
057  public void trimToSize() {
058    for (VarInfo vi : var_infos) {
059      vi.trimToSize();
060    }
061  }
062
063  protected static final List<Invariant> emptyInvList = new ArrayList<>();
064
065  /** Returns a string rep of the specified variable names. */
066  @SuppressWarnings("all:purity") // Impure side effects do not escape (string creation)
067  @SideEffectFree
068  public static String varNames(VarInfo[] infos) {
069    StringJoiner sj = new StringJoiner(", ", "(", ")");
070    if (infos.length == 0) {
071      sj.add("<implication slice>");
072    } else {
073      for (VarInfo vi : infos) {
074        sj.add(vi.name());
075      }
076    }
077    return sj.toString();
078  }
079
080  /** Return a string representation of the variable names. */
081  @SideEffectFree
082  public String varNames(@GuardSatisfied @UnknownInitialization(Ppt.class) Ppt this) {
083    return varNames(var_infos);
084  }
085
086  /**
087   * Returns the varinfo_index of the variable whose name is varname. Returns -1 if there is no such
088   * variable.
089   */
090  @Pure
091  public int indexOf(@UnknownInitialization(Ppt.class) Ppt this, String varname) {
092    for (int i = 0; i < var_infos.length; i++) {
093      if (var_infos[i].name().equals(varname)) {
094        return i;
095      }
096    }
097    return -1;
098  }
099
100  /** Returns the VarInfo with the specified name. Null if the name is not found. */
101  @Pure
102  public @Nullable VarInfo find_var_by_name(
103      @UnknownInitialization(Ppt.class) Ppt this, String varname) {
104    // System.out.printf("Ppt.find_var_by_name(%s): %s%n", varname, this);
105    int i = indexOf(varname);
106    if (i == -1) {
107      if (varname.contains("[]")) {
108        return find_var_by_name(varname.replace("[]", "[..]"));
109      }
110      // System.out.printf("Ppt.find_var_by_name: Didn't find %s or %s in %s%n", varname,
111      // varname.replace ("[]", "[..]"), this);
112      return null;
113    } else {
114      return var_infos[i];
115    }
116  }
117
118  public boolean containsVar(VarInfo vi) {
119    // There's gotta be a faster way of doing this.  I don't want to
120    // use a HashSet for var_infos because various things clobber
121    // this.var_infos.
122    for (VarInfo elt : var_infos) {
123      if (elt == vi) {
124        return true;
125      }
126    }
127    return false;
128  }
129
130  // It might make more sense to put the sorting into
131  // PptMap.sortedIterator(), for example, but it's in here for now
132
133  // Check if o1 and o2 are both main exits (combined or only exits)
134  // If so, compare their name without the EXIT[line]
135  // If the name is the same, return 0, otherwise
136  // Orders ppts by the name, except . and : are swapped
137  //   so that Foo:::OBJECT and Foo:::CLASS are processed before Foo.method.
138  public static final class NameComparator implements Comparator<PptTopLevel> {
139    @Pure
140    @Override
141    public int compare(PptTopLevel p1, PptTopLevel p2) {
142      if (p1 == p2) {
143        return 0;
144      }
145
146      String name1 = p1.name();
147      String name2 = p2.name();
148
149      String swapped1 = swap(name1, '.', ':');
150      String swapped2 = swap(name2, '.', ':');
151
152      return swapped1.compareTo(swapped2);
153    }
154
155    static String swap(String s, char a, char b) {
156      final char magic = '\255';
157      return s.replace(a, magic).replace(b, a).replace(magic, b);
158    }
159  }
160}