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