001package daikon.inv; 002 003import daikon.PptSlice; 004import daikon.PptTopLevel; 005import daikon.VarInfo; 006import daikon.split.PptSplitter; 007import java.util.Arrays; 008import java.util.List; 009import java.util.logging.Level; 010import java.util.logging.Logger; 011import org.checkerframework.checker.formatter.qual.FormatMethod; 012import org.checkerframework.checker.initialization.qual.UnknownInitialization; 013import org.checkerframework.checker.lock.qual.GuardSatisfied; 014import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; 015import org.checkerframework.checker.nullness.qual.Nullable; 016import org.checkerframework.dataflow.qual.Pure; 017import org.checkerframework.dataflow.qual.SideEffectFree; 018import typequals.prototype.qual.NonPrototype; 019import typequals.prototype.qual.Prototype; 020 021// Here Implication is reimplemented as an extension of the new general 022// Joiner class 023 024/** 025 * The Implication invariant class is used internally within Daikon to handle invariants that are 026 * only true when certain other conditions are also true (splitting). 027 */ 028public class Implication extends Joiner { 029 static final long serialVersionUID = 20030822L; 030 031 // orig_left and orig_right are the original invariants, in the original 032 // context (the parent of the conditional ppt where predicate and 033 // consequent appear). predicate and consequent might be permuted from 034 // the original. orig_left and orig_right are used in computeConfidence, 035 // and orig_right is used in isObvious*. 036 /** The original predicate invariant from its original conditional ppt. */ 037 private Invariant orig_left; 038 039 /** 040 * The original consequent invariant from its original conditional ppt. Or, right itself if right 041 * is a DummyInvariant from a splitter file. 042 */ 043 private Invariant orig_right; 044 045 public Invariant predicate() { 046 return left; 047 } 048 049 public Invariant consequent() { 050 return right; 051 } 052 053 public boolean iff; 054 055 protected Implication( 056 PptSlice ppt, 057 Invariant predicate, 058 Invariant consequent, 059 boolean iff, 060 Invariant orig_predicate, 061 Invariant orig_consequent) { 062 super(ppt, predicate, consequent); 063 assert (predicate != null); 064 assert (consequent != null); 065 assert (orig_predicate != null); 066 assert (orig_consequent != null); 067 this.iff = iff; 068 this.orig_left = orig_predicate; 069 this.orig_right = orig_consequent; 070 } 071 072 /** 073 * Creates a new Implication Invariant and adds it to the PptTopLevel. 074 * 075 * @return null if predicate and the consequent are the same, or if the PptTopLevel already 076 * contains this Implication 077 */ 078 public static @Nullable Implication makeImplication( 079 PptTopLevel ppt, 080 Invariant predicate, 081 Invariant consequent, 082 boolean iff, 083 Invariant orig_predicate, 084 Invariant orig_consequent) { 085 if (predicate.isSameInvariant(consequent)) { 086 PptSplitter.debug.fine( 087 "Not creating implication (pred==conseq): " + predicate + " ==> " + consequent); 088 return null; 089 } 090 091 Implication result = 092 new Implication( 093 ppt.joiner_view, predicate, consequent, iff, orig_predicate, orig_consequent); 094 095 // Don't add this Implication to the program point if the program 096 // point already has this implication. 097 if (ppt.joiner_view.hasImplication(result)) { 098 return null; 099 } 100 101 if (PptSplitter.debug.isLoggable(Level.FINE)) { 102 PptSplitter.debug.fine("Creating implication " + predicate + " ==> " + consequent); 103 } 104 return result; 105 } 106 107 @Override 108 protected double computeConfidence() { 109 double pred_conf = orig_left.computeConfidence(); 110 double cons_conf = orig_right.computeConfidence(); 111 if ((pred_conf == CONFIDENCE_NEVER) || (cons_conf == CONFIDENCE_NEVER)) { 112 return CONFIDENCE_NEVER; 113 } 114 double result = confidence_and(pred_conf, cons_conf); 115 log("Confidence %s %s/%s for %s", result, pred_conf, cons_conf, format()); 116 return result; 117 } 118 119 @Override 120 public String repr(@GuardSatisfied Implication this) { 121 return "[Implication: " + left.repr() + " => " + right.repr() + "]"; 122 } 123 124 @SideEffectFree 125 @Override 126 public String format_using(@GuardSatisfied Implication this, OutputFormat format) { 127 String pred_fmt = left.format_using(format); 128 String consq_fmt = right.format_using(format); 129 if (format == OutputFormat.DAIKON || format == OutputFormat.JML) { 130 String arrow = (iff ? " <==> " : " ==> "); // "interned" 131 return "(" + pred_fmt + ")" + arrow + "(" + consq_fmt + ")"; 132 } else if (format == OutputFormat.ESCJAVA) { 133 String arrow = (iff ? " == " : " ==> "); // "interned" 134 return "(" + pred_fmt + ")" + arrow + "(" + consq_fmt + ")"; 135 } else if (format == OutputFormat.JAVA) { 136 String mid = (iff ? " == " : " || !"); // "interned" 137 return "(" + consq_fmt + ")" + mid + "(" + pred_fmt + ")"; 138 } else if (format == OutputFormat.SIMPLIFY) { 139 String cmp = (iff ? "IFF" : "IMPLIES"); 140 return "(" + cmp + " " + pred_fmt + " " + consq_fmt + ")"; 141 } else if (format == OutputFormat.DBCJAVA) { 142 if (iff) { 143 return "((" + pred_fmt + ") == (" + consq_fmt + "))"; 144 } else { 145 return "(" + pred_fmt + " $implies " + consq_fmt + ")"; 146 } 147 } else if (format == OutputFormat.CSHARPCONTRACT) { 148 if (iff) { 149 return "(" + pred_fmt + ") == (" + consq_fmt + ")"; 150 } else { 151 return "(" + pred_fmt + ").Implies(" + consq_fmt + ")"; 152 } 153 } else { 154 return format_unimplemented(format); 155 } 156 } 157 158 @Pure 159 @Override 160 public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) { 161 assert vis.length > 0; 162 for (int ii = 0; ii < vis.length; ii++) { 163 assert vis[ii] != null; 164 } 165 return orig_right.isObviousStatically(vis); 166 } 167 168 @Pure 169 @Override 170 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 171 assert vis.length > 0; 172 for (int ii = 0; ii < vis.length; ii++) { 173 assert vis[ii] != null; 174 } 175 DiscardInfo di = orig_right.isObviousDynamically(vis); 176 if (di != null) { 177 log("failed isObviousDynamically with vis = %s", Arrays.toString(vis)); 178 return di; 179 } 180 181 return null; 182 } 183 184 /** 185 * Return true if the right side of the implication and some equality combinations of its member 186 * variables are statically obvious. For example, if a == b, and f(a) is obvious, then so is f(b). 187 * We use the someInEquality (or least interesting) method during printing so we only print an 188 * invariant if all its variables are interesting, since a single, static, non interesting 189 * occurance means all the equality combinations aren't interesting. 190 * 191 * <p>This must be overridden for Implication because the right side is the invariant of interest. 192 * The standard version passes the vis from the slice containing the implication itself (slice 0). 193 */ 194 @Pure 195 @Override 196 public @Nullable DiscardInfo isObviousStatically_SomeInEquality() { 197 return orig_right.isObviousStatically_SomeInEquality(); 198 // DiscardInfo result = isObviousStatically (orig_right.ppt.var_infos); 199 // if (result != null) { 200 // return result; 201 // } 202 // assert orig_right.ppt.var_infos.length > 0; 203 // for (int ii = 0; ii < orig_right.ppt.var_infos.length; ii++ ) 204 // assert orig_right.ppt.var_infos[ii] != null; 205 // return isObviousStatically_SomeInEqualityHelper (orig_right.ppt.var_infos, 206 // new VarInfo[orig_right.ppt.var_infos.length], 0); 207 } 208 209 /** 210 * Return true if the rightr side of the implication some equality combinations of its member 211 * variables are dynamically obvious. For example, a == b, and f(a) is obvious, so is f(b). We use 212 * the someInEquality (or least interesting) method during printing so we only print an invariant 213 * if all its variables are interesting, since a single, dynamic, non interesting occurance means 214 * all the equality combinations aren't interesting. 215 * 216 * <p>This must be overridden for Implication because the right side is the invariant of interest. 217 * The standard version passes the vis from the slice containing the implication itself (slice 0). 218 */ 219 @Pure 220 @Override 221 public @Nullable DiscardInfo isObviousDynamically_SomeInEquality() { 222 223 // If the consequent is ni-suppressed in its original program point, 224 // then it is obvious from some set of other invariants. Those invariants 225 // could be other implications or they could be true at both conditional 226 // points. 227 // JHP: Seemingly it would be better if this invariant was never 228 // created, but somehow that creates other implications. See the 229 // disabled code in PptSplitter.add_implication() 230 if (orig_right.is_ni_suppressed()) { 231 return new DiscardInfo( 232 this, DiscardCode.obvious, "consequent " + orig_right.format() + " is ni suppressed"); 233 } 234 235 return orig_right.isObviousDynamically_SomeInEquality(); 236 // DiscardInfo result = isObviousDynamically (orig_right.ppt.var_infos); 237 // if (result != null) 238 // return result; 239 // return isObviousDynamically_SomeInEqualityHelper (orig_right.ppt.var_infos, 240 // new VarInfo[right.ppt.var_infos.length], 0); 241 } 242 243 @Pure 244 @Override 245 public boolean isSameFormula(Invariant other) { 246 Implication other_implic = (Implication) other; 247 return (iff == other_implic.iff) && super.isSameFormula(other_implic); 248 } 249 250 @EnsuresNonNullIf(result = true, expression = "#1") 251 @Pure 252 @Override 253 public boolean isSameInvariant(Invariant other) { 254 if (other == null) { 255 return false; 256 } 257 if (!(other instanceof Implication)) { 258 return false; 259 } 260 if (iff != ((Implication) other).iff) { 261 return false; 262 } 263 return super.isSameInvariant(other); 264 } 265 266 // If a constant managed to appear in a predicate, that's 267 // interesting enough for us. 268 @Override 269 public boolean hasUninterestingConstant() { 270 return consequent().hasUninterestingConstant(); 271 } 272 273 @Pure 274 @Override 275 public boolean isAllPrestate() { 276 return predicate().isAllPrestate() && consequent().isAllPrestate(); 277 } 278 279 // Using `@link` leads to javadoc -Xdoclint:all crashing with: 280 // "com.sun.tools.javac.code.Type$AnnotatedType cannot be cast to 281 // com.sun.tools.javac.code.Type$ClassType" 282 /** 283 * Logs a description of the invariant and the specified msg via the logger as described in {@code 284 * daikon.Debug#log(Logger, Class, Ppt, VarInfo[], String)}. Uses the consequent as the logger. 285 */ 286 @Override 287 public void log( 288 /*NOT: @UnknownInitialization(Implication.class) Implication this,*/ Logger log, String msg) { 289 290 right.log( 291 log, 292 msg 293 + "[for implication " 294 + format() 295 + " (" 296 + (orig_right == null ? "null" : orig_right.format()) 297 + ")]"); 298 } 299 300 // Using `@link` leads to javadoc -Xdoclint:all crashing with: 301 // "com.sun.tools.javac.code.Type$AnnotatedType cannot be cast to 302 // com.sun.tools.javac.code.Type$ClassType" 303 /** 304 * Logs a description of the invariant and the specified msg via the logger as described in {@code 305 * daikon.Debug#log(Logger, Class, Ppt, VarInfo[], String)}. Uses the consequent as the logger. 306 * 307 * @return whether or not it logged anything 308 */ 309 @Override 310 @FormatMethod 311 @SuppressWarnings({ 312 "nullness:override.receiver", // sound overriding, not expressible in Checker Framework 313 }) 314 public boolean log( 315 @UnknownInitialization(Implication.class) Implication this, 316 String format, 317 @Nullable Object... args) { 318 String msg = (args.length == 0) ? format : String.format(format, args); 319 @SuppressWarnings("nullness:method.invocation") 320 String formatted = format(); 321 return right.log( 322 "%s [for implication %s (%s)]", 323 msg, formatted, (orig_right == null ? "null" : orig_right.format())); 324 } 325 326 @Override 327 public boolean enabled(@Prototype Implication this) { 328 throw new Error("do not invoke " + getClass() + ".enabled()"); 329 } 330 331 @Override 332 public boolean valid_types(@Prototype Implication this, VarInfo[] vis) { 333 throw new Error("do not invoke " + getClass() + ".valid_types()"); 334 } 335 336 @Override 337 protected @NonPrototype Invariant instantiate_dyn(@Prototype Implication this, PptSlice slice) { 338 throw new Error("do not invoke " + getClass() + ".instantiate_dyn()"); 339 } 340 341 @Override 342 public @Nullable @NonPrototype Implication merge( 343 @Prototype Implication this, List<@NonPrototype Invariant> invs, PptSlice parent_ppt) { 344 throw new Error("do not merge implications"); 345 } 346}