001// MultiDiffVisitor.java 002 003package daikon.diff; 004 005import daikon.PptMap; 006import daikon.inv.Invariant; 007import daikon.inv.OutputFormat; 008import java.io.OutputStream; 009import java.io.PrintStream; 010import java.util.ArrayList; 011import java.util.HashMap; 012import java.util.HashSet; 013import java.util.Map; 014import java.util.StringTokenizer; 015import org.checkerframework.checker.nullness.qual.KeyFor; 016import org.checkerframework.checker.nullness.qual.NonNull; 017import org.checkerframework.checker.nullness.qual.Nullable; 018import org.plumelib.util.CollectionsPlume; 019 020/** 021 * <B>MultiDiffVisitor</B> is a state-storing NodeVisitor that works across multiple files 022 * regardless of the current two-file infrastructure. This allows the selection of very unique 023 * invariants that occur once over an entire set of trace files. 024 */ 025public class MultiDiffVisitor extends PrintNullDiffVisitor { 026 027 protected PptMap currMap; 028 private HashSet<String> programPointsList; 029 private HashMap<String, Integer> freqList; 030 private HashSet<String> justifiedList; 031 private int total = 0; 032 private static boolean spinfoMode = false; 033 private static PrintStream out = System.out; 034 035 public MultiDiffVisitor(PptMap firstMap) { 036 // I'll always want System.out, and never verbose! 037 super(System.out, false); 038 currMap = firstMap; 039 programPointsList = new HashSet<String>(); 040 freqList = new HashMap<>(); 041 justifiedList = new HashSet<String>(); 042 } 043 044 public static void setForSpinfoOut(OutputStream out_os) { 045 MultiDiffVisitor.out = new PrintStream(out_os, true); 046 spinfoMode = true; 047 } 048 049 @Override 050 public void visit(RootNode node) { 051 052 total++; 053 super.visit(node); 054 } 055 056 @Override 057 public void visit(InvNode node) { 058 Invariant inv1 = node.getInv1(); 059 Invariant inv2 = node.getInv2(); 060 061 // Use the histogram map 062 if (inv1 != null && shouldPrint(inv1, inv2)) { 063 String tmpStr = inv1.ppt.name(); 064 // example: 065 // tmpStr == FeedTheCat.measure(III)I:::ENTER(b, this.bCap 066 String thisPptName = tmpStr.substring(0, tmpStr.lastIndexOf('(')); 067 068 programPointsList.add(thisPptName); 069 String key = thisPptName + "$" + inv1.format_using(OutputFormat.JAVA); 070 Integer val = freqList.get(key); 071 if (val == null) { 072 // Use one as default, obviously 073 freqList.put(key, 1); 074 } else { 075 // increment if it's already there 076 freqList.put(key, val.intValue() + 1); 077 } 078 079 // add to justified list if this was justified once 080 // if (inv1.justified()) { 081 justifiedList.add(key); 082 // } 083 } 084 } 085 086 /** Prints everything in the goodList. */ 087 public void printAll() { 088 089 if (spinfoMode) { 090 printAllSpinfo(); 091 return; 092 } 093 094 // keeps track of suppressed invariants due to appearing in 095 // every sample of the MultiDiff 096 int kill = 0; 097 int unjustifiedKill = 0; 098 ArrayList<String> bigList = new ArrayList<>(); 099 100 // New historgram stuff 101 System.out.println("Histogram**************"); 102 103 // This gets all of the output in the format: 104 // inv.ppt.name() + "$" + inv1.format_java() + " Count = " + freq 105 for (String str : freqList.keySet()) { 106 int freq = freqList.get(str).intValue(); 107 if (freq < total && justifiedList.contains(str)) { 108 bigList.add(str + " Count = " + freq); 109 // System.out.println (str + " Count = " + freq); 110 111 } 112 // don't print something true in EVERY set 113 else if (freq == total) { 114 kill++; 115 } else { 116 // don't print something that was never justified 117 unjustifiedKill++; 118 } 119 } 120 System.out.println("Invariants appearing in all: " + kill); 121 System.out.println("Invariants never justified: " + unjustifiedKill); 122 123 // Now build the final HashMap that will have the following 124 // mapping: program point names -> 125 // ArrayList of inv.format_java() with frequency 126 127 HashMap<String, ArrayList<String>> lastMap = new HashMap<>(); 128 // One pass to fill each mapping with an empty ArrayList 129 for (String key : programPointsList) { 130 lastMap.put(key, new ArrayList<String>()); 131 } 132 133 // Now to populate those ArrayLists 134 for (String str : bigList) { 135 StringTokenizer st = new StringTokenizer(str, "$"); 136 String key = st.nextToken(); // a Ppt name 137 String data = st.nextToken(); 138 try { 139 @SuppressWarnings("nullness") // map 140 @NonNull ArrayList<String> formatAndFrequencyList = lastMap.get(key); 141 formatAndFrequencyList.add(data); 142 } catch (Exception e) { 143 System.out.println(key + " error in MultiDiffVisitor"); 144 } 145 } 146 147 // print it all 148 for (Map.Entry<@KeyFor("lastMap") String, ArrayList<String>> entry : lastMap.entrySet()) { 149 String key = entry.getKey(); 150 ArrayList<String> al = entry.getValue(); 151 // don't print anything if there are no selective invariants 152 if (al.size() == 0) { 153 continue; 154 } 155 System.out.println(); 156 System.out.println(key + "*****************"); 157 System.out.println(); 158 for (Object toPrint : al) { 159 System.out.println(toPrint); 160 } 161 } 162 System.out.println(); 163 System.out.println(); 164 } 165 166 /** Prints everything in the goodList, outputs as spinfo. */ 167 public void printAllSpinfo() { 168 169 // keeps track of suppressed invariants due to appearing in 170 // every sample of the MultiDiff 171 ArrayList<String> bigList = new ArrayList<>(); 172 173 // This gets all of the output in the format: 174 // inv.ppt.name() + "$" + inv1.format_java() 175 for (String str : freqList.keySet()) { 176 int freq = freqList.get(str).intValue(); 177 if (freq < total && justifiedList.contains(str)) { 178 // just want the String on its own line 179 bigList.add(str); 180 } 181 } 182 183 // Now build the final HashMap that will have the following 184 // mapping: program point names -> 185 // ArrayList of inv.format_java() with frequency 186 187 HashMap<String, ArrayList<String>> lastMap = new HashMap<>(); 188 // One pass to fill each mapping with an empty ArrayList 189 for (String key : programPointsList) { 190 lastMap.put(key, new ArrayList<String>()); 191 } 192 193 // Now to populate those ArrayLists 194 for (String str : bigList) { 195 StringTokenizer st = new StringTokenizer(str, "$"); 196 String key = st.nextToken(); 197 String data = st.nextToken(); 198 try { 199 @SuppressWarnings("nullness") // map 200 @NonNull ArrayList<String> formatAndFrequencyList = lastMap.get(key); 201 formatAndFrequencyList.add(data); 202 } catch (Exception e) { 203 out.println(key + " error in MultiDiffVisitor"); 204 } 205 } 206 207 // print it all 208 String lastPpt = ""; 209 // sort them so that multiple exits will end up being adjacent 210 // to each other when they are from the same method 211 for (@KeyFor("lastMap") String key : CollectionsPlume.sortedKeySet(lastMap)) { 212 ArrayList<String> al = lastMap.get(key); 213 // don't print anything if there are no selective invariants 214 215 if (al.size() == 0) { 216 continue; 217 } 218 219 // Get rid of the extra stuff like (III)I:::ENTER 220 // at the end of each of the program points 221 222 // use the fact that we only want the stuff before the first '(' 223 StringTokenizer pToke = new StringTokenizer(key, "("); 224 225 // sadly we only want EXIT values, so throw out any ENTERs 226 // because the spinfo won't deal well with them anyway 227 228 // if (key.indexOf ("ENTER") != -1) continue; 229 230 // Now we don't want to reprint the program point name 231 // again in the spinfo file if it has been printed from 232 // the previous Ppt that exited at a different point -LL 233 234 String thisPpt = pToke.nextToken(); 235 236 if (!lastPpt.equals(thisPpt)) { 237 out.println(); 238 out.println("PPT_NAME " + thisPpt); 239 240 lastPpt = thisPpt; 241 } 242 for (Object toPrint : al) { 243 out.println(toPrint); 244 } 245 } 246 } 247 248 @Override 249 protected boolean shouldPrint(@Nullable Invariant inv1, @Nullable Invariant inv2) { 250 return true; // super.shouldPrint (inv1, inv2) && 251 // inv1.format().toString().indexOf(">") == -1 && 252 // inv1.format().toString().indexOf("orig") == -1; 253 } 254}