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