001package daikon.diff; 002 003import daikon.Global; 004import daikon.Ppt; 005import daikon.inv.Invariant; 006import java.io.PrintStream; 007import java.text.DecimalFormat; 008import org.checkerframework.checker.nullness.qual.Nullable; 009 010/** Prints all the invariant pairs, including pairs containing identical invariants. */ 011public class PrintAllVisitor extends DepthFirstVisitor { 012 013 // Protected so subclasses can use it. 014 protected static final String lineSep = Global.lineSep; 015 016 protected static boolean HUMAN_OUTPUT = false; 017 018 private static DecimalFormat CONFIDENCE_FORMAT = new DecimalFormat("0.####"); 019 020 private PrintStream ps; 021 private boolean verbose; 022 private boolean printEmptyPpts; 023 024 /** 025 * Stores the output generated when visiting invariant nodes. This output cannot be printed 026 * directly to the print stream, because the Ppt output must come before the Invariant output. 027 */ 028 private StringBuilder bufOutput = new StringBuilder(); 029 030 public PrintAllVisitor(PrintStream ps, boolean verbose, boolean printEmptyPpts) { 031 this.ps = ps; 032 this.verbose = verbose; 033 this.printEmptyPpts = printEmptyPpts; 034 } 035 036 /** Prints the pair of program points, and all the invariants contained within them. */ 037 @Override 038 public void visit(PptNode node) { 039 // Empty the string buffer 040 bufOutput.setLength(0); 041 042 super.visit(node); 043 044 if (bufOutput.length() > 0 || printEmptyPpts) { 045 Ppt ppt1 = node.getPpt1(); 046 Ppt ppt2 = node.getPpt2(); 047 048 ps.print("<"); 049 if (ppt1 == null) { 050 ps.print((@Nullable String) null); 051 } else { 052 ps.print(ppt1.name()); 053 } 054 055 if (ppt1 == null || ppt2 == null || !ppt1.name().equals(ppt2.name())) { 056 ps.print(", "); 057 if (ppt2 == null) { 058 ps.print((@Nullable String) null); 059 } else { 060 ps.print(ppt2.name()); 061 } 062 } 063 ps.println(">"); 064 ps.print(bufOutput.toString()); 065 } 066 } 067 068 /** Prints a pair of invariants. Includes the type of the invariants and their relationship. */ 069 @Override 070 public void visit(InvNode node) { 071 072 if (HUMAN_OUTPUT) { 073 printHumanOutput(node); 074 return; 075 } 076 077 Invariant inv1 = node.getInv1(); 078 Invariant inv2 = node.getInv2(); 079 080 bufPrint(" <"); 081 082 if (inv1 == null) { 083 bufPrint(null); 084 } else { 085 printInvariant(inv1); 086 } 087 bufPrint(", "); 088 if (inv2 == null) { 089 bufPrint((@Nullable String) null); 090 } else { 091 printInvariant(inv2); 092 } 093 bufPrint(">"); 094 095 int arity = DetailedStatisticsVisitor.determineArity(inv1, inv2); 096 String arityLabel = DetailedStatisticsVisitor.ARITY_LABELS[arity]; 097 int rel = DetailedStatisticsVisitor.determineRelationship(inv1, inv2); 098 String relLabel = DetailedStatisticsVisitor.RELATIONSHIP_LABELS[rel]; 099 100 bufPrint(" (" + arityLabel + "," + relLabel + ")"); 101 102 bufPrintln(); 103 } 104 105 /** 106 * This method is an alternate printing procedure for an InvNode so that the output is more human 107 * readable. The format resembles cvs diff with '+' and '-' signs for the differing invariants. 108 * There is no information on justification or invariant type. 109 */ 110 public void printHumanOutput(InvNode node) { 111 112 Invariant inv1 = node.getInv1(); 113 Invariant inv2 = node.getInv2(); 114 115 // bufPrint(" <"); 116 117 if (inv1 != null && inv2 != null && inv1.format().equals(inv2.format())) { 118 return; 119 } 120 121 if (inv1 == null) { 122 // bufPrint((String) null); 123 } else { 124 // printInvariant(inv1); 125 bufPrintln(("- " + inv1.format()).trim()); 126 } 127 // bufPrint(", "); 128 if (inv2 == null) { 129 // bufPrint((String) null); 130 } else { 131 bufPrintln(("+ " + inv2.format()).trim()); 132 // printInvariant(inv2); 133 } 134 // bufPrint(">"); 135 136 // int arity = DetailedStatisticsVisitor.determineArity(inv1, inv2); 137 // int rel = DetailedStatisticsVisitor.determineRelationship(inv1, inv2); 138 // String arityLabel = DetailedStatisticsVisitor.ARITY_LABELS[arity]; 139 // String relLabel = DetailedStatisticsVisitor.RELATIONSHIP_LABELS[rel]; 140 // bufPrint(" (" + arityLabel + "," + relLabel + ")"); 141 142 bufPrintln(); 143 } 144 145 /** 146 * Prints an invariant, including its printability and possibly its confidence. Example: "argv != 147 * null {0.9999+}". 148 */ 149 protected void printInvariant(Invariant inv) { 150 if (verbose) { 151 bufPrint(inv.repr_prob()); 152 bufPrint(" {"); 153 printPrintability(inv); 154 bufPrint("}"); 155 } else { 156 bufPrint(inv.format()); 157 bufPrint(" {"); 158 printConfidence(inv); 159 printPrintability(inv); 160 bufPrint("}"); 161 } 162 } 163 164 /** 165 * Prints the confidence of the invariant. Confidences between .9999 and 1 are rounded to .9999. 166 */ 167 private void printConfidence(Invariant inv) { 168 double conf = inv.getConfidence(); 169 if (.9999 < conf && conf < 1) { 170 conf = .9999; 171 } 172 bufPrint(CONFIDENCE_FORMAT.format(conf)); 173 } 174 175 /** Prints '+' if the invariant is worth printing, '-' otherwise. */ 176 // XXX This routine takes up most of diff's run time on large .inv 177 // files, and is not particularly interesting. There should perhaps 178 // be an option to turn it off. -SMcC 179 private void printPrintability(Invariant inv) { 180 if (inv.isWorthPrinting()) { 181 bufPrint("+"); 182 } else { 183 bufPrint("-"); 184 } 185 } 186 187 // "prints" by appending to a string buffer 188 protected void bufPrint(@Nullable String s) { 189 bufOutput.append(s); 190 } 191 192 protected void bufPrintln(@Nullable String s) { 193 bufPrint(s); 194 bufPrintln(); 195 } 196 197 protected void bufPrintln() { 198 bufOutput.append(Global.lineSep); 199 } 200}