001// ***** This file is automatically generated from IntComparisons.java.jpp 002 003package daikon.inv.binary.twoString; 004 005import daikon.*; 006import daikon.derive.binary.*; 007import daikon.derive.unary.*; 008import daikon.inv.*; 009import daikon.inv.binary.twoScalar.*; 010import daikon.inv.binary.twoSequence.*; 011import daikon.inv.unary.scalar.*; 012import daikon.inv.unary.sequence.*; 013import daikon.inv.unary.string.*; 014import daikon.suppress.*; 015import java.util.*; 016import java.util.logging.Level; 017import java.util.logging.Logger; 018import org.checkerframework.checker.interning.qual.Interned; 019import org.checkerframework.checker.lock.qual.GuardSatisfied; 020import org.checkerframework.checker.nullness.qual.NonNull; 021import org.checkerframework.checker.nullness.qual.Nullable; 022import org.checkerframework.dataflow.qual.Pure; 023import org.checkerframework.dataflow.qual.SideEffectFree; 024import org.plumelib.util.Intern; 025import typequals.prototype.qual.NonPrototype; 026import typequals.prototype.qual.Prototype; 027 028/** 029 * Represents an invariant of == between two String scalars. Prints as {@code x == y}. 030 */ 031public final class StringEqual extends TwoString implements EqualityComparison { 032 033 // We are Serializable, so we specify a version to allow changes to 034 // method signatures without breaking serialization. If you add or 035 // remove fields, you should change this number to the current date. 036 static final long serialVersionUID = 20030822L; 037 038 // Variables starting with dkconfig_ should only be set via the 039 // daikon.config.Configuration interface. 040 /** Boolean. True iff StringEqual invariants should be considered. */ 041 public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault; 042 043 public static final Logger debug = Logger.getLogger("daikon.inv.binary.twoScalar.StringEqual"); 044 045 StringEqual(PptSlice ppt) { 046 super(ppt); 047 } 048 049 @Prototype StringEqual() { 050 super(); 051 } 052 053 private static @Prototype StringEqual proto = new @Prototype StringEqual(); 054 055 /** Returns the prototype invariant for StringEqual */ 056 public static @Prototype StringEqual get_proto() { 057 return proto; 058 } 059 060 /** Returns whether or not this invariant is enabled. */ 061 @Override 062 public boolean enabled() { 063 return dkconfig_enabled; 064 } 065 066 /** Returns whether or not the specified var types are valid for StringEqual */ 067 @Override 068 public boolean instantiate_ok(VarInfo[] vis) { 069 070 if (!valid_types(vis)) { 071 return false; 072 } 073 074 boolean result = !(vis[0].has_typeof() ^ vis[1].has_typeof()); 075 return result; 076 } 077 078 /** Instantiate an invariant on the specified slice. */ 079 @Override 080 protected StringEqual instantiate_dyn(@Prototype StringEqual this, PptSlice slice) { 081 082 return new StringEqual(slice); 083 } 084 085 @Pure 086 public boolean is_equality_inv() { 087 return true; 088 } 089 090 @Override 091 protected Invariant resurrect_done_swapped() { 092 093 // we don't care if things swap; we have symmetry 094 return this; 095 } 096 097 @Pure 098 @Override 099 public boolean is_symmetric() { 100 return true; 101 } 102 103 // JHP: this should be removed in favor of checks in PptTopLevel 104 // such as is_equal, is_lessequal, etc. 105 // Look up a previously instantiated StringEqual relationship. 106 // Should this implementation be made more efficient? 107 public static @Nullable StringEqual find(PptSlice ppt) { 108 assert ppt.arity() == 2; 109 for (Invariant inv : ppt.invs) { 110 if (inv instanceof StringEqual) { 111 return (StringEqual) inv; 112 } 113 } 114 115 // If the invariant is suppressed, create it 116 if ((suppressions != null) && suppressions.suppressed(ppt)) { 117 StringEqual inv = proto.instantiate_dyn(ppt); 118 // System.out.printf("%s is suppressed in ppt %s%n", inv.format(), ppt.name()); 119 return inv; 120 } 121 122 return null; 123 } 124 125 @Override 126 public String repr(@GuardSatisfied StringEqual this) { 127 return "StringEqual" + varNames(); 128 } 129 130 @SideEffectFree 131 @Override 132 public String format_using(@GuardSatisfied StringEqual this, OutputFormat format) { 133 134 String var1name = var1().name_using(format); 135 String var2name = var2().name_using(format); 136 137 if ((format == OutputFormat.DAIKON) || (format == OutputFormat.ESCJAVA)) { 138 String comparator = "=="; 139 return var1name + " " + comparator + " " + var2name; 140 } 141 142 if (format == OutputFormat.CSHARPCONTRACT) { 143 144 assert var1().has_typeof() == var2().has_typeof(); 145 if (var1().has_typeof()) { 146 return var1name + " == " + var2name; 147 } else { 148 return var1name + ".Equals(" + var2name + ")"; 149 } 150 151 } 152 153 if (format.isJavaFamily()) { 154 155 assert var1().has_typeof() == var2().has_typeof(); 156 if (var1().has_typeof()) { 157 return var1name + " == " + var2name; 158 } else { 159 return var1name + ".equals(" + var2name + ")"; 160 } 161 162 } 163 164 if (format == OutputFormat.SIMPLIFY) { 165 166 String comparator = "EQ"; 167 168 return "(" 169 + comparator 170 + " " 171 + var1().simplifyFixup(var1name) 172 + " " 173 + var2().simplifyFixup(var2name) 174 + ")"; 175 } 176 177 return format_unimplemented(format); 178 } 179 180 @Override 181 public InvariantStatus check_modified(@Interned String v1, @Interned String v2, int count) { 182 if (!((v1 != null) && ( v2 != null) && (v1 == v2))) { 183 return InvariantStatus.FALSIFIED; 184 } 185 return InvariantStatus.NO_CHANGE; 186 } 187 188 @Override 189 public InvariantStatus add_modified(@Interned String v1, @Interned String v2, int count) { 190 if (logDetail() || debug.isLoggable(Level.FINE)) { 191 log( 192 debug, 193 "add_modified (" + v1 + ", " + v2 + ", ppt.num_values = " + ppt.num_values() + ")"); 194 } 195 if ((logOn() || debug.isLoggable(Level.FINE)) 196 && check_modified(v1, v2, count) == InvariantStatus.FALSIFIED) 197 log(debug, "destroy in add_modified (" + v1 + ", " + v2 + ", " + count + ")"); 198 199 return check_modified(v1, v2, count); 200 } 201 202 // This is very tricky, because whether two variables are equal should 203 // presumably be transitive, but it's not guaranteed to be so when using 204 // this method and not dropping out all variables whose values are ever 205 // missing. 206 @Override 207 protected double computeConfidence() { 208 // Should perhaps check number of samples and be unjustified if too few 209 // samples. 210 211 // We MUST check if we have seen samples; otherwise we get 212 // undesired transitivity with missing values. 213 if (ppt.num_samples() == 0) { 214 return Invariant.CONFIDENCE_UNJUSTIFIED; 215 } 216 217 // It's an equality invariant. I ought to use the actual ranges somehow. 218 // Actually, I can't even use this .5 test because it can make 219 // equality non-transitive. 220 // return Math.pow(.5, num_values()); 221 return Invariant.CONFIDENCE_JUSTIFIED; 222 223 } 224 225 @Override 226 public boolean enoughSamples(@GuardSatisfied StringEqual this) { 227 return ppt.num_samples() > 0; 228 } 229 230 // For Comparison interface, which is satisfied only by exact equalities. 231 @Override 232 public double eq_confidence() { 233 if (isExact()) { 234 return getConfidence(); 235 } else { 236 return Invariant.CONFIDENCE_NEVER; 237 } 238 } 239 240 @Pure 241 @Override 242 public boolean isExact() { 243 244 return true; 245 } 246 247 // // Temporary, for debugging 248 // public void destroy() { 249 // if (debug.isLoggable(Level.FINE)) { 250 // System.out.println("StringEqual.destroy(" + ppt.name() + ")"); 251 // System.out.println(repr()); 252 // (new Error()).printStackTrace(); 253 // } 254 // super.destroy(); 255 // } 256 257 @Override 258 public InvariantStatus add( 259 @Interned Object v1, @Interned Object v2, int mod_index, int count) { 260 if (debug.isLoggable(Level.FINE)) { 261 debug.fine( 262 "StringEqual" 263 + ppt.varNames() 264 + ".add(" 265 + v1 266 + "," 267 + v2 268 + ", mod_index=" 269 + mod_index 270 + "), count=" 271 + count 272 + ")"); 273 } 274 return super.add(v1, v2, mod_index, count); 275 } 276 277 @Pure 278 @Override 279 public boolean isSameFormula(Invariant other) { 280 return true; 281 } 282 283 @Pure 284 @Override 285 public boolean isExclusiveFormula(Invariant other) { 286 287 // Also ought to check against LinearBinary, etc. 288 289 if ((other instanceof StringLessThan) 290 || (other instanceof StringGreaterThan) 291 || (other instanceof StringNonEqual)) { 292 return true; 293 } 294 295 return false; 296 } 297 298 @Override 299 public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) { 300 final VarInfo var1 = vis[0]; 301 final VarInfo var2 = vis[1]; 302 303 // If A.minvalue==A.maxvalue==B.minvalue==B.maxvalue, then 304 // there's nothing to see here. 305 if (var1.aux.hasValue(VarInfoAux.MINIMUM_VALUE) 306 && var1.aux.hasValue(VarInfoAux.MAXIMUM_VALUE) 307 && var2.aux.hasValue(VarInfoAux.MINIMUM_VALUE) 308 && var2.aux.hasValue(VarInfoAux.MAXIMUM_VALUE)) { 309 @SuppressWarnings("all:argument") // EnsuresKeyFor for multiple maps; also https://tinyurl.com/cfissue/2586 310 int minA = var1.aux.getInt(VarInfoAux.MINIMUM_VALUE), 311 maxA = var1.aux.getInt(VarInfoAux.MAXIMUM_VALUE), 312 minB = var2.aux.getInt(VarInfoAux.MINIMUM_VALUE), 313 maxB = var2.aux.getInt(VarInfoAux.MAXIMUM_VALUE); 314 315 if (minA == maxA && maxA == minB && minB == maxB) { 316 return new DiscardInfo( 317 this, DiscardCode.obvious, var1.name() + " == " + var2.name() + " is already known"); 318 } 319 } 320 321 return super.isObviousStatically(vis); 322 } 323 324 /** 325 * Since this invariant can be a postProcessed equality, we have to handle isObvious especially to 326 * avoid circular isObvious relations. We only check if this.ppt.var_infos imply obviousness 327 * rather than the cartesian product on the equality set. 328 */ 329 @Pure 330 @Override 331 public @Nullable DiscardInfo isObviousStatically_SomeInEquality() { 332 if (var1().equalitySet == var2().equalitySet) { 333 return isObviousStatically(this.ppt.var_infos); 334 } else { 335 return super.isObviousStatically_SomeInEquality(); 336 } 337 } 338 339 /** 340 * Since this invariant can be a postProcessed equality, we have to handle isObvious especially to 341 * avoid circular isObvious relations. We only check if this.ppt.var_infos imply obviousness 342 * rather than the cartesian product on the equality set. 343 */ 344 @Pure 345 @Override 346 public @Nullable DiscardInfo isObviousDynamically_SomeInEquality() { 347 if (var1().equalitySet == var2().equalitySet) { 348 return isObviousDynamically(this.ppt.var_infos); 349 } else { 350 return super.isObviousDynamically_SomeInEquality(); 351 } 352 } 353 354 @Pure 355 @Override 356 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 357 358 // JHP: We might consider adding a check over bounds. If 359 // x < c and y > c then we know that x < y. Similarly for 360 // x > c and y < c. We could also substitute oneof for 361 // one or both of the bound checks. 362 363 DiscardInfo super_result = super.isObviousDynamically(vis); 364 if (super_result != null) { 365 return super_result; 366 } 367 368 @SuppressWarnings("UnusedVariable") // generated code, variable is sometimes used 369 DiscardInfo di; 370 371 // Check for size(A[]) == Size(B[]) where A[] == B[] 372 di = array_eq_implies(vis); 373 if (di != null) { 374 return di; 375 } 376 377 return null; 378 } // isObviousDynamically 379 380 /** 381 * If the equality is between two array size variables, check to see if the underlying arrays are 382 * equal: 383 * 384 * <pre>(x[] = y[]) ⇒ size(x[]) = size(y[])</pre> 385 */ 386 private @Nullable DiscardInfo array_eq_implies(VarInfo[] vis) { 387 388 // Make sure v1 and v2 are size(array) with the same shift 389 VarInfo v1 = vis[0]; 390 if (!v1.isDerived() || !(v1.derived instanceof SequenceLength)) { 391 return null; 392 } 393 VarInfo v2 = vis[1]; 394 if (!v2.isDerived() || !(v2.derived instanceof SequenceLength)) { 395 return null; 396 } 397 if (!v1.derived.isSameFormula(v2.derived)) { 398 return null; 399 } 400 401 VarInfo seqvar1 = v1.derived.getBase(0); 402 VarInfo seqvar2 = v2.derived.getBase(0); 403 if (ppt.parent.is_equal(seqvar1, seqvar2)) { 404 return new DiscardInfo( 405 this, 406 DiscardCode.obvious, 407 "Implied by " 408 + seqvar1 409 + " == " 410 + seqvar2 411 + " and " 412 + var1() 413 + " == " 414 + v1 415 + " and " 416 + var2() 417 + " == " 418 + v2); 419 } 420 421 return null; 422 } 423 424 /** NI suppressions, initialized in get_ni_suppressions() */ 425 private static @Nullable NISuppressionSet suppressions = null; 426 427 /** Returns the non-instantiating suppressions for this invariant. */ 428 @Pure 429 @Override 430 public @Nullable NISuppressionSet get_ni_suppressions() { 431 return null; 432 } 433 434}