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