/** Eliminates all non-normal variables from varInfos. See isNormalVar() for details. */ private static VarInfo[] filterNonVars(VarInfo[] varInfos) { List<VarInfo> filteredList = new ArrayList<VarInfo>(); for (int i = 0; i < varInfos.length; i++) { if (isNormalVar(varInfos[i])) { filteredList.add(varInfos[i]); } else { // System.out.println("filterNonVars removed " + varInfos[i].name.name()); } } return filteredList.toArray(new VarInfo[0]); }
/** * Creates a new instance of VariableManager. * * @param varInfos the varInfos for the variables to be managed. * @param condition the condition in which the variables are used. */ private static VariableManager[] makeVariableManagerArray( VarInfo[] varInfos, String condition, String className) throws ParseException { List<VariableManager> variableManagerList = new ArrayList<VariableManager>(); List<String> classVars = findPossibleClassVariables(condition); for (int i = 0; i < varInfos.length; i++) { VarInfo varInfo = varInfos[i]; try { String compilableName = compilableName(varInfo, className); // System.out.println("varInfo " + varInfo.name.name() + ", compilableName=" + // compilableName + ", isNeeded=" + isNeeded(compilableName, classVars)); if (isNeeded(compilableName, classVars)) { variableManagerList.add(new VariableManager(varInfo, condition, className)); } } catch (ParseException e) { System.out.println("ParseException: " + e.toString()); } } return variableManagerList.toArray(new VariableManager[0]); }
/** * requires: condition is a string representation of a conditional * * @return a list of all possible variable variable names in condition. arrays appear with "[]" at * the end if their elements or accessed in the condition. */ private static List<String> findPossibleClassVariables(String condition) throws ParseException { NodeToken[] tokens = TokenExtractor.extractTokens(condition); // System.out.println("TokenExtractor.extractTokens(" + condition + ") ==> " + // ArraysMDE.toString(tokens)); List<String> variables = new ArrayList<String>(); if (tokens.length >= 1) { if (tokens[0].kind == IDENTIFIER && (tokens.length <= 1 || tokens[1].kind != LPAREN)) { variables.add(tokens[0].tokenImage); } } if (tokens.length >= 2) { if (tokens[1].kind == IDENTIFIER && (tokens.length <= 2 || tokens[2].kind != LPAREN) && (!variables.contains(tokens[1].tokenImage))) { variables.add(tokens[1].tokenImage); } } for (int i = 2; i < tokens.length - 1; i++) { NodeToken token = tokens[i]; if (token.kind == IDENTIFIER && tokens[i - 1].kind != DOT && tokens[i + 1].kind != LPAREN && (!variables.contains(token.tokenImage))) { variables.add(token.tokenImage); } } if (tokens.length >= 3) { int lastIndex = tokens.length - 1; if (tokens[lastIndex].kind == IDENTIFIER && tokens[lastIndex - 1].kind != DOT && (!variables.contains(tokens[lastIndex].tokenImage))) { variables.add(tokens[lastIndex].tokenImage); } } // System.out.println("findPossibleClassVariables(" + condition + ") ==> " + // variables.toString()); return variables; }
/** * Extract consequents from a implications at a single program point. It only searches for top * level Program points because Implications are produced only at those points. */ public static void extract_consequent_maybe(PptTopLevel ppt, PptMap all_ppts) { ppt.simplify_variable_names(); List<Invariant> invs = new ArrayList<Invariant>(); if (invs.size() > 0) { String pptname = cleanup_pptname(ppt.name()); for (Invariant maybe_as_inv : invs) { Implication maybe = (Implication) maybe_as_inv; // don't print redundant invariants. if (Daikon.suppress_redundant_invariants_with_simplify && maybe.ppt.parent.redundant_invs.contains(maybe)) { continue; } // don't print out invariants with min(), max(), or sum() variables boolean mms = false; VarInfo[] varbls = maybe.ppt.var_infos; for (int v = 0; !mms && v < varbls.length; v++) { mms |= varbls[v].isDerivedSequenceMinMaxSum(); } if (mms) { continue; } if (maybe.ppt.parent.ppt_name.isExitPoint()) { for (int i = 0; i < maybe.ppt.var_infos.length; i++) { VarInfo vi = maybe.ppt.var_infos[i]; if (vi.isDerivedParam()) { continue; } } } Invariant consequent = maybe.consequent(); Invariant predicate = maybe.predicate(); Invariant inv, cluster_inv; boolean cons_uses_cluster = false, pred_uses_cluster = false; // extract the consequent (predicate) if the predicate // (consequent) uses the variable "cluster". Ignore if they // both depend on "cluster" if (consequent.usesVarDerived("cluster")) cons_uses_cluster = true; if (predicate.usesVarDerived("cluster")) pred_uses_cluster = true; if (!(pred_uses_cluster ^ cons_uses_cluster)) { continue; } else if (pred_uses_cluster) { inv = consequent; cluster_inv = predicate; } else { inv = predicate; cluster_inv = consequent; } if (!inv.isInteresting()) { continue; } if (!inv.isWorthPrinting()) { continue; } if (contains_constant_non_012(inv)) { continue; } // filter out unwanted invariants // 1) Invariants involving sequences if (inv instanceof daikon.inv.binary.twoSequence.TwoSequence || inv instanceof daikon.inv.binary.sequenceScalar.SequenceScalar || inv instanceof daikon.inv.binary.sequenceString.SequenceString || inv instanceof daikon.inv.unary.sequence.SingleSequence || inv instanceof daikon.inv.unary.stringsequence.SingleStringSequence) { continue; } if (inv instanceof daikon.inv.ternary.threeScalar.LinearTernary || inv instanceof daikon.inv.binary.twoScalar.LinearBinary) { continue; } String inv_string = inv.format_using(OutputFormat.JAVA); if (orig_pattern.matcher(inv_string).find() || dot_class_pattern.matcher(inv_string).find()) { continue; } String fake_inv_string = simplify_inequalities(inv_string); HashedConsequent real = new HashedConsequent(inv, null); if (!fake_inv_string.equals(inv_string)) { // For instance, inv_string is "x != y", fake_inv_string is "x == y" HashedConsequent fake = new HashedConsequent(inv, inv_string); boolean added = store_invariant( cluster_inv.format_using(OutputFormat.JAVA), fake_inv_string, fake, pptname); if (!added) { // We couldn't add "x == y", (when we're "x != y") because // it already exists; so don't add "x == y" either. continue; } } store_invariant(cluster_inv.format_using(OutputFormat.JAVA), inv_string, real, pptname); } } }
/** * This does the work of main, but it never calls System.exit, so it is appropriate to be called * progrmmatically. Termination of the program with a message to the user is indicated by throwing * Daikon.TerminationMessage. * * @see #main(String[]) * @see daikon.Daikon.TerminationMessage */ public static void mainHelper(final String[] args) throws FileNotFoundException, StreamCorruptedException, OptionalDataException, IOException, ClassNotFoundException { daikon.LogHelper.setupLogs(daikon.LogHelper.INFO); LongOpt[] longopts = new LongOpt[] { new LongOpt(Daikon.config_option_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(output_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(dir_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(conf_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(filter_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.ppt_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; Getopt g = new Getopt("daikon.tools.InvariantChecker", args, "h", longopts); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); if (Daikon.help_SWITCH.equals(option_name)) { System.out.println(usage); throw new Daikon.TerminationMessage(); } else if (conf_SWITCH.equals(option_name)) { doConf = true; } else if (filter_SWITCH.equals(option_name)) { doFilter = true; } else if (dir_SWITCH.equals(option_name)) { dir_file = new File(g.getOptarg()); if (!dir_file.exists() || !dir_file.isDirectory()) throw new Daikon.TerminationMessage("Error reading the directory " + dir_file); } else if (output_SWITCH.equals(option_name)) { output_file = new File(g.getOptarg()); output_stream = new PrintStream(new FileOutputStream(output_file)); } else if (Daikon.config_option_SWITCH.equals(option_name)) { String item = g.getOptarg(); daikon.config.Configuration.getInstance().apply(item); break; } else if (Daikon.debugAll_SWITCH.equals(option_name)) { Global.debugAll = true; } else if (Daikon.debug_SWITCH.equals(option_name)) { LogHelper.setLevel(g.getOptarg(), LogHelper.FINE); } else if (Daikon.track_SWITCH.equals(option_name)) { LogHelper.setLevel("daikon.Debug", LogHelper.FINE); String error = Debug.add_track(g.getOptarg()); if (error != null) { throw new Daikon.TerminationMessage( "Error parsing track argument '" + g.getOptarg() + "' - " + error); } } else { throw new RuntimeException("Unknown long option received: " + option_name); } break; case 'h': System.out.println(usage); throw new Daikon.TerminationMessage(); case '?': break; // getopt() already printed an error default: System.out.println("getopt() returned " + c); break; } } // Loop through each filename specified for (int i = g.getOptind(); i < args.length; i++) { // Get the file and make sure it exists File file = new File(args[i]); if (!file.exists()) { throw new Error("File " + file + " not found."); } // These aren't "endsWith()" because there might be a suffix on the end // (eg, a date). String filename = file.toString(); if (filename.indexOf(".inv") != -1) { if (inv_file != null) { throw new Daikon.TerminationMessage("multiple inv files specified", usage); } inv_file = file; } else if (filename.indexOf(".dtrace") != -1) { dtrace_files.add(filename); } else { throw new Error("Unrecognized argument: " + file); } } if (dir_file == null) { checkInvariants(); return; } // Yoav additions: File[] filesInDir = dir_file.listFiles(); if (filesInDir == null || filesInDir.length == 0) throw new Daikon.TerminationMessage("The directory " + dir_file + " is empty", usage); ArrayList<File> invariants = new ArrayList<File>(); for (File f : filesInDir) if (f.toString().indexOf(".inv") != -1) invariants.add(f); if (invariants.size() == 0) throw new Daikon.TerminationMessage( "Did not find any invariant files in the directory " + dir_file, usage); ArrayList<File> dtraces = new ArrayList<File>(); for (File f : filesInDir) if (f.toString().indexOf(".dtrace") != -1) dtraces.add(f); if (dtraces.size() == 0) throw new Daikon.TerminationMessage( "Did not find any dtrace files in the directory " + dir_file, usage); System.out.println( "Collecting data for invariants files " + invariants + " and dtrace files " + dtraces); dtrace_files.clear(); for (File dtrace : dtraces) { dtrace_files.add(dtrace.toString()); } String commaLine = ""; for (File inFile : invariants) { String name = inFile.getName().replace(".inv", "").replace(".gz", ""); commaLine += "," + name; } outputComma.add(commaLine); commaLine = ""; for (File inFile : invariants) { inv_file = inFile; failedInvariants.clear(); testedInvariants.clear(); error_cnt = 0; output_stream = new PrintStream( new FileOutputStream( inFile.toString().replace(".inv", "").replace(".gz", "") + ".false-positives.txt")); checkInvariants(); output_stream.close(); int failedCount = failedInvariants.size(); int testedCount = testedInvariants.size(); String percent = toPercentage(failedCount, testedCount); commaLine += "," + percent; } outputComma.add(commaLine); System.out.println(); for (String output : outputComma) System.out.println(output); }
/** Returns true if the variable represented by varInfo is used in this splitting condition. */ private static boolean isNeeded(String name, List<String> vars) { return vars.contains(name); }