001package daikon.inv; 002 003import static daikon.tools.nullness.NullnessUtil.castNonNullDeep; 004 005import daikon.Daikon; 006import daikon.Debug; 007import daikon.FileIO; 008import daikon.PptSlice; 009import daikon.PptSlice1; 010import daikon.PptSlice2; 011import daikon.PrintInvariants; 012import daikon.ValueTuple; 013import daikon.VarComparability; 014import daikon.VarComparabilityImplicit; 015import daikon.VarInfo; 016import daikon.inv.binary.BinaryInvariant; 017import daikon.inv.filter.InvariantFilters; 018import daikon.inv.ternary.TernaryInvariant; 019import daikon.inv.unary.OneOf; 020import daikon.inv.unary.UnaryInvariant; 021import daikon.simplify.LemmaStack; 022import daikon.simplify.SimpUtil; 023import daikon.suppress.NISuppressionSet; 024import java.io.Serializable; 025import java.lang.reflect.Field; 026import java.lang.reflect.Method; 027import java.lang.reflect.Modifier; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.Comparator; 031import java.util.IdentityHashMap; 032import java.util.List; 033import java.util.StringJoiner; 034import java.util.logging.Level; 035import java.util.logging.Logger; 036import java.util.regex.Pattern; 037import org.checkerframework.checker.formatter.qual.FormatMethod; 038import org.checkerframework.checker.initialization.qual.UnderInitialization; 039import org.checkerframework.checker.initialization.qual.UnknownInitialization; 040import org.checkerframework.checker.interning.qual.UsesObjectEquals; 041import org.checkerframework.checker.lock.qual.GuardSatisfied; 042import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; 043import org.checkerframework.checker.nullness.qual.Nullable; 044import org.checkerframework.dataflow.qual.Pure; 045import org.checkerframework.dataflow.qual.SideEffectFree; 046import org.checkerframework.framework.qual.Unused; 047import org.plumelib.util.ArraysPlume; 048import org.plumelib.util.CollectionsPlume; 049import org.plumelib.util.MathPlume; 050import typequals.prototype.qual.NonPrototype; 051import typequals.prototype.qual.Prototype; 052 053/** 054 * Base implementation for Invariant objects. Intended to be subclassed but not to be directly 055 * instantiated. Rules/assumptions for invariants: 056 * 057 * <p>For each program point's set of VarInfos, there exists no more than one invariant of its type. 058 * For example, between variables a and b at PptTopLevel T, there will not be two instances of 059 * invariant I(a, b). 060 */ 061@UsesObjectEquals 062@Prototype 063public abstract class Invariant implements Serializable, Cloneable // but don't YOU clone it 064{ 065 static final long serialVersionUID = 20040921L; 066 067 /** General debug tracer. */ 068 public static final Logger debug = Logger.getLogger("daikon.inv.Invariant"); 069 070 /** Debug tracer for printing invariants. */ 071 public static final Logger debugPrint = Logger.getLogger("daikon.print"); 072 073 /** Debug tracer for invariant flow. */ 074 public static final Logger debugFlow = Logger.getLogger("daikon.flow.flow"); 075 076 /** Debug tracer for printing equality invariants. */ 077 public static final Logger debugPrintEquality = Logger.getLogger("daikon.print.equality"); 078 079 /** Debug tracer for isWorthPrinting() checks. */ 080 public static final Logger debugIsWorthPrinting = 081 Logger.getLogger("daikon.print.isWorthPrinting"); 082 083 /** Debug tracer for guarding. */ 084 public static final Logger debugGuarding = Logger.getLogger("daikon.guard"); 085 086 /** Debug tracer for isObvious checks. */ 087 public static final Logger debugIsObvious = Logger.getLogger("daikon.inv.Invariant.isObvious"); 088 089 /** 090 * Floating-point number between 0 and 1. Invariants are displayed only if the confidence that the 091 * invariant did not occur by chance is greater than this. (May also be set via the {@code 092 * --conf_limit} command-line option to Daikon; refer to manual.) 093 */ 094 public static double dkconfig_confidence_limit = .99; 095 096 /** 097 * A boolean value. If true, Daikon's Simplify output (printed when the {@code --format simplify} 098 * flag is enabled, and used internally by {@code --suppress_redundant}) will include new 099 * predicates representing some complex relationships in invariants, such as lexical ordering 100 * among sequences. If false, some complex relationships will appear in the output as complex 101 * quantified formulas, while others will not appear at all. When enabled, Simplify may be able to 102 * make more inferences, allowing {@code --suppress_redundant} to suppress more redundant 103 * invariants, but Simplify may also run more slowly. 104 */ 105 public static boolean dkconfig_simplify_define_predicates = false; 106 107 /** 108 * Floating-point number between 0 and 0.1, representing the maximum relative difference between 109 * two floats for fuzzy comparisons. Larger values will result in floats that are relatively 110 * farther apart being treated as equal. A value of 0 essentially disables fuzzy comparisons. 111 * Specifically, if {@code abs(1 - f1/f2)} is less than or equal to this value, then the two 112 * doubles ({@code f1} and {@code f2}) will be treated as equal by Daikon. 113 */ 114 public static double dkconfig_fuzzy_ratio = 0.0001; 115 116 /** The default for dkconfig_enabled in each subclass of Invariant. */ 117 public static boolean invariantEnabledDefault = true; 118 119 /** 120 * The program point for this invariant; includes values, number of samples, VarInfos, etc. Can be 121 * null for a "prototype" invariant. 122 */ 123 @Unused(when = Prototype.class) 124 public PptSlice ppt; 125 126 // Has to be public so wrappers can read it. 127 /** 128 * True exactly if the invariant has been falsified: it is guaranteed never to hold (and should be 129 * either in the process of being destroyed or about to be destroyed). This should never be set 130 * directly; instead, call destroy(). 131 */ 132 protected boolean falsified = false; 133 134 // Whether an invariant is a guarding predicate, that is, creately solely 135 // for the purpose of ensuring invariants with variables that can be 136 // missing do not cause exceptions when tested. If this is true, then 137 // the invariant itself does not hold over the observed data. 138 public boolean isGuardingPredicate = false; 139 140 /** 141 * The probability that this could have happened by chance alone. <br> 142 * 1 = could never have happened by chance; that is, we are fully confident that this invariant is 143 * a real invariant 144 */ 145 public static final double CONFIDENCE_JUSTIFIED = 1; 146 147 /** 148 * (0..1) = greater to lesser likelihood of coincidence <br> 149 * 0 = must have happened by chance 150 */ 151 public static final double CONFIDENCE_UNJUSTIFIED = 0; 152 153 /** -1 = delete this invariant; we know it's not true */ 154 public static final double CONFIDENCE_NEVER = -1; 155 156 /** 157 * The probability that this could have happened by chance alone. <br> 158 * 0 = could never have happened by chance; that is, we are fully confident that this invariant is 159 * a real invariant 160 */ 161 public static final double PROBABILITY_JUSTIFIED = 0; 162 163 /** 164 * (0..1) = lesser to greater likelihood of coincidence <br> 165 * 1 = must have happened by chance 166 */ 167 public static final double PROBABILITY_UNJUSTIFIED = 1; 168 169 /** 3 = delete this invariant; we know it's not true */ 170 public static final double PROBABILITY_NEVER = 3; 171 172 /** 173 * Return Invariant.CONFIDENCE_JUSTIFIED if x≥goal. Return Invariant.CONFIDENCE_UNJUSTIFIED if 174 * x≤1. For intermediate inputs, the result gives confidence that grades between the two 175 * extremes. See the discussion of gradual vs. sudden confidence transitions. 176 * 177 * @param x the greater value 178 * @param goal the lesser value 179 * @return CONFIDENCE_JUSTIFIED if x≥goal, Invariant.CONFIDENCE_UNJUSTIFIED if x≤1, other 180 * values otherwise 181 */ 182 public static final double conf_is_ge(double x, double goal) { 183 if (x >= goal) { 184 return 1; 185 } 186 if (x <= 1) { 187 return 0; 188 } 189 double result = 1 - (goal - x) / (goal - 1); 190 assert 0 <= result && result <= 1 191 : "conf_is_ge: bad result = " + result + " for (x=" + x + ", goal=" + goal + ")"; 192 return result; 193 } 194 195 /** 196 * Return Invariant.PROBABILITY_JUSTIFIED if x≥goal. Return Invariant.PROBABILITY_UNJUSTIFIED 197 * if x≤1. For intermediate inputs, the result gives probability that grades between the two 198 * extremes. See the discussion of gradual vs. sudden probability transitions. 199 * 200 * @param x the greater value 201 * @param goal the lesser value 202 * @return if x≥goal: invariant.PROBABILITY_JUSTIFIED; if x≤1: 203 * Invariant.PROBABILITY_UNJUSTIFIED; otherwise: other values 204 */ 205 public static final double prob_is_ge(double x, double goal) { 206 if (x >= goal) { 207 return 0; 208 } 209 if (x <= 1) { 210 return 1; 211 } 212 double result = (goal - x) / (goal - 1); 213 assert 0 <= result && result <= 1 214 : "prob_is_ge: bad result = " + result + " for (x=" + x + ", goal=" + goal + ")"; 215 return result; 216 } 217 218 /** 219 * Return the "and" of the given confidences. This is the confidence that multiple conditions 220 * (whose confidences are given) are all satisfied. 221 * 222 * @param c1 the confidence of the first condition 223 * @param c2 the confidence of the second condition 224 * @return the "and" of the two condidences 225 */ 226 public static final double confidence_and(double c1, double c2) { 227 assert 0 <= c1 && c1 <= 1 : "confidence_and: bad c1 = " + c1; 228 assert 0 <= c2 && c2 <= 1 : "confidence_and: bad c2 = " + c2; 229 230 double result = c1 * c2; 231 232 assert 0 <= result && result <= 1 : "confidence_and: bad result = " + result; 233 return result; 234 } 235 236 /** 237 * Return the "and" of the given confidences. This is the confidence that multiple conditions 238 * (whose confidences are given) are all satisfied. 239 * 240 * @param c1 the confidence of the first condition 241 * @param c2 the confidence of the second condition 242 * @param c3 the confidence of the third condition 243 * @return the "and" of the two condidences 244 */ 245 public static final double confidence_and(double c1, double c2, double c3) { 246 assert 0 <= c1 && c1 <= 1 : "confidence_and: bad c1 = " + c1; 247 assert 0 <= c2 && c2 <= 1 : "confidence_and: bad c2 = " + c1; 248 assert 0 <= c3 && c3 <= 1 : "confidence_and: bad c3 = " + c1; 249 250 double result = c1 * c2 * c3; 251 252 assert 0 <= result && result <= 1 : "confidence_and: bad result = " + result; 253 return result; 254 } 255 256 /** 257 * Return the "or" of the given confidences. This is the confidence that at least one of multiple 258 * conditions (whose confidences are given) is satisfied. 259 * 260 * @param c1 the confidence of the first condition 261 * @param c2 the confidence of the second condition 262 * @return the "or" of the two condidences 263 */ 264 public static final double confidence_or(double c1, double c2) { 265 // Not "1-(1-c1)*(1-c2)" because that can produce a value too large; we 266 // don't want the result to be larger than the larger argument. 267 return Math.max(c1, c2); 268 } 269 270 /** 271 * Return the "and" of the given probabilities. This is the probability that multiple conditions 272 * (whose probabilities are given) are all satisfied. 273 * 274 * @param p1 the probability of the first condition 275 * @param p2 the probability of the second condition 276 * @return the "and" of the two condidences 277 */ 278 public static final double prob_and(double p1, double p2) { 279 assert 0 <= p1 && p1 <= 1 : "prob_and: bad p1 = " + p1; 280 assert 0 <= p2 && p2 <= 1 : "prob_and: bad p2 = " + p2; 281 282 // 1 - (1-p1)*(1-p2) 283 double result = p1 + p2 - p1 * p2; 284 285 assert 0 <= result && result <= 1 : "prob_and: bad result = " + result; 286 return result; 287 } 288 289 /** 290 * Return the "and" of the given probabilities. This is the probability that multiple conditions 291 * (whose probabilities are given) are all satisfied. 292 * 293 * @param p1 the probability of the first condition 294 * @param p2 the probability of the second condition 295 * @param p3 the probability of the third condition 296 * @return the "and" of the two condidences 297 */ 298 public static final double prob_and(double p1, double p2, double p3) { 299 assert 0 <= p1 && p1 <= 1 : "prob_and: bad p1 = " + p1; 300 assert 0 <= p2 && p2 <= 1 : "prob_and: bad p2 = " + p1; 301 assert 0 <= p3 && p3 <= 1 : "prob_and: bad p3 = " + p1; 302 303 double result = 1 - (1 - p1) * (1 - p2) * (1 - p3); 304 305 assert 0 <= result && result <= 1 : "prob_and: bad result = " + result; 306 return result; 307 } 308 309 /** 310 * Return the "or" of the given probabilities. This is the probability that at least one of 311 * multiple conditions (whose probabilities are given) is satisfied. 312 * 313 * @param p1 the probability of the first condition 314 * @param p2 the probability of the second condition 315 * @return the "or" of the two condidences 316 */ 317 public static final double prob_or(double p1, double p2) { 318 // Not "p1*p2" because that can produce a value too small; we don't 319 // want the result to be smaller than the smaller argument. 320 return Math.min(p1, p2); 321 } 322 323 // Subclasses should set these; Invariant never does. 324 325 /** 326 * At least this many samples are required, or else we don't report any invariant at all. (Except 327 * that OneOf invariants are treated differently.) 328 */ 329 public static final int min_mod_non_missing_samples = 5; 330 331 /** 332 * Returns true if the invariant has enough samples to have its computed constants well-formed. Is 333 * overridden in classes like LinearBinary/Ternary and Upper/LowerBound. 334 * 335 * @return true if the invariant has enough samples to have its computed constants well-formed 336 */ 337 public boolean enoughSamples(@GuardSatisfied @NonPrototype Invariant this) { 338 return true; 339 } 340 341 // The confidence routines (getConfidence and internal helper 342 // computeConfidence) use ModBitTracker information to compute 343 // justification. 344 345 // There are three confidence routines: 346 // justified() is what most clients should call 347 // getConfidence() gives the actual confidence. It used to cache 348 // results, but it does not do so any longer. 349 // computeConfidence() is an internal helper method that does the 350 // actual work, but it should not be called externally, only by 351 // getConfidence. It ignores whether the invariant is falsified. 352 353 // There are two general approaches to computing confidence 354 // when there is a threshold (such as needing to see 10 samples): 355 // * Make the confidence typically either 0 or 1, transitioning 356 // suddenly between the two as soon as the 10th sample is observed. 357 // * Make the confidence transition more gradually; for instance, each 358 // sample changes the confidence by 10%. 359 // The gradual approach has advantages and disadvantages: 360 // + Users can set the confidence limit to see invariants earlier; this 361 // is simpler than figuring out all the thresholds to set. 362 // + Tools such as the operational difference for test suite generation 363 // are assisted by knowing whether they are getting closer to 364 // justification. 365 // - The code is a bit more complicated. 366 367 /** 368 * A wrapper around getConfidence() or getConfidence(). 369 * 370 * @return true if this invariant's confidence is greater than the global confidence limit 371 */ 372 public final boolean justified(@NonPrototype Invariant this) { 373 boolean just = (!falsified && (getConfidence() >= dkconfig_confidence_limit)); 374 if (logOn()) { 375 log( 376 "justified = %s, confidence = %s, samples = %s", 377 just, getConfidence(), ppt.num_samples()); 378 } 379 return just; 380 } 381 382 // If confidence == CONFIDENCE_NEVER, then this invariant can be eliminated. 383 /** 384 * Given that this invariant has been true for all values seen so far, this method returns the 385 * confidence that that situation has occurred by chance alone. 386 * 387 * <p>Returns the probability that the observed data did not happen by chance alone. The result is 388 * a value between 0 and 1 inclusive. 0 means that this invariant could never have occurred by 389 * chance alone; we are fully confident that its truth is no coincidence. 1 means that the 390 * invariant is certainly a happenstance, so the truth of the invariant is not relevant and it 391 * should not be reported. Values between 0 and 1 give differing confidences in the invariant. The 392 * method may also return {@link #CONFIDENCE_NEVER}, meaning the invariant has been falsified. 393 * 394 * <p>An invariant is printed only if its probability of not occurring by chance alone is large 395 * enough (by default, greater than .99; see Daikon's --conf_limit command-line option. 396 * 397 * <p>As an example, consider the invariant "x!=0". If only one value, 22, has been seen for x, 398 * then the conclusion "x!=0" is not justified. But if there have been 1,000,000 values, and none 399 * of them were 0, then we may be confident that the property "x!=0" is not a coincidence. 400 * 401 * <p>This method is a wrapper around {@link #computeConfidence()}, which does the actual work. 402 * 403 * <p>Consider the invariant is 'x is even', which has a 50% chance of being true by chance for 404 * each sample. Then a reasonable body for {@link #computeConfidence} would be 405 * 406 * <pre>return 1 - Math.pow(.5, ppt.num_samples());</pre> 407 * 408 * If 5 values had been seen, then this implementation would return 31/32, which is the likelihood 409 * that all 5 values seen so far were even not purely by chance. 410 * 411 * @return confidence of this invariant 412 * @see #computeConfidence() 413 */ 414 public final double getConfidence(@NonPrototype Invariant this) { 415 assert !falsified; 416 // if (falsified) 417 // return CONFIDENCE_NEVER; 418 double result = computeConfidence(); 419 // System.out.println("getConfidence: " + getClass().getName() + " " + ppt.varNames()); 420 if (!((result == CONFIDENCE_JUSTIFIED) 421 || (result == CONFIDENCE_UNJUSTIFIED) 422 || (result == CONFIDENCE_NEVER) 423 || ((0 <= result) && (result <= 1)))) { 424 // Can't print this.repr_prob(), as it may compute the confidence! 425 System.out.println( 426 "getConfidence: " + getClass().getName() + " " + ppt.varNames() + " => " + result); 427 System.out.println(" " + this.format() + "; " + repr()); 428 } 429 assert ((0 <= result) && (result <= 1)) 430 || (result == CONFIDENCE_JUSTIFIED) 431 || (result == CONFIDENCE_UNJUSTIFIED) 432 || (result == CONFIDENCE_NEVER) 433 : "unexpected conf value: " + getClass().getName() + ": " + repr() + ", result=" + result; 434 return result; 435 } 436 437 /** 438 * This method computes the confidence that this invariant occurred by chance. Clients should call 439 * {@link #getConfidence()} instead. 440 * 441 * <p>This method need not check the value of field "falsified", as the caller does that. 442 * 443 * @return confidence of this invariant 444 * @see #getConfidence() 445 */ 446 protected abstract double computeConfidence(@NonPrototype Invariant this); 447 448 /** 449 * Subclasses should override. An exact invariant indicates that given all but one variable value, 450 * the last one can be computed. (I think that's correct, anyway.) Examples are IntComparison 451 * (when only equality is possible), LinearBinary, FunctionUnary. OneOf is treated differently, as 452 * an interface. The result of this method does not depend on whether the invariant is justified, 453 * destroyed, etc. 454 * 455 * @return true if any variable value can be computed from all the others 456 */ 457 @Pure 458 public boolean isExact(@Prototype Invariant this) { 459 return false; 460 } 461 462 // Implementations of this need to examine all the data values already 463 // in the ppt. Or, don't put too much work in the constructor and instead 464 // have the caller do that. 465 // The "ppt" argument can be null if this is a prototype invariant. 466 protected Invariant(PptSlice ppt) { 467 this.ppt = ppt; 468 checkMergeOverridden(); 469 } 470 471 @SuppressWarnings("nullness") // weakness in @Unused checking 472 protected @Prototype Invariant() { 473 this.ppt = null; 474 checkMergeOverridden(); 475 } 476 477 @SuppressWarnings("unused") 478 @Pure 479 private boolean isPrototype() { 480 return this.ppt == null; 481 } 482 483 /** 484 * Marks the invariant as falsified. Should always be called rather than just setting the flag so 485 * that we can track when this happens. 486 */ 487 public void falsify(@NonPrototype Invariant this) { 488 falsified = true; 489 if (logOn()) { 490 log("Destroyed %s", format()); 491 } 492 } 493 494 /** Clear the falsified flag. */ 495 public void clear_falsified(@NonPrototype Invariant this) { 496 falsified = false; 497 } 498 499 /** 500 * Returns whether or not this invariant has been falsified. 501 * 502 * @return true if this invariant has been falsified 503 */ 504 @Pure 505 public boolean is_false(@NonPrototype Invariant this) { 506 return falsified; 507 } 508 509 /** Do nothing special, Overridden to remove exception from declaration. */ 510 @SideEffectFree 511 @Override 512 public Invariant clone(@GuardSatisfied @NonPrototype Invariant this) { 513 try { 514 Invariant result = (Invariant) super.clone(); 515 return result; 516 } catch (CloneNotSupportedException e) { 517 throw new Error(); // can never happen 518 } 519 } 520 521 /** 522 * Make a copy of this invariant and transfer it into a new PptSlice. 523 * 524 * @param new_ppt must have the same arity and types 525 * @param permutation gives the varinfo array index mapping in the new ppt 526 * @return a copy of the invariant, on a different slice 527 */ 528 public Invariant transfer(@NonPrototype Invariant this, PptSlice new_ppt, int[] permutation) { 529 // Check some sanity conditions 530 assert new_ppt.arity() == ppt.arity(); 531 assert permutation.length == ppt.arity(); 532 for (int i = 0; i < ppt.arity(); i++) { 533 VarInfo oldvi = ppt.var_infos[i]; 534 VarInfo newvi = new_ppt.var_infos[permutation[i]]; 535 // We used to check that all 3 types were equal, but we can't do 536 // that anymore, because with equality, invariants may get 537 // transferred between old and new VarInfos of different types. 538 // They are, however, comparable 539 assert oldvi.comparableNWay(newvi); 540 } 541 542 Invariant result; 543 // Clone it 544 result = this.clone(); 545 546 // Fix up the fields 547 result.ppt = new_ppt; 548 // Let subclasses fix what they need to 549 result = result.resurrect_done(permutation); 550 551 if (logOn()) { 552 result.log( 553 "Created %s:%s via transfer from %s:%s using permutation %s old_ppt = %s new_ppt = %s", 554 result.getClass().getName(), 555 result.format(), 556 getClass().getName(), 557 format(), 558 Arrays.toString(permutation), 559 ppt, 560 new_ppt); 561 // result.log (UtilPlume.backTrace()); 562 } 563 // if (debug.isLoggable(Level.FINE)) 564 // debug.fine ("Invariant.transfer to " + new_ppt.name() + " " 565 // + result.repr()); 566 567 return result; 568 } 569 570 /** 571 * Clones the invariant and then permutes it as specified. Normally used to make child invariant 572 * match the variable order of the parent when merging invariants bottom up. 573 */ 574 public Invariant clone_and_permute(@NonPrototype Invariant this, int[] permutation) { 575 576 Invariant result = this.clone(); 577 result = result.resurrect_done(permutation); 578 579 if (logOn()) { 580 result.log( 581 "Created %s via clone_and_permute from %s using permutation %s old_ppt = %s", 582 result.format(), format(), Arrays.toString(permutation), Arrays.toString(ppt.var_infos) 583 // + " new_ppt = " + Arrays.toString (new_ppt.var_infos) 584 ); 585 } 586 587 return result; 588 } 589 590 /** 591 * Take a falsified invariant and resurrect it in a new PptSlice. 592 * 593 * @param new_ppt must have the same arity and types 594 * @param permutation gives the varinfo array index mapping 595 * @return the resurrected invariant, in a new PptSlice 596 */ 597 public Invariant resurrect(@NonPrototype Invariant this, PptSlice new_ppt, int[] permutation) { 598 // Check some sanity conditions 599 assert falsified; 600 assert new_ppt.arity() == ppt.arity(); 601 assert permutation.length == ppt.arity(); 602 for (int i = 0; i < ppt.arity(); i++) { 603 VarInfo oldvi = ppt.var_infos[i]; 604 VarInfo newvi = new_ppt.var_infos[permutation[i]]; 605 // We used to check that all 3 types were equal, but we can't do 606 // that anymore, because with equality, invariants may get 607 // resurrected between old and new VarInfos of different types. 608 // They are, however, comparable 609 assert oldvi.comparableNWay(newvi); 610 } 611 612 Invariant result; 613 // Clone it 614 result = this.clone(); 615 616 // Fix up the fields 617 result.falsified = false; 618 result.ppt = new_ppt; 619 // Let subclasses fix what they need to 620 result = result.resurrect_done(permutation); 621 622 if (logOn()) { 623 result.log( 624 "Created %s via resurrect from %s using permutation %s old_ppt = %s new_ppt = %s", 625 result.format(), 626 format(), 627 Arrays.toString(permutation), 628 Arrays.toString(ppt.var_infos), 629 Arrays.toString(new_ppt.var_infos)); 630 } 631 632 return result; 633 } 634 635 /** 636 * Returns a single VarComparability that describes the set of variables used by this invariant. 637 * Since all of the variables in an invariant must be comparable, this can usually be the 638 * comparability information for any variable. The exception is when one or more variables is 639 * always comparable (comparable to everything else). An always comparable VarComparability is 640 * returned only if all of the variables involved are always comparable. Otherwise the 641 * comparability information from one of the non always-comparable variables is returned. 642 * 643 * @return a VarComparability that describes any (and all) of this invariant's variables 644 */ 645 public VarComparability get_comparability(@NonPrototype Invariant this) { 646 647 // assert ppt != null : "class " + getClass(); 648 649 // Return the first variable that is not always-comparable 650 for (int i = 0; i < ppt.var_infos.length; i++) { 651 VarComparability vc = ppt.var_infos[i].comparability; 652 if (!vc.alwaysComparable()) { 653 return vc; 654 } 655 } 656 657 // All the variables are always-comparable, just return the first one 658 // return ppt.var_infos[0].comparability; 659 return VarComparabilityImplicit.unknown; 660 } 661 662 /** 663 * Merge the invariants in invs to form a new invariant. This implementation merely returns a 664 * clone of the first invariant in the list. This is correct for simple invariants whose equation 665 * or statistics don't depend on the actual samples seen. It should be overriden for more complex 666 * invariants (eg, bound, oneof, linearbinary, etc). 667 * 668 * @param invs list of invariants to merge. The invariants must all be of the same type and should 669 * come from the children of parent_ppt. They should also all be permuted to match the 670 * variable order in parent_ppt. 671 * @param parent_ppt slice that will contain the new invariant 672 * @return the merged invariant or null if the invariants didn't represent the same invariant 673 */ 674 public @Nullable @NonPrototype Invariant merge( 675 @Prototype Invariant this, List<@NonPrototype Invariant> invs, PptSlice parent_ppt) { 676 677 Invariant first = invs.get(0); 678 Invariant result = first.clone(); 679 result.ppt = parent_ppt; 680 result.log( 681 "Merged '%s' from %s child invariants", 682 result.format(), invs.size() /*, first.ppt.name() */); 683 684 // Make sure that each invariant was really of the same type 685 boolean assert_enabled = false; 686 assert (assert_enabled = true); 687 // Now, assert_enabled is true if the JVM was started with the "-ea" command-line argument. 688 if (assert_enabled) { 689 Match m = new Match(result); 690 for (int i = 1; i < invs.size(); i++) { 691 assert m.equals(new Match(invs.get(i))); 692 } 693 } 694 695 return result; 696 } 697 698 /** 699 * Permutes the invariant as specified. Often creates a new invariant (with a different class). 700 * 701 * @param permutation the permutation 702 * @return the permuted invariant 703 */ 704 public @NonPrototype Invariant permute(@NonPrototype Invariant this, int[] permutation) { 705 return resurrect_done(permutation); 706 } 707 708 /** 709 * Called on the new invariant just before resurrect() returns it to allow subclasses to fix any 710 * information they might have cached from the old Ppt and VarInfos. 711 * 712 * @param permutation the permutation 713 * @return the permuted invariant 714 */ 715 protected abstract Invariant resurrect_done(@NonPrototype Invariant this, int[] permutation); 716 717 // Regrettably, I can't declare a static abstract method. 718 // // The return value is probably ignored. The new Invariant installs 719 // // itself on the PptSlice, and that's what really matters (right?). 720 // public static abstract Invariant instantiate(PptSlice ppt); 721 722 /** Return true if this invariant uses the given variable. */ 723 public boolean usesVar(@NonPrototype Invariant this, VarInfo vi) { 724 return ppt.usesVar(vi); 725 } 726 727 /** Return true if this invariant uses the given variable. */ 728 public boolean usesVar(@NonPrototype Invariant this, String name) { 729 return ppt.usesVar(name); 730 } 731 732 /** Return true if this invariant uses the given variable or any variable derived from it. */ 733 public boolean usesVarDerived(@NonPrototype Invariant this, String name) { 734 return ppt.usesVarDerived(name); 735 } 736 737 // Not used as of 1/31/2000 738 // // For use by subclasses. 739 // /** Put a string representation of the variable names in the StringBuilder. */ 740 // public void varNames(StringBuilder sb) { 741 // // sb.append(this.getClass().getName()); 742 // ppt.varNames(sb); 743 // } 744 745 /** 746 * Return a string representation of the variable names. 747 * 748 * @return a string representation of the variable names 749 */ 750 public final String varNames(@GuardSatisfied @NonPrototype Invariant this) { 751 return ppt.varNames(); 752 } 753 754 // repr()'s output should not include result of getConfidence, because 755 // repr() may be called from computeConfidence or elsewhere for 756 // debugging purposes. 757 /** 758 * For printing invariants, there are two interfaces: repr gives a low-level representation 759 * ({@link #repr_prob} also prints the confidence), and {@link #format} gives a high-level 760 * representation for user output. 761 * 762 * @return a string representation of this 763 */ 764 public String repr(@GuardSatisfied @NonPrototype Invariant this) { 765 // A better default would be to use reflection and print out all 766 // the variable names. 767 return getClass() + varNames() + ": " + format(); 768 } 769 770 /** 771 * For printing invariants, there are two interfaces: {@link #repr} gives a low-level 772 * representation (repr_prob also prints the confidence), and {@link #format} gives a high-level 773 * representation for user output. 774 * 775 * @return {@link #repr()}, but with the confidence as well 776 */ 777 public String repr_prob(@NonPrototype Invariant this) { 778 return repr() + "; confidence = " + getConfidence(); 779 } 780 781 /** 782 * Returns a high-level printed representation of the invariant, for user output. {@code format} 783 * produces normal output, while the {@link #repr} formatting routine produces low-level, detailed 784 * output for debugging, and {@link #repr_prob} also prints the confidence. 785 * 786 * @return a string representation of this 787 */ 788 // Does not respect PrintInvariants.dkconfig_print_inv_class; PrintInvariants does so. 789 // Receiver must be fully-initialized because subclasses read their fields. 790 @SideEffectFree 791 public String format(@GuardSatisfied @NonPrototype Invariant this) { 792 return format_using(OutputFormat.DAIKON); 793 } 794 795 /** 796 * Returns the class name of the invariant, for use in debugging output. Returns "" if {@link 797 * PrintInvariants#dkconfig_print_inv_class} is false. 798 * 799 * @return a string representation of the class name of the invariant, or "" 800 */ 801 public String format_classname() { 802 if (!PrintInvariants.dkconfig_print_inv_class) { 803 return ""; 804 } 805 String classname = getClass().getName(); 806 int index = classname.lastIndexOf('.'); 807 classname = classname.substring(index + 1); 808 return " [" + classname + "]"; 809 } 810 811 /** Return a printed representation of this invariant, in the given format. */ 812 @SideEffectFree 813 public abstract String format_using( 814 @GuardSatisfied @NonPrototype Invariant this, OutputFormat format); 815 816 /** 817 * Returns a conjuction of mapping the same function of our expresssions's VarInfos, in general. 818 * Subclasses may override if they are able to handle generally-inexpressible properties in 819 * special-case ways. 820 * 821 * @return conjuction of mapping the same function of our expresssions's VarInfos 822 * @see VarInfo#isValidEscExpression 823 */ 824 @Pure 825 public boolean isValidEscExpression(@NonPrototype Invariant this) { 826 for (int i = 0; i < ppt.var_infos.length; i++) { 827 if (!ppt.var_infos[i].isValidEscExpression()) { 828 return false; 829 } 830 } 831 return true; 832 } 833 834 /** A "\type(...)" construct where the "..." contains a "$". */ 835 private static Pattern anontype_pat = Pattern.compile("\\\\type\\([^\\)]*\\$"); 836 837 /** 838 * Returns true if this Invariant can be properly formatted for the given output format. 839 * 840 * @param format the expected output format 841 * @return true if this Invariant can be properly formatted for the given output format 842 */ 843 @Pure 844 public boolean isValidExpression(@NonPrototype Invariant this, OutputFormat format) { 845 if ((format == OutputFormat.ESCJAVA) && !isValidEscExpression()) { 846 return false; 847 } 848 849 String s = format_using(format); 850 851 if ((format == OutputFormat.ESCJAVA) || format.isJavaFamily()) { 852 // This list should get shorter as we improve the formatting. 853 if ((s.indexOf(" needs to be implemented: ") != -1) 854 || (s.indexOf("<<") != -1) 855 || (s.indexOf(">>") != -1) 856 || (s.indexOf("warning: ") != -1) 857 || (s.indexOf('~') != -1) 858 || (s.indexOf("\\new") != -1) 859 || (s.indexOf(".toString ") != -1) 860 || s.endsWith(".toString") 861 || (s.indexOf(".typeArray") != -1) 862 || (s.indexOf("warning: method") != -1) 863 || (s.indexOf("inexpressible") != -1) 864 || (s.indexOf("unimplemented") != -1) 865 || (s.indexOf("Infinity") != -1) 866 || anontype_pat.matcher(s).find()) { 867 return false; 868 } 869 } 870 return true; 871 } 872 873 /** 874 * Returns standard "format needs to be implemented" for the given requested format. Made public 875 * so cores can call it. 876 * 877 * @param format the requested output format 878 * @return standard "format needs to be implemented" for the given requested format 879 */ 880 public String format_unimplemented( 881 @GuardSatisfied @NonPrototype Invariant this, OutputFormat format) { 882 String classname = this.getClass().getName(); 883 return "warning: method " 884 + classname 885 + ".format(" 886 + format 887 + ")" 888 + " needs to be implemented: " 889 + format(); 890 } 891 892 /** 893 * Returns standard "too few samples for to have interesting invariant" for the requested format. 894 * For machine-readable formats, this is just "true". An optional string argument, if supplied, is 895 * a human-readable description of the invariant in its uninformative state, which will be added 896 * to the message. 897 * 898 * @param format the requested output format 899 * @return standard "too few samples for to have interesting invariant" for the requested format 900 */ 901 public String format_too_few_samples( 902 @GuardSatisfied @NonPrototype Invariant this, OutputFormat format, @Nullable String attempt) { 903 if (format == OutputFormat.SIMPLIFY) { 904 return "(AND)"; 905 } else if (format == OutputFormat.JAVA 906 || format == OutputFormat.ESCJAVA 907 || format == OutputFormat.JML 908 || format == OutputFormat.DBCJAVA) { 909 return "true"; 910 } 911 String classname = this.getClass().getName(); 912 if (attempt == null) { 913 attempt = varNames(); 914 } 915 return "warning: too few samples for " + classname + " invariant: " + attempt; 916 } 917 918 /** 919 * Convert a floating point value into the weird Modula-3-like floating point format that the 920 * Simplify tool requires. 921 * 922 * @param d the number to print 923 * @return a printed representation of the number, for Simplify 924 */ 925 public static String simplify_format_double(double d) { 926 String s = d + ""; 927 if (s.indexOf('E') != -1) { 928 // 1E6 -> 1d6 929 // 1.43E6 -> 1.43d6 930 s = s.replace('E', 'd'); 931 } else if (s.indexOf('.') != -1) { 932 // 3.14 -> 3.14d0 933 s = s + "d0"; 934 } else if (s.equals("-Infinity")) { 935 // -Infinity -> NegativeInfinity 936 s = "NegativeInfinity"; 937 } 938 // 5 -> 5 939 // NaN -> NaN 940 // Infinity -> Infinity 941 return s; 942 } 943 944 /** 945 * Conver a long integer value into a format that Simplify can use. If the value is too big, we 946 * have to print it in a weird way, then tell Simplify about its properties specially. 947 * 948 * @param l the number to print 949 * @return a printed representation of the number, for Simplify 950 */ 951 public static String simplify_format_long(long l) { 952 LemmaStack.noticeInt(l); 953 if (l > -LemmaStack.SMALL_INTEGER && l < LemmaStack.SMALL_INTEGER) { 954 // Simplify's internal numeric representation is based on 955 // (ratios of) signed 32-bit integers, so it can't be both sound 956 // and precise with respect to integer overflow. In its default 957 // configuration it crashes with an internal error when any 958 // internal computation overflows. To work around this, we print 959 // large integers in an abstract format, and then explicitly 960 // give the ordering among those values. This loses other 961 // arithmetic facts, but is good enough for the way we use it. 962 // Examples of inputs containing large integers that crash: 963 // > (BG_PUSH (< 2147483647 n)) 964 // (assertion in negative argument to GCD) 965 // > (BG_PUSH (>= x -1073741825)) 966 // > (BG_PUSH (<= x 1073741825)) 967 // > (OR) 968 // (assertion: unexpected negative value in the Simplex engine) 969 // > (BG_PUSH (EQ x 56312)) 970 // > (BG_PUSH (EQ y (* y x))) 971 // (assertion: negative denomniator in rational normalize) 972 // The value 32000 for SMALL_INTEGER is semi-empirically derived 973 // as "2**15 - some slop" in hopes of working around as many 974 // potential overflows in Simplify as possible, while still 975 // letting it do concrete arithmetic on small integers. It may 976 // be that there's no bound that would work with arbitrary 977 // formulas, but this one seems to work OK for formulas 978 // generated by Daikon. 979 return "" + l; 980 } else { 981 return SimpUtil.formatInteger(l); 982 } 983 } 984 985 /** 986 * Convert a string value into the weird |-quoted format that the Simplify tool requires. (Note 987 * that Simplify doesn't distinguish between variables, symbolic constants, and strings, so we 988 * prepend "_string_" to avoid collisions with variables and other symbols). 989 * 990 * @param s the number to print 991 * @return a printed representation of the string, for Simplify 992 */ 993 public static String simplify_format_string(String s) { 994 if (s == null) { 995 return "null"; 996 } 997 StringBuilder buf = new StringBuilder("|_string_"); 998 if (s.length() > 150) { 999 // Simplify can't handle long strings (its input routines have a 1000 // 4000-character limit for |...| identifiers, but it gets an 1001 // internal array overflow for ones more than about 195 1002 // characters), so replace all but the beginning and end of a 1003 // long string with a hashed summary. 1004 int summ_length = s.length() - 100; 1005 int p1 = 50 + summ_length / 4; 1006 int p2 = 50 + summ_length / 2; 1007 int p3 = 50 + 3 * summ_length / 4; 1008 int p4 = 50 + summ_length; 1009 StringBuilder summ_buf = new StringBuilder(s.substring(0, 50)); 1010 summ_buf.append("..."); 1011 summ_buf.append(Integer.toHexString(s.substring(50, p1).hashCode())); 1012 summ_buf.append(Integer.toHexString(s.substring(p1, p2).hashCode())); 1013 summ_buf.append(Integer.toHexString(s.substring(p2, p3).hashCode())); 1014 summ_buf.append(Integer.toHexString(s.substring(p3, p4).hashCode())); 1015 summ_buf.append("..."); 1016 summ_buf.append(s.substring(p4)); 1017 s = summ_buf.toString(); 1018 } 1019 for (int i = 0; i < s.length(); i++) { 1020 char c = s.charAt(i); 1021 // The following line uses '\n' rather than linesep. 1022 if (c == '\n') buf.append("\\n"); 1023 else if (c == '\r') buf.append("\\r"); 1024 else if (c == '\t') buf.append("\\t"); 1025 else if (c == '\f') buf.append("\\f"); 1026 else if (c == '\\') buf.append("\\\\"); 1027 else if (c == '|') buf.append("\\|"); 1028 else if (c >= ' ' && c <= '~') buf.append(c); 1029 else { 1030 buf.append("\\"); 1031 // AFAIK, Simplify doesn't glork Unicode, so lop off all but 1032 // the low 8 bits 1033 String octal = Integer.toOctalString(c & 0xff); 1034 // Also, Simplify only accepts octal escapes with exactly 3 digits 1035 while (octal.length() < 3) octal = "0" + octal; 1036 buf.append(octal); 1037 } 1038 } 1039 buf.append("|"); 1040 return buf.toString(); 1041 } 1042 1043 // This should perhaps be merged with some kind of PptSlice comparator. 1044 /** Compare based on arity, then printed representation. */ 1045 public static final class InvariantComparatorForPrinting implements Comparator<Invariant> { 1046 @Pure 1047 @Override 1048 public int compare(@NonPrototype Invariant inv1, @NonPrototype Invariant inv2) { 1049 if (inv1 == inv2) { 1050 return 0; 1051 } 1052 1053 // Guarding implications should compare as if they were without the 1054 // guarding predicate 1055 1056 if (inv1 instanceof GuardingImplication) { 1057 inv1 = ((GuardingImplication) inv1).right; 1058 } 1059 if (inv2 instanceof GuardingImplication) { 1060 inv2 = ((GuardingImplication) inv2).right; 1061 } 1062 1063 // Put equality invariants first 1064 if ((inv1 instanceof EqualityComparison) && !(inv2 instanceof EqualityComparison)) { 1065 return -1; 1066 } 1067 if (!(inv1 instanceof EqualityComparison) && (inv2 instanceof EqualityComparison)) { 1068 return 1; 1069 } 1070 1071 // assert inv1.ppt.parent == inv2.ppt.parent; 1072 VarInfo[] vis1 = inv1.ppt.var_infos; 1073 VarInfo[] vis2 = inv2.ppt.var_infos; 1074 int arity_cmp = vis1.length - vis2.length; 1075 if (arity_cmp != 0) { 1076 return arity_cmp; 1077 } 1078 // Comparing on variable index is wrong in general: variables of the 1079 // same name may have different indices at different program points. 1080 // However, it's safe if the invariants are from the same program 1081 // point. Also, it is nice to avoid changing the order of variables 1082 // from that of the data trace file. 1083 1084 if (inv1.ppt.parent == inv2.ppt.parent) { 1085 for (int i = 0; i < vis1.length; i++) { 1086 int tmp = vis1[i].varinfo_index - vis2[i].varinfo_index; 1087 if (tmp != 0) { 1088 return tmp; 1089 } 1090 } 1091 } else { 1092 // // Debugging 1093 // System.out.println("ICFP: different parents for " + inv1.format() + ", " + 1094 // inv2.format()); 1095 1096 for (int i = 0; i < vis1.length; i++) { 1097 String name1 = vis1[i].name(); 1098 String name2 = vis2[i].name(); 1099 if (name1.equals(name2)) { 1100 continue; 1101 } 1102 int name1in2 = inv2.ppt.parent.indexOf(name1); 1103 int name2in1 = inv1.ppt.parent.indexOf(name2); 1104 int cmp1 = (name1in2 == -1) ? 0 : vis1[i].varinfo_index - name1in2; 1105 int cmp2 = (name2in1 == -1) ? 0 : vis2[i].varinfo_index - name2in1; 1106 int cmp = MathPlume.sign(cmp1) + MathPlume.sign(cmp2); 1107 if (cmp != 0) { 1108 return cmp; 1109 } 1110 } 1111 } 1112 1113 // Sort OneOf invariants earlier than others 1114 if ((inv1 instanceof OneOf) && !(inv2 instanceof OneOf)) { 1115 return -1; 1116 } 1117 if (!(inv1 instanceof OneOf) && (inv2 instanceof OneOf)) { 1118 return 1; 1119 } 1120 1121 // System.out.println("ICFP: default rule yields " 1122 // + inv1.format().compareTo(inv2.format()) 1123 // + " for " + inv1.format() + ", " + inv2.format()); 1124 // (Actually, FileIO.new_decl_format should always be non-null here.) 1125 if (PrintInvariants.dkconfig_old_array_names 1126 && FileIO.new_decl_format != null 1127 && FileIO.new_decl_format) { 1128 return inv1.format().replace("[..]", "[]").compareTo(inv2.format().replace("[..]", "[]")); 1129 } else { 1130 return inv1.format().compareTo(inv2.format()); 1131 } 1132 } 1133 } 1134 1135 /** 1136 * Returns true iff the two invariants represent the same mathematical formula. Does not consider 1137 * the context such as variable names, confidences, sample counts, value counts, or related 1138 * quantities. As a rule of thumb, if two invariants format the same, this method returns true. 1139 * Furthermore, in many cases, if an invariant does not involve computed constants (as "x>c" 1140 * and "y=ax+b" do for constants a, b, and c), then this method vacuously returns true. 1141 * 1142 * @param other the invariant to compare to this one 1143 * @return true iff the two invariants represent the same mathematical formula. Does not consider 1144 * @exception RuntimeException if other.getClass() != this.getClass() 1145 */ 1146 public abstract boolean isSameFormula(@Prototype Invariant this, Invariant other); 1147 1148 /** 1149 * Returns whether or not it is possible to merge invariants of the same class but with different 1150 * formulas when combining invariants from lower ppts to build invariants at upper program points. 1151 * Invariants that have this characteristic (eg, bound, oneof) should override this function. Note 1152 * that invariants that can do this, normally need special merge code as well (to merge the 1153 * different formulas into a single formula at the upper point. 1154 * 1155 * @return true if invariants with different formulas can be merged 1156 */ 1157 public boolean mergeFormulasOk(@Prototype Invariant this) { 1158 return false; 1159 } 1160 1161 /** 1162 * Returns true iff the argument is the "same" invariant as this. Same, in this case, means a 1163 * matching type, formula, and variable names. 1164 * 1165 * @param inv2 the other invariant to compare to this one 1166 * @return true iff the argument is the "same" invariant as this 1167 */ 1168 @Pure 1169 public boolean isSameInvariant(@NonPrototype Invariant this, Invariant inv2) { 1170 // return isSameInvariant(inv2, defaultIsSameInvariantNameExtractor); 1171 1172 Invariant inv1 = this; 1173 1174 // Can't be the same if they aren't the same type 1175 if (!inv1.getClass().equals(inv2.getClass())) { 1176 return false; 1177 } 1178 1179 // Can't be the same if they aren't the same formula 1180 if (!inv1.isSameFormula(inv2)) { 1181 return false; 1182 } 1183 1184 // The variable names much match up, in order 1185 VarInfo[] vars1 = inv1.ppt.var_infos; 1186 VarInfo[] vars2 = inv2.ppt.var_infos; 1187 1188 // due to inv type match already 1189 assert vars1.length == vars2.length; 1190 1191 for (int i = 0; i < vars1.length; i++) { 1192 VarInfo var1 = vars1[i]; 1193 VarInfo var2 = vars2[i]; 1194 if (!var1.name().equals(var2.name())) { 1195 return false; 1196 } 1197 } 1198 1199 return true; 1200 } 1201 1202 /** 1203 * Returns true iff the two invariants represent mutually exclusive mathematical formulas -- that 1204 * is, if one of them is true, then the other must be false. This method does not consider the 1205 * context such as variable names, confidences, sample counts, value counts, or related 1206 * quantities. 1207 * 1208 * @param other the other invariant to compare to this one 1209 * @return true iff the two invariants represent mutually exclusive mathematical formulas 1210 */ 1211 @Pure 1212 public boolean isExclusiveFormula(@NonPrototype Invariant this, Invariant other) { 1213 return false; 1214 } 1215 1216 /** 1217 * Look up a previously instantiated Invariant. 1218 * 1219 * @param invclass the class of the invariant to search for 1220 * @param ppt the program point in which to look for the invariant 1221 * @return the invariant of class invclass, or null if none was found 1222 */ 1223 // This implementation should be made more efficient, because it's used in 1224 // suppression. We should somehow index invariants by their type. 1225 public static @Nullable Invariant find(Class<? extends Invariant> invclass, PptSlice ppt) { 1226 for (Invariant inv : ppt.invs) { 1227 if (inv.getClass() == invclass) { 1228 return inv; 1229 } 1230 } 1231 return null; 1232 } 1233 1234 /** 1235 * Returns the set of non-instantiating suppressions for this invariant. May return null instead 1236 * of an empty set. Should be overridden by subclasses with non-instantiating suppressions. 1237 * 1238 * @return the set of non-instantiating suppressions for this invariant 1239 */ 1240 @Pure 1241 public @Nullable NISuppressionSet get_ni_suppressions(@Prototype Invariant this) { 1242 return null; 1243 } 1244 1245 /** 1246 * Returns whether or not this invariant is ni-suppressed. 1247 * 1248 * @return true if this invariant is ni-suppressed 1249 */ 1250 @SuppressWarnings( 1251 "nullness") // tricky control flow, need to mark get_ni_suppressions as @Pure if that's true 1252 @EnsuresNonNullIf(result = true, expression = "get_ni_suppressions()") 1253 @Pure 1254 public boolean is_ni_suppressed() { 1255 1256 NISuppressionSet ss = get_ni_suppressions(); 1257 if (ss == null) { 1258 return false; 1259 } 1260 boolean suppressed = ss.suppressed(ppt); 1261 if (suppressed && Debug.logOn() && (Daikon.current_inv != null)) { 1262 Daikon.current_inv.log("inv %s suppressed: %s", format(), ss); 1263 } 1264 if (Debug.logDetail()) { 1265 log("suppressed = %s suppression set = %s", suppressed, ss); 1266 } 1267 1268 return suppressed; 1269 } 1270 1271 // /////////////////////////////////////////////////////////////////////////// 1272 // Tests about the invariant (for printing) 1273 // 1274 1275 // DO NOT OVERRIDE. Should be declared "final", but the "final" is 1276 // omitted to allow for easier testing. 1277 @Pure 1278 public boolean isWorthPrinting(@NonPrototype Invariant this) { 1279 return InvariantFilters.defaultFilters().shouldKeep(this) == null; 1280 } 1281 1282 // //////////////////////////////////////////////////////////////////////////// 1283 // Static and dynamic checks for obviousness 1284 1285 /** 1286 * Return true if this invariant is necessarily true from a fact that can be determined statically 1287 * from the decls files. (An example is being from a certain derivation.) Intended to be 1288 * overridden by subclasses. 1289 * 1290 * <p>This method is final because children of Invariant should be extending 1291 * isObviousStatically(VarInfo[]) because it is more general. 1292 */ 1293 @Pure 1294 public final @Nullable DiscardInfo isObviousStatically(@NonPrototype Invariant this) { 1295 return isObviousStatically(this.ppt.var_infos); 1296 } 1297 1298 /** 1299 * Return true if this invariant is necessarily true from a fact that can be determined statically 1300 * -- for the given varInfos rather than the varInfos of this. Conceptually, this means "is this 1301 * invariant statically obvious if its VarInfos were switched with vis?" Intended to be overridden 1302 * by subclasses. Should only do static checking. 1303 * 1304 * <p>Precondition: vis.length == this.ppt.var_infos.length 1305 * 1306 * @param vis the VarInfos this invariant is obvious over. The position and data type of the 1307 * variables is the *same* as that of this.ppt.var_infos. 1308 */ 1309 @Pure 1310 public @Nullable DiscardInfo isObviousStatically(@Prototype Invariant this, VarInfo[] vis) { 1311 return null; 1312 } 1313 1314 /** 1315 * Return true if this invariant and all equality combinations of its member variables are 1316 * necessarily true from a fact that can be determined statically (i.e., the decls files). For 1317 * example, a == b, and f(a) is obvious, but f(b) is not. In that case, this method on f(a) would 1318 * return false. If f(b) is also obvious, then this method would return true. 1319 */ 1320 // This is used because we cannot decide to non-instantiate some 1321 // invariants just because isObviousStatically is true, since some 1322 // of the member variables may be equal to non-obvious varInfos. If 1323 // we were to non-instantiate, we could not copy an invariant to the 1324 // non-obvious VarInfos should they split off from the obvious one. 1325 // Of course, it's expensive to examine every possible permutation 1326 // of VarInfos and their equality set, so a possible conservative 1327 // approximation is to simply return false. 1328 @Pure 1329 public boolean isObviousStatically_AllInEquality(@NonPrototype Invariant this) { 1330 // If the leaders aren't statically obvious, then clearly not all 1331 // combinations are. 1332 if (isObviousStatically() == null) { 1333 return false; 1334 } 1335 1336 for (int i = 0; i < ppt.var_infos.length; i++) { 1337 if (ppt.var_infos[i].equalitySet.getVars().size() > 1) { 1338 return false; 1339 } 1340 } 1341 return true; 1342 } 1343 1344 /** 1345 * Return true if this invariant and some equality combinations of its member variables are 1346 * statically obvious. For example, if a == b, and f(a) is obvious, then so is f(b). We use the 1347 * someInEquality (or least interesting) method during printing so we only print an invariant if 1348 * all its variables are interesting, since a single, static, non interesting occurance means all 1349 * the equality combinations aren't interesting. 1350 * 1351 * @return the VarInfo array that contains the VarInfos that showed this invariant to be obvious. 1352 * The contains variables that are elementwise in the same equality set as this.ppt.var_infos. 1353 * Can be null if no such assignment exists. 1354 */ 1355 @Pure 1356 public @Nullable DiscardInfo isObviousStatically_SomeInEquality(@NonPrototype Invariant this) { 1357 DiscardInfo result = isObviousStatically(); 1358 if (result != null) { 1359 return result; 1360 } 1361 return isObviousStatically_SomeInEqualityHelper( 1362 this.ppt.var_infos, new /*NNC:@MonotonicNonNull*/ VarInfo[this.ppt.var_infos.length], 0); 1363 } 1364 1365 // TODO: finish this comment. 1366 /** Recurse through vis and generate the cartesian product of ... */ 1367 @Pure 1368 protected @Nullable DiscardInfo isObviousStatically_SomeInEqualityHelper( 1369 @NonPrototype Invariant this, 1370 VarInfo[] vis, 1371 /*NNC:@MonotonicNonNull*/ VarInfo[] assigned, 1372 int position) { 1373 if (position == vis.length) { 1374 if (debugIsObvious.isLoggable(Level.FINE)) { 1375 StringBuilder sb = new StringBuilder(); 1376 sb.append(" isObviousStatically_SomeInEquality: "); 1377 for (int i = 0; i < vis.length; i++) { 1378 sb.append(assigned[i].name() + " "); 1379 } 1380 debugIsObvious.fine(sb.toString()); 1381 } 1382 1383 assigned = castNonNullDeep(assigned); // https://tinyurl.com/cfissue/986 1384 return isObviousStatically(assigned); 1385 } else { 1386 for (VarInfo vi : vis[position].get_equalitySet_vars()) { 1387 assigned[position] = vi; 1388 DiscardInfo temp = isObviousStatically_SomeInEqualityHelper(vis, assigned, position + 1); 1389 if (temp != null) { 1390 return temp; 1391 } 1392 } 1393 return null; 1394 } 1395 } 1396 1397 /** 1398 * Return true if this invariant is necessarily true from a fact that can be determined statically 1399 * (i.e., the decls files) or dynamically (after checking data). Intended not to be overriden, 1400 * because sub-classes should override isObviousStatically or isObviousDynamically. Wherever 1401 * possible, suppression, rather than this, should do the dynamic checking. 1402 */ 1403 @Pure 1404 public final @Nullable DiscardInfo isObvious(@NonPrototype Invariant this) { 1405 // Actually actually, we'll eliminate invariants as they become obvious 1406 // rather than on output; the point of this is to speed up computation. 1407 // // Actually, we do need to check isObviousDerived after all because we 1408 // // add invariants that might be obvious, but might also turn out to be 1409 // // even stronger (and so not obvious). We don't know how the invariant 1410 // // turns out until after testing it. 1411 // // // We don't need to check isObviousDerived because we won't add 1412 // // // obvious-derived invariants to lists in the first place. 1413 DiscardInfo staticResult = isObviousStatically_SomeInEquality(); 1414 if (staticResult != null) { 1415 if (debugPrint.isLoggable(Level.FINE)) { 1416 debugPrint.fine(" [obvious: " + repr_prob() + " ]"); 1417 } 1418 return staticResult; 1419 } else { 1420 DiscardInfo dynamicResult = isObviousDynamically_SomeInEquality(); 1421 if (dynamicResult != null) { 1422 if (debugPrint.isLoggable(Level.FINE)) { 1423 debugPrint.fine(" [obvious: " + repr_prob() + " ]"); 1424 } 1425 return dynamicResult; 1426 } else { 1427 return null; 1428 } 1429 } 1430 } 1431 1432 /** 1433 * Return non-null if this invariant is necessarily true from a fact that can be determined 1434 * dynamically (after checking data) -- for the given varInfos rather than the varInfos of this. 1435 * Conceptually, this means, "Is this invariant dynamically obvious if its VarInfos were switched 1436 * with vis?" Intended to be overriden by subclasses so they can filter invariants after checking; 1437 * the overriding method should first call "super.isObviousDynamically(vis)". Since this method is 1438 * dynamic, it should only be called after all processing. 1439 */ 1440 public @Nullable DiscardInfo isObviousDynamically(@NonPrototype Invariant this, VarInfo[] vis) { 1441 assert !Daikon.isInferencing; 1442 assert vis.length <= 3 : "Unexpected more-than-ternary invariant"; 1443 if (!ArraysPlume.hasNoDuplicates(vis)) { 1444 log("Two or more variables are equal %s", format()); 1445 return new DiscardInfo(this, DiscardCode.obvious, "Two or more variables are equal"); 1446 } 1447 // System.out.println("Passed Invariant.isObviousDynamically(): " + format()); 1448 return null; 1449 } 1450 1451 /** 1452 * Return true if more than one of the variables in the invariant are the same variable. We create 1453 * such invariants for the purpose of equality set processing, but they aren't intended for 1454 * printing; there should be invariants with the same meaning but lower arity instead. For 1455 * instance, we don't need "x = x + x" because we have "x = 0" instead. 1456 * 1457 * <p>Actually, this isn't strictly true: we don't have an invariant "a[] is a palindrome" 1458 * corresponding to "a[] is the reverse of a[]", for instance. 1459 * 1460 * @return true if more than one of the variables in the invariant are the same variable 1461 */ 1462 @Pure 1463 public boolean isReflexive(@NonPrototype Invariant this) { 1464 return !ArraysPlume.hasNoDuplicates(ppt.var_infos); 1465 } 1466 1467 /** 1468 * Return true if this invariant is necessarily true from a fact that can be determined 1469 * dynamically (after checking data, based on other invariants that were inferred). Since this 1470 * method is dynamic, it should only be called after all processing. 1471 * 1472 * <p>If a test does not look up other inferred invariants (that is, it relies only on information 1473 * in the decls file), then it should be written as an isObviousStatically test, not an 1474 * isObviousDynamically test. 1475 * 1476 * <p>This method is final because subclasses should extend isObviousDynamically(VarInfo[]) since 1477 * that method is more general. 1478 */ 1479 public final @Nullable DiscardInfo isObviousDynamically(@NonPrototype Invariant this) { 1480 assert !Daikon.isInferencing; 1481 return isObviousDynamically(ppt.var_infos); 1482 } 1483 1484 /** 1485 * Return true if this invariant and some equality combinations of its member variables are 1486 * dynamically obvious. For example, a == b, and f(a) is obvious, so is f(b). We use the 1487 * someInEquality (or least interesting) method during printing so we only print an invariant if 1488 * all its variables are interesting, since a single, dynamic, non interesting occurance means all 1489 * the equality combinations aren't interesting. 1490 * 1491 * @return the VarInfo array that contains the VarInfos that showed this invariant to be obvious. 1492 * The contains variables that are elementwise in the same equality set as this.ppt.var_infos. 1493 * Can be null if no such assignment exists. 1494 */ 1495 @Pure 1496 public @Nullable DiscardInfo isObviousDynamically_SomeInEquality(@NonPrototype Invariant this) { 1497 DiscardInfo result = isObviousDynamically(); 1498 if (result != null) { 1499 return result; 1500 } 1501 return isObviousDynamically_SomeInEqualityHelper( 1502 this.ppt.var_infos, new /*NNC:@MonotonicNonNull*/ VarInfo[this.ppt.var_infos.length], 0); 1503 } 1504 1505 /** 1506 * Recurse through vis (an array of leaders) and generate the cartesian product of their equality 1507 * sets; in other words, every combination of one element from each equality set. For each such 1508 * combination, test isObviousDynamically; if any test is true, then return that combination. The 1509 * combinations are generated via recursive calls to this routine. 1510 */ 1511 protected @Nullable DiscardInfo isObviousDynamically_SomeInEqualityHelper( 1512 @NonPrototype Invariant this, VarInfo[] vis, VarInfo[] assigned, int position) { 1513 if (position == vis.length) { 1514 // base case 1515 if (debugIsObvious.isLoggable(Level.FINE)) { 1516 StringBuilder sb = new StringBuilder(); 1517 sb.append(" isObviousDynamically_SomeInEquality: "); 1518 for (int i = 0; i < vis.length; i++) { 1519 sb.append(assigned[i].name() + " "); 1520 } 1521 debugIsObvious.fine(sb.toString()); 1522 } 1523 return isObviousDynamically(assigned); 1524 } else { 1525 // recursive case 1526 for (VarInfo vi : vis[position].get_equalitySet_vars()) { 1527 assigned[position] = vi; 1528 DiscardInfo temp = isObviousDynamically_SomeInEqualityHelper(vis, assigned, position + 1); 1529 if (temp != null) { 1530 return temp; 1531 } 1532 } 1533 return null; 1534 } 1535 } 1536 1537 /** 1538 * Returns true if this invariant is only over prestate variables. 1539 * 1540 * @return true if this invariant is only over prestate variables 1541 */ 1542 @Pure 1543 public boolean isAllPrestate(@NonPrototype Invariant this) { 1544 return ppt.allPrestate(); 1545 } 1546 1547 /** 1548 * An invariant that includes an uninteresting constant (say, "size(x[]) < 237") is likely to 1549 * be an artifact of the way the program was tested, rather than a statement that would in fact 1550 * hold over all possible executions. 1551 */ 1552 public boolean hasUninterestingConstant(@NonPrototype Invariant this) { 1553 return false; 1554 } 1555 1556 // Orders invariants by class, then by variable names. If the 1557 // invariants are both of class Implication, they are ordered by 1558 // comparing the predicate, then the consequent. 1559 public static final class ClassVarnameComparator implements Comparator<Invariant> { 1560 @Pure 1561 @Override 1562 public int compare(Invariant inv1, Invariant inv2) { 1563 1564 if (inv1 instanceof Implication && inv2 instanceof Implication) { 1565 return compareImplications((Implication) inv1, (Implication) inv2); 1566 } 1567 1568 int compareClass = compareClass(inv1, inv2); 1569 if (compareClass != 0) { 1570 return compareClass; 1571 } 1572 1573 return compareVariables(inv1, inv2); 1574 } 1575 1576 // Returns 0 if the invariants are of the same class. Else, 1577 // returns the comparison of the class names. 1578 private int compareClass(Invariant inv1, Invariant inv2) { 1579 if (inv1.getClass().equals(inv2.getClass())) { 1580 if (inv1 instanceof DummyInvariant) { 1581 // This special case is needed because the other code 1582 // assumes that all invariants of a given class have the 1583 // same arity. 1584 String df1 = inv1.format(); 1585 String df2 = inv2.format(); 1586 int cmp = df1.compareTo(df2); 1587 if (cmp != 0) { 1588 return cmp; 1589 } 1590 return inv1.ppt.var_infos.length - inv2.ppt.var_infos.length; 1591 } 1592 return 0; 1593 } else { 1594 String classname1 = inv1.getClass().getName(); 1595 String classname2 = inv2.getClass().getName(); 1596 return classname1.compareTo(classname2); 1597 } 1598 } 1599 1600 // Returns 0 if the invariants have the same variable names. 1601 // Else, returns the comparison of the first variable names that 1602 // differ. Requires that the invariants be of the same class. 1603 private int compareVariables(Invariant inv1, Invariant inv2) { 1604 VarInfo[] vars1 = inv1.ppt.var_infos; 1605 VarInfo[] vars2 = inv2.ppt.var_infos; 1606 1607 // due to inv type match already 1608 assert vars1.length == vars2.length 1609 : "Bad type match: " + inv1.format() + " vs. " + inv2.format(); 1610 1611 for (int i = 0; i < vars1.length; i++) { 1612 VarInfo var1 = vars1[i]; 1613 VarInfo var2 = vars2[i]; 1614 int compare = var1.name().compareTo(var2.name()); 1615 if (compare != 0) { 1616 return compare; 1617 } 1618 } 1619 1620 // All the variable names matched 1621 return 0; 1622 } 1623 1624 private int compareImplications(Implication inv1, Implication inv2) { 1625 int comparePredicate = compare(inv1.predicate(), inv2.predicate()); 1626 if (comparePredicate != 0) { 1627 return comparePredicate; 1628 } 1629 1630 return compare(inv1.consequent(), inv2.consequent()); 1631 } 1632 } 1633 1634 /** 1635 * Orders invariants by class, then variable names, then formula. If the formulas are the same, 1636 * compares the printed representation obtained from the format() method. 1637 */ 1638 public static final class ClassVarnameFormulaComparator implements Comparator<Invariant> { 1639 1640 Comparator<Invariant> classVarnameComparator = new ClassVarnameComparator(); 1641 1642 @Pure 1643 @Override 1644 public int compare(@NonPrototype Invariant inv1, @NonPrototype Invariant inv2) { 1645 int compareClassVarname = classVarnameComparator.compare(inv1, inv2); 1646 1647 if (compareClassVarname != 0) { 1648 return compareClassVarname; 1649 } 1650 1651 if (inv1.isSameInvariant(inv2)) { 1652 return 0; 1653 } 1654 1655 int result = inv1.format().compareTo(inv2.format()); 1656 1657 // The purpose of the assertion below would seem to be to insist that 1658 // anything that doesn't return true to isSameInvariant() will not 1659 // produce the same written formula. This can happen, however, if the 1660 // variables have a different order (as in function binary), but the 1661 // swapped variables are actually the same (since we create invariants 1662 // of the form f(a, a, a) because of equality sets. 1663 // assert result != 0 1664 // : "isSameInvariant() returned false " 1665 // + "(isSameFormula returned " + inv1.isSameFormula(inv2) + ")," + lineSep 1666 // + "but format().compareTo() returned 0:" + lineSep 1667 // + " " + inv1.format() + lineSep + " " + inv1.repr() + lineSep 1668 // + " " + inv1.ppt.parent.name + lineSep 1669 // + " " + inv2.format() + lineSep + " " + inv2.repr() + lineSep 1670 // + " " + inv1.ppt.parent.name + lineSep 1671 // ; 1672 1673 return result; 1674 } 1675 } 1676 1677 /** 1678 * Class used as a key to store invariants in a MAP where their equality depends on the invariant 1679 * representing the same invariant (i.e., their class is the same) and the same internal state 1680 * (when multiple invariants with the same class are possible). 1681 * 1682 * <p>Note that this is based on the Invariant type (i.e., class) and the internal state and not 1683 * on what ppt the invariant is in or what variables it is over. Thus, invariants from different 1684 * ppts are the same if they represent the same type of invariant. 1685 */ 1686 public static class Match { 1687 1688 public Invariant inv; 1689 1690 public Match(Invariant inv) { 1691 this.inv = inv; 1692 } 1693 1694 @EnsuresNonNullIf(result = true, expression = "#1") 1695 @Pure 1696 @Override 1697 public boolean equals(@GuardSatisfied Match this, @GuardSatisfied @Nullable Object obj) { 1698 if (!(obj instanceof Match)) { 1699 return false; 1700 } 1701 1702 Match ic = (Match) obj; 1703 return ic.inv.match(inv); 1704 } 1705 1706 @Pure 1707 @Override 1708 public int hashCode(@GuardSatisfied Match this) { 1709 return inv.getClass().hashCode(); 1710 } 1711 } 1712 1713 /** 1714 * Returns whether or not two invariants are of the same type. To be of the same type, invariants 1715 * must be of the same class. Some invariant classes represent multiple invariants (such as 1716 * FunctionBinary). They must also be the same formula. Note that invariants with different 1717 * formulas based on their samples (LinearBinary, Bounds, etc) will still match as long as the 1718 * mergeFormulaOk() method returns true. 1719 */ 1720 public boolean match(@Prototype Invariant inv) { 1721 1722 if (inv.getClass() == getClass()) { 1723 return inv.mergeFormulasOk() || isSameFormula(inv); 1724 } else { 1725 return false; 1726 } 1727 } 1728 1729 /** 1730 * Returns whether or not the invariant matches the specified state. Must be overriden by 1731 * subclasses that support this. Otherwise, it returns true only if the state is null. 1732 */ 1733 public boolean state_match(@NonPrototype Invariant this, Object state) { 1734 return (state == null); 1735 } 1736 1737 /** Create a guarding predicate for a given invariant. Returns null if no guarding is needed. */ 1738 public @Nullable @NonPrototype Invariant createGuardingPredicate(boolean install) { 1739 if (debugGuarding.isLoggable(Level.FINE)) { 1740 debugGuarding.fine("Guarding predicate being created for: "); 1741 debugGuarding.fine(" " + this.format()); 1742 } 1743 1744 // Find which VarInfos must be guarded 1745 List<VarInfo> mustBeGuarded = getGuardingList(); 1746 1747 if (mustBeGuarded.isEmpty()) { 1748 if (debugGuarding.isLoggable(Level.FINE)) { 1749 debugGuarding.fine("No guarding is needed, returning"); 1750 } 1751 return null; 1752 } 1753 1754 // This conjunction would look better if it was built up right-to-left. 1755 Invariant guardingPredicate = null; 1756 for (VarInfo vi : mustBeGuarded) { 1757 Invariant currentGuard = vi.createGuardingPredicate(install); 1758 if (currentGuard == null) { 1759 continue; 1760 } 1761 debugGuarding.fine(String.format("VarInfo %s guard is %s", vi, currentGuard)); 1762 if (guardingPredicate == null) { 1763 guardingPredicate = currentGuard; 1764 } else { 1765 guardingPredicate = new AndJoiner(ppt.parent, guardingPredicate, currentGuard); 1766 } 1767 debugGuarding.fine(String.format(" predicate so far: %s", guardingPredicate)); 1768 } 1769 1770 // If the guarding predicate has been previously constructed, return it. 1771 // Otherwise, we will return the newly constructed one. 1772 // This algorithm is inefficient. 1773 if (guardingPredicate != null) { // equivalently: mustBeGuarded.size() > 1 1774 List<Invariant> joinerViewInvs = ppt.parent.joiner_view.invs; 1775 for (Invariant currentInv : joinerViewInvs) { 1776 if (currentInv.isSameInvariant(guardingPredicate)) { 1777 return currentInv; 1778 } 1779 } 1780 } 1781 return guardingPredicate; 1782 } 1783 1784 /** 1785 * Return a list of all the variables that must be non-null in order for this invariant to be 1786 * evaluated. For instance, it this invariant is "a.b.c > d.e" (where c and e are of integer 1787 * type), then it doesn't make sense to evaluate the invariant unless "a" is non-null, "a.b" is 1788 * non-null, and "d" is non-null. So, another way to write the invariant (in "guarded" form) would 1789 * be "a != null && a.b != null && d != null && a.b.c > d.e". 1790 */ 1791 public List<VarInfo> getGuardingList(@NonPrototype Invariant this) { 1792 return getGuardingList(ppt.var_infos); 1793 } 1794 1795 /** 1796 * Returns the union of calling VarInfo.getGuardingList on each element of the argument. 1797 * 1798 * @param varInfos an array of VarInfo 1799 * @return the union of calling VarInfo.getGuardingList on each element of the argument 1800 */ 1801 public static List<VarInfo> getGuardingList(VarInfo[] varInfos) { 1802 List<VarInfo> guardingList = new ArrayList<>(); 1803 1804 for (int i = 0; i < varInfos.length; i++) { 1805 // debugGuarding.fine (varInfos[i]); 1806 guardingList.addAll(varInfos[i].getGuardingList()); 1807 // debugGuarding.fine (guardingSet.toString()); 1808 } 1809 1810 return CollectionsPlume.withoutDuplicates(guardingList); 1811 } 1812 1813 // This is called only from finally_print_the_invariants(). 1814 // Nothing is ever done with the result except print it and discard it. 1815 /** 1816 * This procedure guards one invariant and returns the resulting guarded invariant (implication), 1817 * without placing it in any slice and without modifying the original invariant. Returns null if 1818 * the invariant does not need to be guarded. 1819 */ 1820 public @Nullable @NonPrototype Invariant createGuardedInvariant(boolean install) { 1821 if (Daikon.dkconfig_guardNulls == "never") { // interned 1822 return null; 1823 } 1824 1825 if (debugGuarding.isLoggable(Level.FINE)) { 1826 debugGuarding.fine(" Trying to add guard for: " + this + "; repr = " + repr()); 1827 } 1828 if (isGuardingPredicate) { 1829 debugGuarding.fine(" Do not guard: this is a guarding predicate"); 1830 return null; 1831 } 1832 Invariant guardingPredicate = createGuardingPredicate(install); 1833 if (debugGuarding.isLoggable(Level.FINE)) { 1834 if (guardingPredicate != null) { 1835 debugGuarding.fine(" Predicate: " + guardingPredicate.format()); 1836 debugGuarding.fine(" Consequent: " + format()); 1837 } else { 1838 debugGuarding.fine(" No implication needed"); 1839 } 1840 } 1841 1842 if (guardingPredicate == null) { 1843 return null; 1844 } 1845 1846 Implication guardingImplication = 1847 GuardingImplication.makeGuardingImplication(ppt.parent, guardingPredicate, this, false); 1848 1849 if (install) { 1850 if (!ppt.parent.joiner_view.hasImplication(guardingImplication)) { 1851 ppt.parent.joiner_view.addInvariant(guardingImplication); 1852 } 1853 } 1854 return guardingImplication; 1855 } 1856 1857 /** 1858 * Instantiates (creates) an invariant of the same class on the specified slice. Must be 1859 * overridden in each class. Must be used rather than {@link #clone} so that checks in {@link 1860 * #instantiate} for reasonable invariants are done. 1861 * 1862 * <p>The implementation of this method is almost always {@code return new 1863 * <em>InvName</em>(slice);} 1864 * 1865 * @return the new invariant 1866 */ 1867 protected abstract @NonPrototype Invariant instantiate_dyn( 1868 @Prototype Invariant this, PptSlice slice); 1869 1870 /** 1871 * Returns whether or not this class of invariants is currently enabled. 1872 * 1873 * <p>Its implementation is almost always {@code return dkconfig_enabled;}. 1874 */ 1875 public abstract boolean enabled(@Prototype Invariant this); 1876 1877 /** 1878 * Returns whether or not the invariant is valid over the basic types in vis. This only checks 1879 * basic types (scalar, string, array, etc) and should match the basic superclasses of invariant 1880 * (SingleFloat, SingleScalarSequence, ThreeScalar, etc). More complex checks that depend on 1881 * variable details can be implemented in instantiate_ok(). 1882 * 1883 * @see #instantiate_ok(VarInfo[]) 1884 */ 1885 public abstract boolean valid_types(@Prototype Invariant this, VarInfo[] vis); 1886 1887 /** 1888 * Returns true if it makes sense to instantiate this invariant over the specified variables. 1889 * Checks details beyond what is provided by {@link #valid_types}. This should never be called 1890 * without calling valid_types() first (implementations should be able to presume that 1891 * valid_types() returns true). 1892 * 1893 * <p>This method does not have to be overridden; the default implementation in Invariant returns 1894 * true. 1895 * 1896 * @see #valid_types(VarInfo[]) 1897 */ 1898 public boolean instantiate_ok(@Prototype Invariant this, VarInfo[] vis) { 1899 return true; 1900 } 1901 1902 // Every Invariant is either a regular Invariant, or a "prototype" 1903 // Invariant. A prototype invariant is really a factory. The 1904 // "instantiate" method should only be called on a prototype invariant, 1905 // and many methods should only be called on non-prototype methods. 1906 // Another (arguably better, though less convenient in certain ways) 1907 // design would not represent the factory as an Invariant object. An 1908 // object never transitions at run time between being a factory/prototype 1909 // and being a normal invariant. 1910 // 1911 // Could we just use the class, such as Positive.class, as (a proxy for) 1912 // the factory? 1913 // * That would require use of reflection to call the constructor, which 1914 // is ugly. 1915 // * The factory needs at least some state is needed, for example to 1916 // distinguish between creating a division operator "a/b" vs. "b/a". 1917 // 1918 // Could the factories be represented by a separate class, unrelated in 1919 // the type hierarchy to Invariant? 1920 // * That would probably be a better design. 1921 // * instantiate_dyn would have to have more than just the single line that 1922 // it is right now; longer code is more error-prone. 1923 // * Not all the code for an invariant would be in a single class any 1924 // more; but it could still all be in the same file, for example. 1925 // * There are probably other difficulties that escape me at the moment. 1926 1927 /** 1928 * Instantiates this invariant over the specified slice. The slice must not be null and its 1929 * variables must be valid for this type of invariant. Returns null if the invariant is not 1930 * enabled or if the invariant is not reasonable over the specified variables. Otherwise returns 1931 * the new invariant. 1932 */ 1933 public @Nullable Invariant instantiate(@Prototype Invariant this, PptSlice slice) { 1934 1935 assert isPrototype(); // receiver should be a "prototype" invariant 1936 assert slice != null; 1937 if (!valid_types(slice.var_infos)) { 1938 System.out.printf("this.getClass(): %s%n", this.getClass()); 1939 System.out.printf("slice: %s%n", slice); 1940 System.out.printf( 1941 "slice.var_infos (length %d): %s%n", slice.var_infos.length, (Object) slice.var_infos); 1942 for (VarInfo vi : slice.var_infos) { 1943 System.out.printf(" var_info: %s %s%n", vi, vi.type); 1944 } 1945 } 1946 assert valid_types(slice.var_infos) 1947 : String.format("valid_types(%s) = false for %s", Arrays.toString(slice.var_infos), this); 1948 if (!enabled() || !instantiate_ok(slice.var_infos)) { 1949 return null; 1950 } 1951 Invariant inv = instantiate_dyn(slice); 1952 assert inv != null; 1953 if (inv.ppt == null) { 1954 // Avoid creating the message if the check succeeds 1955 assert inv.ppt != null : "invariant class " + inv.getClass(); 1956 } 1957 return inv; 1958 } 1959 1960 /** 1961 * Adds the specified sample to the invariant and returns the result. 1962 * 1963 * @param vt the sample to add to this invariant 1964 * @param count the number of occurrences of the sample to add to this invariant 1965 * @return the result of adding the samples to this invariant 1966 */ 1967 public InvariantStatus add_sample(@NonPrototype Invariant this, ValueTuple vt, int count) { 1968 1969 if (ppt instanceof PptSlice1) { 1970 1971 VarInfo v = ppt.var_infos[0]; 1972 UnaryInvariant unary_inv = (UnaryInvariant) this; 1973 return unary_inv.add(vt.getValue(v), vt.getModified(v), count); 1974 1975 } else if (ppt instanceof PptSlice2) { 1976 1977 VarInfo v1 = ppt.var_infos[0]; 1978 VarInfo v2 = ppt.var_infos[1]; 1979 BinaryInvariant bin_inv = (BinaryInvariant) this; 1980 return bin_inv.add_unordered(vt.getValue(v1), vt.getValue(v2), vt.getModified(v1), count); 1981 1982 } else /* must be ternary */ { 1983 1984 VarInfo v1 = ppt.var_infos[0]; 1985 VarInfo v2 = ppt.var_infos[1]; 1986 VarInfo v3 = ppt.var_infos[2]; 1987 assert (this instanceof TernaryInvariant) 1988 : "invariant '" + format() + "' in slice " + ppt.name() + " is not ternary"; 1989 TernaryInvariant ternary_inv = (TernaryInvariant) this; 1990 return ternary_inv.add( 1991 vt.getValue(v1), vt.getValue(v2), vt.getValue(v3), vt.getModified(v1), count); 1992 } 1993 } 1994 1995 /** Check the rep invariants of this. */ 1996 public void repCheck(@Prototype Invariant this) {} 1997 1998 /** 1999 * Returns whether or not the invariant is currently active. This is used to identify those 2000 * invariants that require a certain number of points before they actually do computation (eg, 2001 * LinearBinary) 2002 * 2003 * <p>This is used during suppresion. Any invariant that is not active cannot suppress another 2004 * invariant. 2005 * 2006 * @return true if this invariant is currently active 2007 */ 2008 @Pure 2009 public boolean isActive(@NonPrototype Invariant this) { 2010 return true; 2011 } 2012 2013 // TODO: The logDetail and (especially) logOn methods are misleading, 2014 // because they are static but are very often called with an instance as 2015 // the receiver, suggesting that they have something to do with the 2016 // receiver. This should be corrected. -MDE 2017 2018 /** 2019 * Returns true if detailed logging is on. Note that this check is not performed inside the 2020 * logging calls themselves, it must be performed by the caller. 2021 * 2022 * @return true if detailed logging is on 2023 * @see daikon.Debug#logDetail() 2024 * @see daikon.Debug#logOn() 2025 * @see daikon.Debug#log(Logger, Class, Ppt, String) 2026 */ 2027 public static boolean logDetail() { 2028 return Debug.logDetail(); 2029 } 2030 2031 /** 2032 * Returns whether or not logging is on. 2033 * 2034 * @see daikon.Debug#logOn() 2035 */ 2036 public static boolean logOn() { 2037 return Debug.logOn(); 2038 } 2039 2040 // Using `@link` leads to javadoc -Xdoclint:all crashing with: 2041 // "com.sun.tools.javac.code.Type$AnnotatedType cannot be cast to 2042 // com.sun.tools.javac.code.Type$ClassType" 2043 /** 2044 * Logs a description of the invariant and the specified msg via the logger as described in {@code 2045 * daikon.Debug#log(Logger, Class, Ppt, VarInfo[], String)}. 2046 * 2047 * @param log where to log the message 2048 * @param msg the message to log 2049 */ 2050 // receiver needs to be initialized because subclass implementations will read their own fields 2051 public void log(@NonPrototype Invariant this, Logger log, String msg) { 2052 2053 if (Debug.logOn()) { 2054 Debug.log(log, getClass(), ppt, msg); 2055 } 2056 } 2057 2058 // Using `@link` leads to javadoc -Xdoclint:all crashing with: 2059 // "com.sun.tools.javac.code.Type$AnnotatedType cannot be cast to 2060 // com.sun.tools.javac.code.Type$ClassType" 2061 /** 2062 * Logs a description of the invariant and the specified msg via the logger as described in {@code 2063 * daikon.Debug#log(Logger, Class, Ppt, VarInfo[], String)}. 2064 * 2065 * @param format a format string 2066 * @param args the argumnts to the format string 2067 * @return whether or not it logged anything 2068 */ 2069 @FormatMethod 2070 public boolean log( 2071 @UnknownInitialization(Invariant.class) @NonPrototype Invariant this, 2072 String format, 2073 @Nullable Object... args) { 2074 if (ppt != null) { 2075 String msg = format; 2076 if (args.length > 0) { 2077 msg = String.format(format, args); 2078 } 2079 return Debug.log(getClass(), ppt, msg); 2080 } else { 2081 return false; 2082 } 2083 } 2084 2085 // Receiver must be fully initialized 2086 @SideEffectFree 2087 @Override 2088 public String toString(@GuardSatisfied Invariant this) { 2089 return format(); 2090 } 2091 2092 /** 2093 * Return a string representation of the given invariants. 2094 * 2095 * @param invs the invariants to get a string representation of 2096 * @return a string representation of the given invariants 2097 */ 2098 public static String toString(@NonPrototype Invariant[] invs) { 2099 2100 ArrayList<String> strings = new ArrayList<>(invs.length); 2101 for (int i = 0; i < invs.length; i++) { 2102 if (invs[i] == null) { 2103 strings.add("null"); 2104 } else { 2105 strings.add(invs[i].format()); 2106 } 2107 } 2108 return String.join(", ", strings); 2109 } 2110 2111 /** 2112 * Used throughout Java family formatting of invariants. 2113 * 2114 * <p>Returns 2115 * 2116 * <p>"plume.FuzzyFloat.method(v1_name, v2_name)" 2117 * 2118 * <p>Where v1_name and v2_name are the properly formatted varinfos v1 and v2, under the given 2119 * format. 2120 */ 2121 // [[ This method doesn't belong here. But where? ]] 2122 public static String formatFuzzy(String method, VarInfo v1, VarInfo v2, OutputFormat format) { 2123 2124 StringBuilder results = new StringBuilder(); 2125 return results 2126 .append("daikon.Quant.fuzzy.") 2127 .append(method) 2128 .append("(") 2129 .append(v1.name_using(format)) 2130 .append(", ") 2131 .append(v2.name_using(format)) 2132 .append(")") 2133 .toString(); 2134 } 2135 2136 @SuppressWarnings("unchecked") // casting method 2137 public static Class<? extends Invariant> asInvClass(Object x) { 2138 return (Class<? extends Invariant>) x; 2139 } 2140 2141 /** 2142 * Returns true if this is an equality comparison. That is, returns true if this Invariant 2143 * satisfies the following conditions: 2144 * 2145 * <ul> 2146 * <li>the Invariant is an EqualityComparison (its relationship is =, not <, ≤, >, or 2147 * ≥). 2148 * <li>the invariant is statistically satisfied (its confidence is above the limit) 2149 * </ul> 2150 * 2151 * This does not consider PairwiseIntComparison to be an equality invariant. 2152 */ 2153 public boolean isEqualityComparison() { 2154 if (!(this instanceof EqualityComparison)) { 2155 return false; 2156 } 2157 double chance_conf = ((EqualityComparison) this).eq_confidence(); 2158 return chance_conf > Invariant.dkconfig_confidence_limit; 2159 } 2160 2161 /** 2162 * Throws an exception if this object is invalid. 2163 * 2164 * @exception RuntimeException if representation invariant on this is broken 2165 */ 2166 public void checkRep() { 2167 // very partial initial implementation 2168 for (VarInfo vi : ppt.var_infos) { 2169 vi.checkRep(); 2170 } 2171 } 2172 2173 /** Classes for which {@link #checkMergeOverridden} has been called. */ 2174 public static IdentityHashMap<Class<?>, Boolean> checkedMergeOverridden = new IdentityHashMap<>(); 2175 2176 /** 2177 * Throws an exception if the class directly defines fields but does not override {@link #merge}. 2178 */ 2179 private void checkMergeOverridden( 2180 @UnderInitialization(daikon.inv.Invariant.class) Invariant this) { 2181 Class<?> thisClass = getClass(); 2182 if (!checkedMergeOverridden.containsKey(thisClass)) { 2183 checkedMergeOverridden.put(thisClass, true); 2184 2185 // TODO: Could look at all fields and compare them to the fields of Invariant.class. 2186 Field[] declaredFields = thisClass.getDeclaredFields(); 2187 List<Field> statefulFields = new ArrayList<>(4); 2188 for (Field declaredField : declaredFields) { 2189 if (Modifier.isStatic(declaredField.getModifiers())) { 2190 continue; 2191 } 2192 2193 String fieldName = declaredField.getName(); 2194 if (fieldName.equals("serialVersionUID")) { 2195 continue; 2196 } 2197 if (fieldName.startsWith("$")) { 2198 continue; 2199 } 2200 if (fieldName.startsWith("dkconfig_")) { 2201 continue; 2202 } 2203 if (fieldName.startsWith("debug")) { 2204 continue; 2205 } 2206 if (fieldName.endsWith("Cache")) { 2207 continue; 2208 } 2209 2210 statefulFields.add(declaredField); 2211 } 2212 2213 if (statefulFields.isEmpty()) { 2214 return; 2215 } 2216 2217 try { 2218 @SuppressWarnings( 2219 "UnusedVariable" // Method is called for side effect, ignore return value, but give the 2220 // unused variable a name for documentation purposes. 2221 ) 2222 Method mergeMethod = thisClass.getDeclaredMethod("merge", List.class, PptSlice.class); 2223 // `mergeMethod` is non-null, or else `NoSuchMethodException` was thrown. 2224 } catch (NoSuchMethodException e) { 2225 StringJoiner fields = new StringJoiner(", "); 2226 for (Field f : statefulFields) { 2227 fields.add(f.getName()); 2228 } 2229 throw new Error( 2230 thisClass.getSimpleName() 2231 + " does not override `merge(List, PptTopLevel)`," 2232 + " but these fields might store state: " 2233 + fields); 2234 } 2235 } 2236 } 2237}