001// ***** This file is automatically generated from Numeric.java.jpp
002
003package daikon.inv.binary.twoString;
004
005import org.checkerframework.checker.lock.qual.GuardSatisfied;
006import org.checkerframework.checker.nullness.qual.NonNull;
007import org.checkerframework.checker.nullness.qual.Nullable;
008import org.checkerframework.checker.signature.qual.ClassGetName;
009import org.checkerframework.dataflow.qual.Pure;
010import org.checkerframework.dataflow.qual.SideEffectFree;
011import static daikon.inv.Invariant.asInvClass;
012
013import daikon.*;
014import daikon.Quantify.QuantFlags;
015import daikon.derive.binary.*;
016import daikon.inv.*;
017import daikon.inv.binary.twoScalar.*;
018import daikon.inv.binary.twoString.*;
019import daikon.inv.unary.scalar.*;
020import daikon.inv.unary.sequence.*;
021import daikon.suppress.*;
022import java.util.*;
023import org.plumelib.util.UtilPlume;
024import typequals.prototype.qual.NonPrototype;
025import typequals.prototype.qual.Prototype;
026
027/**
028 * Baseclass for binary numeric invariants.
029 *
030 * Each specific invariant is implemented in a subclass (typically, in this file). The subclass must
031 * provide the methods instantiate(), check(), and format(). Symmetric functions should define
032 * is_symmetric() to return true.
033 */
034public abstract class StdString extends TwoString {
035
036  // We are Serializable, so we specify a version to allow changes to
037  // method signatures without breaking serialization.  If you add or
038  // remove fields, you should change this number to the current date.
039  static final long serialVersionUID = 20060609L;
040
041  protected StdString(PptSlice ppt, boolean swap) {
042    super(ppt);
043    this.swap = swap;
044  }
045
046  protected StdString(boolean swap) {
047    super();
048    this.swap = swap;
049  }
050
051  /** Returns true if it is ok to instantiate a numeric invariant over the specified slice. */
052  @Override
053  public boolean instantiate_ok(VarInfo[] vis) {
054
055    ProglangType type1 = vis[0].file_rep_type;
056    ProglangType type2 = vis[1].file_rep_type;
057    if (!type1.isString() || !type2.isString()) {
058      return false;
059    }
060
061    return true;
062  }
063
064  @Pure
065  @Override
066  public boolean isExact() {
067    return true;
068  }
069
070  @Override
071  public String repr(@GuardSatisfied StdString this) {
072    return getClass().getSimpleName() + ": " + format()
073      + (swap ? " [swapped]" : " [unswapped]");
074  }
075
076  /**
077   * Returns a string in the specified format that describes the invariant.
078   *
079   * The generic format string is obtained from the subclass specific get_format_str(). Instances of
080   * %varN% are replaced by the variable name in the specified format.
081   */
082  @SideEffectFree
083  @Override
084  public String format_using(@GuardSatisfied StdString this, OutputFormat format) {
085
086    if (ppt == null) {
087      return String.format("proto ppt [class %s] format %s", getClass(),
088                           get_format_str(format));
089    }
090    String fmt_str = get_format_str(format);
091
092    String v1 = var1().name_using(format);
093    String v2 = var2().name_using(format);
094
095    // Note that we do not use String.replaceAll here, because that's
096    // inseparable from the regex library, and we don't want to have to
097    // escape v1 with something like
098    // v1.replaceAll("([\\$\\\\])", "\\\\$1")
099    fmt_str = fmt_str.replace("%var1%", v1);
100    fmt_str = fmt_str.replace("%var2%", v2);
101
102    // if (false && (format == OutputFormat.DAIKON)) {
103    //   fmt_str = "[" + getClass() + "]" + fmt_str + " ("
104    //          + var1().get_value_info() + ", " + var2().get_value_info() +  ")";
105    // }
106    return fmt_str;
107  }
108
109  /** Calls the function specific equal check and returns the correct status. */
110
111  @Override
112  public InvariantStatus check_modified(String x, String y, int count) {
113
114    try {
115      if (eq_check(x, y)) {
116        return InvariantStatus.NO_CHANGE;
117      } else {
118        return InvariantStatus.FALSIFIED;
119      }
120    } catch (Exception e) {
121      return InvariantStatus.FALSIFIED;
122    }
123  }
124
125  /**
126   * Checks to see if 'x[a] op y[b]' where 'x[] op y[]' and 'a == b'. Doesn't catch the case where
127   * a = b+1.
128   */
129  public @Nullable DiscardInfo is_subscript(VarInfo[] vis) {
130
131    VarInfo v1 = var1(vis);
132    VarInfo v2 = var2(vis);
133
134    // Make sure each var is a sequence subscript
135    if (!v1.isDerived() || !(v1.derived instanceof SequenceStringSubscript)) {
136      return null;
137    }
138    if (!v2.isDerived() || !(v2.derived instanceof SequenceStringSubscript)) {
139      return null;
140    }
141
142    @NonNull SequenceStringSubscript der1 = (SequenceStringSubscript) v1.derived;
143    @NonNull SequenceStringSubscript der2 = (SequenceStringSubscript) v2.derived;
144
145    // Make sure the shifts match
146    if (der1.index_shift != der2.index_shift) {
147      return null;
148    }
149
150    // Look for this invariant over a sequence
151    String cstr = getClass().getName();
152    cstr = cstr.replaceFirst("Numeric", "PairwiseNumeric");
153    cstr = cstr.replaceFirst("twoScalar", "twoSequence");
154    cstr = cstr.replaceFirst("twoFloat", "twoSequence");
155    Class<? extends Invariant> pairwise_class;
156    try {
157      @SuppressWarnings("signature") // string manipulation; application invariants
158      @ClassGetName String cstr_cgn = cstr;
159      pairwise_class = asInvClass(Class.forName(cstr_cgn));
160    } catch (Exception e) {
161      throw new Error("can't create class for " + cstr, e);
162    }
163    Invariant inv = find(pairwise_class, der1.seqvar(), der2.seqvar());
164    if (inv == null) {
165      return null;
166    }
167
168    // Look to see if the subscripts are equal
169    Invariant subinv = find(StringEqual.class, der1.sclvar(), der2.sclvar());
170    if (subinv == null) {
171      return null;
172    }
173
174    return new DiscardInfo(this, DiscardCode.obvious, "Implied by "
175                           + inv.format() + " and " + subinv.format());
176  }
177
178  @Pure
179  @Override
180  public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) {
181
182    DiscardInfo super_result = super.isObviousDynamically(vis);
183    if (super_result != null) {
184      return super_result;
185    }
186
187      // any relation across subscripts is made obvious by the same
188      // relation across the original sequence if the subscripts are equal
189      DiscardInfo result = is_subscript(vis);
190      if (result != null) {
191        return result;
192      }
193
194    // Check for invariant specific obvious checks.  The obvious_checks
195    // method returns an array of arrays of antecedents.  If all of the
196    // antecedents in an array are true, then the invariant is obvoius.
197    InvDef[][] obvious_arr = obvious_checks(vis);
198    obvious_loop:
199    for (int i = 0; i < obvious_arr.length; i++) {
200      InvDef[] antecedents = obvious_arr[i];
201      StringBuilder why = null;
202      for (int j = 0; j < antecedents.length; j++) {
203        Invariant inv = antecedents[j].find();
204        if (inv == null) {
205          continue obvious_loop;
206        }
207        if (why == null) {
208          why = new StringBuilder(inv.format());
209        } else {
210          why.append(" and ");
211          why.append(inv.format());
212        }
213      }
214      return new DiscardInfo(this, DiscardCode.obvious, "Implied by " + why);
215    }
216
217    return null;
218  }
219
220  /**
221   * Return a format string for the specified output format. Each instance of %varN% will be
222   * replaced by the correct name for varN.
223   */
224  public abstract String get_format_str(@GuardSatisfied StdString this, OutputFormat format);
225
226  /** Returns true if x and y don't invalidate the invariant. */
227  public abstract boolean eq_check(String x, String y);
228
229  /**
230   * Returns an array of arrays of antecedents. If all of the antecedents in any array are true,
231   * then the invariant is obvious.
232   */
233  public InvDef[][] obvious_checks(VarInfo[] vis) {
234    return new InvDef[][] {};
235  }
236
237  public static List<@Prototype Invariant> get_proto_all() {
238
239    List<@Prototype Invariant> result = new ArrayList<>();
240
241        result.add(SubString.get_proto(false));
242        result.add(SubString.get_proto(true));
243
244    // System.out.printf("%s get proto: %s%n", StdString.class, result);
245    return result;
246  }
247
248  // suppressor definitions, used by many of the classes below
249  protected static NISuppressor
250
251    var1_eq_var2    = new NISuppressor(0, 1, StringEqual.class),
252    var2_eq_var1    = new NISuppressor(0, 1, StringEqual.class);
253
254  //
255  // Int and Float Numeric Invariants
256  //
257
258//
259// Standard String invariants
260//
261
262  /**
263   * Represents the substring invariant between two String scalars.
264   * Prints as {@code x is a substring of y}.
265   */
266  public static class SubString extends StdString {
267    // We are Serializable, so we specify a version to allow changes to
268    // method signatures without breaking serialization.  If you add or
269    // remove fields, you should change this number to the current date.
270    static final long serialVersionUID = 20081113L;
271
272    protected SubString(PptSlice ppt, boolean swap) {
273      super(ppt, swap);
274    }
275
276    protected SubString(boolean swap) {
277      super(swap);
278    }
279
280    private static @Prototype SubString proto = new @Prototype SubString(false);
281    private static @Prototype SubString proto_swap = new @Prototype SubString(true);
282
283    /** Returns the prototype invariant. */
284    public static @Prototype SubString get_proto(boolean swap) {
285      if (swap) {
286        return proto_swap;
287      } else {
288        return proto;
289      }
290    }
291
292    // Variables starting with dkconfig_ should only be set via the
293    // daikon.config.Configuration interface.
294    /** Boolean. True iff SubString invariants should be considered. */
295    public static boolean dkconfig_enabled = false;
296
297    /** Returns whether or not this invariant is enabled. */
298    @Override
299    public boolean enabled() {
300      return dkconfig_enabled;
301    }
302
303    @Override
304    protected SubString instantiate_dyn(@Prototype SubString this, PptSlice slice) {
305      return new SubString(slice, swap);
306    }
307
308    @Override
309    public String get_format_str(@GuardSatisfied SubString this, OutputFormat format) {
310      if (format == OutputFormat.DAIKON) {
311        return "%var1% is a substring of %var2%";
312      } else if (format.isJavaFamily()) {
313        return "%var2%.contains(%var1%)";
314      } else if (format == OutputFormat.CSHARPCONTRACT) {
315
316          return "%var2%.Contains(%var1%)";
317      } else {
318        return format_unimplemented(format);
319      }
320    }
321
322    @Override
323    public boolean eq_check(String x, String y) {
324      return y.contains(x);
325    }
326
327    /** Justified as long as there are samples. */
328    @Override
329    protected double computeConfidence() {
330      if (ppt.num_samples() == 0) {
331        return Invariant.CONFIDENCE_UNJUSTIFIED;
332      }
333
334      return Invariant.CONFIDENCE_JUSTIFIED;
335    }
336
337    /** Returns a list of non-instantiating suppressions for this invariant. */
338    @Pure
339    @Override
340    public NISuppressionSet get_ni_suppressions() {
341      if (swap) {
342        return suppressions_swap;
343      } else {
344        return suppressions;
345      }
346    }
347
348    /** definition of this invariant (the suppressee) (unswapped) */
349    private static NISuppressee suppressee = new NISuppressee(SubString.class, false);
350
351    private static NISuppressionSet suppressions =
352      new NISuppressionSet(
353          new NISuppression[] {
354              // v1 == v2 ==> v1 subsequence v2
355              new NISuppression(var1_eq_var2, suppressee),
356          });
357    private static NISuppressionSet suppressions_swap = suppressions.swap();
358  }
359
360}