001// ***** This file is automatically generated from OneOf.java.jpp 002 003package daikon.inv.unary.stringsequence; 004 005import daikon.*; 006import daikon.inv.*; 007import daikon.inv.unary.OneOf; 008 009import java.io.*; 010import java.util.logging.Logger; 011import java.util.logging.Level; 012import java.util.*; 013 014 import java.util.regex.*; 015 016import org.checkerframework.checker.initialization.qual.Initialized; 017import org.checkerframework.checker.interning.qual.Interned; 018import org.checkerframework.checker.lock.qual.GuardSatisfied; 019import org.checkerframework.checker.nullness.qual.NonNull; 020import org.checkerframework.checker.nullness.qual.Nullable; 021import org.checkerframework.dataflow.qual.Pure; 022import org.checkerframework.dataflow.qual.SideEffectFree; 023import org.checkerframework.framework.qual.Unused; 024import org.plumelib.reflection.Signatures; 025import org.plumelib.util.ArraysPlume; 026import org.plumelib.util.Intern; 027import org.plumelib.util.StringsPlume; 028import org.plumelib.util.UtilPlume; 029import typequals.prototype.qual.NonPrototype; 030import typequals.prototype.qual.Prototype; 031 032// This subsumes an "exact" invariant that says the value is always exactly 033// a specific value. Do I want to make that a separate invariant 034// nonetheless? Probably not, as this will simplify implication and such. 035 036 /** 037 * Represents String[] variables that take on only a few distinct values. Prints as either 038 * {@code x == c} (when there is only one value) or as {@code x one of {c1, c2, c3}} 039 * (when there are multiple values). 040 041 */ 042 043@SuppressWarnings("UnnecessaryParentheses") // generated code, parentheses are sometimes needed 044public final class OneOfStringSequence extends SingleStringSequence implements OneOf { 045 // We are Serializable, so we specify a version to allow changes to 046 // method signatures without breaking serialization. If you add or 047 // remove fields, you should change this number to the current date. 048 static final long serialVersionUID = 20030822L; 049 050 /** Debugging logger. */ 051 public static final Logger debug = 052 Logger.getLogger(OneOfStringSequence.class.getName()); 053 054 // Variables starting with dkconfig_ should only be set via the 055 // daikon.config.Configuration interface. 056 /** Boolean. True iff OneOf invariants should be considered. */ 057 public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault; 058 059 /** 060 * Positive integer. Specifies the maximum set size for this type of invariant (x is one of 061 * {@code size} items). 062 */ 063 064 public static int dkconfig_size = 2; 065 066 // Probably needs to keep its own list of the values, and number of each seen. 067 // (That depends on the slice; maybe not until the slice is cleared out. 068 // But so few values is cheap, so this is quite fine for now and long-term.) 069 070 @Unused(when=Prototype.class) 071 private @Interned String[] @Interned [] elts; 072 @Unused(when=Prototype.class) 073 private int num_elts; 074 075 @Prototype OneOfStringSequence() { 076 super(); 077 } 078 079 OneOfStringSequence(PptSlice slice) { 080 super(slice); 081 082 // Elements are interned, so can test with == 083 // (in the general online case, it's not worth interning). 084 elts = new @Interned String [dkconfig_size] @Interned []; 085 086 num_elts = 0; 087 088 // var() is initialized by the super constructor 089 assert var().is_array() : 090 String.format("In %s constructor, var %s (type=%s, rep_type=%s) should be an array", 091 "OneOfStringSequence", var().name(), var().type, var().rep_type); 092 093 } 094 095 private static @Prototype OneOfStringSequence proto = new @Prototype OneOfStringSequence(); 096 097 /** Returns the prototype invariant for OneOfStringSequence */ 098 public static @Prototype OneOfStringSequence get_proto() { 099 return proto; 100 } 101 102 /** returns whether or not this invariant is enabled */ 103 @Override 104 public boolean enabled() { 105 return dkconfig_enabled; 106 } 107 108 /** instantiate an invariant on the specified slice */ 109 @Override 110 public OneOfStringSequence instantiate_dyn(@Prototype OneOfStringSequence this, PptSlice slice) { 111 return new OneOfStringSequence(slice); 112 } 113 114 @Pure 115 public boolean is_boolean(@GuardSatisfied OneOfStringSequence this) { 116 return var().file_rep_type.elementType() == ProglangType.BOOLEAN; 117 } 118 @Pure 119 public boolean is_hashcode(@GuardSatisfied OneOfStringSequence this) { 120 return var().file_rep_type.elementType() == ProglangType.HASHCODE; 121 } 122 123 @SideEffectFree 124 @Override 125 public OneOfStringSequence clone(@GuardSatisfied OneOfStringSequence this) { 126 OneOfStringSequence result = (OneOfStringSequence) super.clone(); 127 result.elts = elts.clone(); 128 129 for (int i = 0; i < num_elts; i++) { 130 result.elts[i] = Intern.intern(elts[i].clone()); 131 } 132 133 result.num_elts = this.num_elts; 134 return result; 135 } 136 137 @Override 138 public int num_elts() { 139 return num_elts; 140 } 141 142 @Override 143 public Object elt() { 144 return elt(0); 145 } 146 147 public Object elt(int index) { 148 if (num_elts <= index) { 149 throw new Error("Represents " + num_elts + " elements, index " + index + " not valid"); 150 } 151 152 return elts[index]; 153 } 154 155 static Comparator<String[]> comparator = new ArraysPlume.ComparableArrayComparatorLexical<String>(); // need to figure out proper generic type -MDE 156 157 private void sort_rep(@GuardSatisfied OneOfStringSequence this) { 158 Arrays.sort(elts, 0, num_elts , comparator); 159 } 160 161 public @Interned String @Interned [] min_elt() { 162 if (num_elts == 0) { 163 throw new Error("Represents no elements"); 164 } 165 sort_rep(); 166 return elts[0]; 167 } 168 169 public @Interned String @Interned [] max_elt() { 170 if (num_elts == 0) { 171 throw new Error("Represents no elements"); 172 } 173 sort_rep(); 174 return elts[num_elts - 1]; 175 } 176 177 // Assumes the other array is already sorted 178 public boolean compare_rep(int num_other_elts, @Interned String[] @Interned [] other_elts) { 179 if (num_elts != num_other_elts) { 180 return false; 181 } 182 sort_rep(); 183 for (int i = 0; i < num_elts; i++) { 184 if (!((elts[i]) == (other_elts[i]))) { // elements are interned 185 return false; 186 } 187 } 188 return true; 189 } 190 191 private String subarray_rep(@GuardSatisfied OneOfStringSequence this) { 192 // Not so efficient an implementation, but simple; 193 // and how often will we need to print this anyway? 194 sort_rep(); 195 StringBuilder sb = new StringBuilder(); 196 sb.append("{ "); 197 for (int i = 0; i < num_elts; i++) { 198 if (i != 0) { 199 sb.append(", "); 200 } 201 202 sb.append(Arrays.toString(elts[i])); 203 204 } 205 sb.append(" }"); 206 return sb.toString(); 207 } 208 209 @Override 210 public String repr(@GuardSatisfied OneOfStringSequence this) { 211 return "OneOfStringSequence" + varNames() + ": falsified=" + falsified 212 + ", num_elts=" + num_elts 213 + ", elts=" + subarray_rep(); 214 } 215 216 @SideEffectFree 217 @Override 218 public String format_using(@GuardSatisfied OneOfStringSequence this, OutputFormat format) { 219 sort_rep(); 220 221 if (format.isJavaFamily()) { 222 return format_java_family(format); 223 } 224 225 if (format == OutputFormat.DAIKON) { 226 return format_daikon(); 227 } else if (format == OutputFormat.SIMPLIFY) { 228 return format_simplify(); 229 } else if (format == OutputFormat.ESCJAVA) { 230 String result = format_esc(); 231 return result; 232 } else if (format == OutputFormat.CSHARPCONTRACT) { 233 return format_csharp_contract(); 234 } else { 235 return format_unimplemented(format); 236 } 237 } 238 239 public String format_daikon(@GuardSatisfied OneOfStringSequence this) { 240 String varname = var().name(); 241 if (num_elts == 1) { 242 243 return varname + " == " + Arrays.toString(elts[0]); 244 } else { 245 return varname + " one of " + subarray_rep(); 246 } 247 } 248 249 private static Pattern dollar_char_pat = Pattern.compile("\\$([A-Za-z])"); 250 251 private static String format_esc_string2type(String str) { 252 if ((str == null) || "null".equals(str)) { 253 return "\\typeof(null)"; 254 } 255 String type_str; 256 if (str.startsWith("[")) { 257 type_str = Signatures.fieldDescriptorToBinaryName(str); 258 } else { 259 type_str = str; 260 if (type_str.startsWith("\"") && type_str.endsWith("\"")) { 261 type_str = type_str.substring(1, type_str.length()-1); 262 } 263 } 264 265 // Inner classes 266 // type_str = type_str.replace('$', '.'); 267 // For named inner classes, convert "$" to ".". 268 // For anonymous inner classes, leave as "$". 269 Matcher m = dollar_char_pat.matcher(type_str); 270 type_str = m.replaceAll(".$1"); 271 272 return "\\type(" + type_str + ")"; 273 } 274 275 @Pure 276 @Override 277 public boolean isValidEscExpression() { 278 // format_esc will look at the particulars and decide 279 return true; 280 } 281 282 public String format_esc(@GuardSatisfied OneOfStringSequence this) { 283 sort_rep(); 284 285 String result; 286 287 // If the variable expression is a raw sequence, examine its 288 // element type(s). 289 if (var().is_typeof()) { 290 291 @SuppressWarnings("nullness") 292 @NonNull VarInfo sequence = var().get_enclosing_var(); 293 @SuppressWarnings("nullness") 294 @NonNull String varname = sequence.get_enclosing_var().esc_name(); 295 String type = null; 296 boolean consistent = true; 297 for (int i = 0; consistent && i < num_elts; i++) { 298 String[] elt = elts[i]; 299 for (int j = 0; consistent && j < elt.length; j++) { 300 String maybe = format_esc_string2type(elt[j]); 301 if (type == null) { 302 type = maybe; 303 } else { 304 consistent &= type.equals(maybe); 305 } 306 } 307 } 308 if (consistent && (type != null)) { 309 if (sequence.type.isArray()) { 310 return "\\elemtype(" + varname + ") == " + type; 311 } else { 312 return varname + ".elementType == " + type; 313 } 314 } 315 } 316 317 result = format_unimplemented(OutputFormat.ESCJAVA); // "needs to be implemented" 318 319 return result; 320 } 321 322public String format_csharp_contract(@GuardSatisfied OneOfStringSequence this) { 323 324 @NonNull @Initialized String result; 325 326 result = "(\"oneOf.java.jpp: SEQUENCE unimplemented\" != null)"; // "interned" 327 328 return result; 329 } 330 331 public String format_java_family(@GuardSatisfied OneOfStringSequence this, OutputFormat format) { 332 333 String result; 334 335 // Setting up the name of the unary variable 336 String varname = var().name_using(format); 337 338 result = ""; 339 for (int i = 0; i < num_elts; i++) { 340 if (i != 0) { result += " || "; } 341 342 String seq = "new String[] { "; 343 344 for (int j = 0 ; j < elts[i].length ; j++) { 345 if (j != 0) { seq += ", "; } 346 seq = seq + ((elts[i][j] == null) ? "null" : "\"" + StringsPlume.escapeNonASCII(elts[i][j]) + "\""); 347 } 348 seq += " }"; 349 350 result += "daikon.Quant.pairwiseEqual(" + varname + ", " + seq + ")"; 351 } 352 353 return result; 354 } 355 356 public String format_simplify(@GuardSatisfied OneOfStringSequence this) { 357 358 sort_rep(); 359 360 String result; 361 362 StringBuilder resultBuf = new StringBuilder(); 363 for (int i = 0; i < num_elts; i++) { 364 @Interned String @Interned [] seq = elts[i]; 365 String offset = null; 366 String contents = null; 367 String[] bounds_name; 368 String length = var().get_simplify_size_name(); 369 // if ((length == null) && var().name.isApplySizeSafe()) 370 // System.out.printf("var %s, type %s, is_array %b%n", var().name(), 371 // var().type, var().type.isArray()); 372 if (length != null) { 373 length = "(EQ " + length + " "+ simplify_format_long(seq.length) + ")"; 374 } else if ((bounds_name = var().get_simplify_slice_bounds()) != null) { 375 String size = "(+ 1 (- " + bounds_name[1] +" " + bounds_name[0] + "))"; 376 length = "(EQ " + size + " " + simplify_format_long(seq.length) + ")"; 377 offset = bounds_name[0]; 378 } 379 380 { 381 StringBuilder contentsBuf = new StringBuilder(); 382 for (int j = 0; j < seq.length; j++) { 383 if (j + 3 < seq.length 384 && ((seq[j]) == ( seq[j + 1])) 385 && ((seq[j]) == ( seq[j + 2])) 386 && ((seq[j]) == ( seq[j + 3]))) { 387 // Compress a sequence of adjacent values 388 int k = j + 4; 389 for (; k < seq.length; k++) { 390 if (!((seq[j]) == ( seq[k]))) { 391 break; 392 } 393 } 394 k--; 395 String index_name = VarInfo.get_simplify_free_index(var()); 396 String cond_left, cond_right; 397 if (offset == null) { 398 cond_left = "(<= " + j + " " + index_name + ")"; 399 cond_right = "(<= " + index_name + " " + k + ")"; 400 } else { 401 cond_left = "(<= (+ " + offset + " " + j + ") " 402 + index_name + ")"; 403 cond_right = "(>= (+ " + offset + " " + k + ") " 404 + index_name + ")"; 405 } 406 String cond = "(AND " + cond_left + " " + cond_right + ")"; 407 String nth = var().get_simplify_selectNth(index_name, true, 0); 408 String eq = "(EQ " + nth + " " + simplify_format_string(seq[j]) + ")"; 409 String implies = "(IMPLIES " + cond + " " + eq + ")"; 410 String forall = "(FORALL (" + index_name + ") " + implies + ")"; 411 contentsBuf.append(" " + forall); 412 j = k; 413 } else { 414 // Output a single value 415 String nth = var().get_simplify_selectNth_lower(j); 416 if (nth == null) { 417 String classname = this.getClass().toString().substring(6); 418 result = "warning: method " + classname 419 + ".format_simplify() needs to fix selectNth(): " + format(); 420 return result; 421 } 422 String value = simplify_format_string(seq[j]); 423 contentsBuf.append(" (EQ " + nth + " " + value + ")"); 424 // if (nth.contains ("--orig__a")) 425 // System.out.printf("regular orig__a%n"); 426 427 } 428 } 429 if (seq.length > 1) { 430 contents = "(AND " + contentsBuf.toString() + ")"; 431 } else if (seq.length == 1) { 432 contents = contentsBuf.toString().substring(1); 433 } else if (seq.length == 0) { 434 contents = null; // back from "" 435 } 436 } 437 if (length == null && contents == null) { 438 resultBuf.append(" "); 439 } else if (length == null && contents != null) { 440 resultBuf.append(" " + contents); 441 } else if (length != null && contents == null) { 442 resultBuf.append(" " + length); 443 } else { 444 assert length != null && contents != null; 445 resultBuf.append(" (AND " + length + " " + contents + ")"); 446 } 447 448 } 449 if (num_elts > 1) { 450 result = "(OR" + resultBuf.toString() + ")"; 451 } else if (num_elts == 1) { 452 // chop leading space 453 result = resultBuf.toString().substring(1); 454 } else if (num_elts == 0) { 455 return format_too_few_samples(OutputFormat.SIMPLIFY, null); 456 } else { 457 throw new Error("this can't happen"); 458 // result = null; 459 } 460 if (result.trim().equals("")) { 461 result = "format_simplify() failed on a weird OneOf"; 462 } 463 464 if (result.indexOf("format_simplify") == -1) { 465 daikon.simplify.SimpUtil.assert_well_formed(result); 466 } 467 return result; 468 } 469 470 @Override 471 public InvariantStatus add_modified(@Interned String @Interned [] a, int count) { 472 return runValue(a, count, true); 473 } 474 475 @Override 476 public InvariantStatus check_modified(@Interned String @Interned [] a, int count) { 477 return runValue(a, count, false); 478 } 479 480 private InvariantStatus runValue(@Interned String @Interned [] v, int count, boolean mutate) { 481 InvariantStatus status; 482 if (mutate) { 483 status = add_mod_elem(v, count); 484 } else { 485 status = check_mod_elem(v, count); 486 } 487 if (status == InvariantStatus.FALSIFIED) { 488 if (logOn() && mutate) { 489 StringBuilder eltString = new StringBuilder(); 490 for (int i = 0; i < num_elts; i++) { 491 eltString.append(Arrays.toString(elts[i]) + " "); 492 } 493 log("destroyed on sample %s previous vals = {%s} num_elts = %s", 494 Arrays.toString(v), eltString, num_elts); 495 } 496 return InvariantStatus.FALSIFIED; 497 } 498 return status; 499 } 500 501 /** 502 * Adds a single sample to the invariant. Returns 503 * the appropriate InvariantStatus from the result 504 * of adding the sample to this. 505 */ 506 public InvariantStatus add_mod_elem(@Interned String @Interned [] v, int count) { 507 InvariantStatus status = check_mod_elem(v, count); 508 if (status == InvariantStatus.WEAKENED) { 509 elts[num_elts] = v; 510 num_elts++; 511 } 512 return status; 513 } 514 515 /** 516 * Checks a single sample to the invariant. Returns 517 * the appropriate InvariantStatus from the result 518 * of adding the sample to this. 519 */ 520 public InvariantStatus check_mod_elem(@Interned String @Interned [] v, int count) { 521 522 // Look for v in our list of previously seen values. If it's 523 // found, we're all set. 524 for (int i = 0; i < num_elts; i++) { 525 // if (logDetail()) 526 // log ("add_modified (" + v + ")"); 527 if (((elts[i]) == ( v))) { 528 return InvariantStatus.NO_CHANGE; 529 } 530 } 531 532 if (num_elts == dkconfig_size) { 533 return InvariantStatus.FALSIFIED; 534 } 535 536 return InvariantStatus.WEAKENED; 537 } 538 539 @Override 540 protected double computeConfidence() { 541 // This is not ideal. 542 if (num_elts == 0) { 543 return Invariant.CONFIDENCE_UNJUSTIFIED; 544 } else { 545 return Invariant.CONFIDENCE_JUSTIFIED; 546 } 547 } 548 549 @Pure 550 @Override 551 public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) { 552 // Static constants are necessarily OneOf precisely one value. 553 // This removes static constants from the output, which might not be 554 // desirable if the user doesn't know their actual value. 555 if (vis[0].isStaticConstant()) { 556 assert num_elts <= 1; 557 return new DiscardInfo(this, DiscardCode.obvious, vis[0].name() + " is a static constant."); 558 } 559 return super.isObviousStatically(vis); 560 } 561 562 /** {@inheritDoc} */ 563 @Override 564 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 565 DiscardInfo super_result = super.isObviousDynamically(vis); 566 if (super_result != null) { 567 return super_result; 568 } 569 570 VarInfo v = vis[0]; 571 572 // We can check if all values in the element sequence match 573 // with the ones we know about (useful for booleans and numeric 574 // enumerations). 575 if (v.aux.hasValue(VarInfoAux.VALID_VALUES) 576 && v.aux.hasValue(VarInfoAux.MAXIMUM_LENGTH) 577 && v.aux.hasValue(VarInfoAux.MINIMUM_LENGTH) 578 && v.aux.getInt(VarInfoAux.MAXIMUM_LENGTH) == 1 579 && v.aux.getInt(VarInfoAux.MINIMUM_LENGTH) == 1) { 580 581 String[] vsValidValues = v.aux.getList(VarInfoAux.VALID_VALUES); 582 Set<String> setValidValues = new TreeSet<>(); 583 for (String s : vsValidValues) { 584 setValidValues.add((s)); 585 } 586 Set<String> setValuesInvariant = new TreeSet<>(); 587 for (@Interned String @Interned [] e : elts) { 588 if (e == null) { 589 continue; 590} 591 for (String b : e) { 592 setValuesInvariant.add(b); 593 } 594 } 595 if (setValidValues.equals(setValuesInvariant)) { 596 return new DiscardInfo(this, DiscardCode.obvious, 597 "The value list matches the allowed value list"); 598 } 599 } 600 601 return null; 602 } 603 604 /** 605 * Oneof can merge different formulas from lower points to create a single formula at an upper 606 * point. 607 */ 608 @Override 609 public boolean mergeFormulasOk() { 610 return true; 611 } 612 613 @Pure 614 @Override 615 public boolean isSameFormula(Invariant o) { 616 OneOfStringSequence other = (OneOfStringSequence) o; 617 if (num_elts != other.num_elts) { 618 return false; 619 } 620 if (num_elts == 0 && other.num_elts == 0) { 621 return true; 622 } 623 624 sort_rep(); 625 other.sort_rep(); 626 627 for (int i = 0; i < num_elts; i++) { 628 if (!((elts[i]) == (other.elts[i]))) { 629 return false; 630 } 631 } 632 633 return true; 634 } 635 636 @Pure 637 @Override 638 public boolean isExclusiveFormula(Invariant o) { 639 if (o instanceof OneOfStringSequence) { 640 OneOfStringSequence other = (OneOfStringSequence) o; 641 642 if (num_elts == 0 || other.num_elts == 0) { 643 return false; 644 } 645 for (int i = 0; i < num_elts; i++) { 646 for (int j = 0; j < other.num_elts; j++) { 647 if (((elts[i]) == (other.elts[j]))) // elements are interned 648 return false; 649 } 650 } 651 652 return true; 653 } 654 655 return false; 656 } 657 658 @Override 659 public boolean hasUninterestingConstant() { 660 661 return false; 662 } 663 664 @Pure 665 @Override 666 public boolean isExact() { 667 return num_elts == 1; 668 } 669 670 // Look up a previously instantiated invariant. 671 public static @Nullable OneOfStringSequence find(PptSlice ppt) { 672 assert ppt.arity() == 1; 673 for (Invariant inv : ppt.invs) { 674 if (inv instanceof OneOfStringSequence) { 675 return (OneOfStringSequence) inv; 676 } 677 } 678 return null; 679 } 680 681 // Interning is lost when an object is serialized and deserialized. 682 // Manually re-intern any interned fields upon deserialization. 683 private void readObject(ObjectInputStream in) throws IOException, 684 ClassNotFoundException { 685 in.defaultReadObject(); 686 687 for (int i = 0; i < num_elts; i++) { 688 for (int j = 0; j < elts[i].length; j++) { 689 elts[i][j] = Intern.intern(elts[i][j]); 690 } 691 } 692 693 for (int i = 0; i < num_elts; i++) { 694 elts[i] = Intern.intern(elts[i]); 695 } 696 } 697 698 /** 699 * Merge the invariants in invs to form a new invariant. Each must be a OneOfStringSequence invariant. 700 * This code finds all of the oneof values from each of the invariants and returns the merged 701 * invariant (if any). 702 * 703 * @param invs list of invariants to merge. The invariants must all be of the same type and should 704 * come from the children of parent_ppt. They should also all be permuted to match the 705 * variable order in parent_ppt. 706 * @param parent_ppt slice that will contain the new invariant 707 */ 708 @Override 709 public @Nullable Invariant merge(List<Invariant> invs, PptSlice parent_ppt) { 710 711 // Create the initial parent invariant from the first child 712 OneOfStringSequence first = (OneOfStringSequence) invs.get(0); 713 OneOfStringSequence result = first.clone(); 714 result.ppt = parent_ppt; 715 716 for (int i = 0; i < result.num_elts; i++) { 717 result.elts[i] = Intern.intern(result.elts[i]); 718 } 719 720 // Loop through the rest of the child invariants 721 for (int i = 1; i < invs.size(); i++ ) { 722 723 // Get this invariant 724 OneOfStringSequence inv = (OneOfStringSequence) invs.get(i); 725 726 // Loop through each distinct value found in this child and add 727 // it to the parent. If the invariant is falsified, there is no parent 728 // invariant 729 for (int j = 0; j < inv.num_elts; j++) { 730 @Interned String @Interned [] val = inv.elts[j]; 731 732 val = Intern.intern(val); 733 734 InvariantStatus status = result.add_mod_elem(val, 1); 735 if (status == InvariantStatus.FALSIFIED) { 736 737 result.log("%s", "child value '" + Arrays.toString(val) + "' destroyed oneof"); 738 739 return null; 740 } 741 } 742 } 743 744 result.log("Merged '%s' from %s child invariants", result.format(), invs.size()); 745 return result; 746 } 747 748 /** 749 * Setup the invariant with the specified elements. Normally used when searching for a specified 750 * OneOf. The elements of vals are not necessarily interned; this method interns each element. 751 */ 752 public void set_one_of_val(@Interned String[][] vals) { 753 754 num_elts = vals.length; 755 for (int i = 0; i < num_elts; i++) { 756 elts[i] = Intern.intern(vals[i]); 757 } 758 } 759 760 /** 761 * Returns true if every element in this invariant is contained in the specified state. For 762 * example if x = 1 and the state contains 1 and 2, true will be returned. 763 */ 764 @Override 765 public boolean state_match(Object state) { 766 767 if (num_elts == 0) { 768 return false; 769 } 770 771 if (!(state instanceof @Interned String[] @Interned [])) { 772 // Daikon is about to crash. Produce some debugging output. 773 System.out.printf("state = %s [%s]%n", state, state.getClass()); 774 System.out.printf("problem with %s%n", this); 775 } 776 @Interned String[] @Interned [] e = (@Interned String[] @Interned []) state; 777 for (int i = 0; i < num_elts; i++) { 778 boolean match = false; 779 for (int j = 0; j < e.length; j++) { 780 if (elts[i] == e[j]) { 781 match = true; 782 break; 783 } 784 } 785 if (!match) { 786 return false; 787 } 788 } 789 return true; 790 } 791 792}