/* * e-Knife, a program slicing tool for Erlang based on the EDG * Copyright (c) 2021. David Insa, Sergio PĂ©rez, Josep Silva, Salvador Tamarit. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ package eknife; import edg.DotFactory; import edg.EDGFactory; import edg.PdfFactory; import edg.graph.EDG; import edg.graph.Edge; import edg.graph.LAST; import edg.graph.Node; import edg.slicing.*; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.*; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.*; public class EKnife { public enum Language { Java, Erlang, Php } public static void main(String[] args) { if (args.length == 0) { EKnife.printHelp(); return; } final Args arguments = EKnife.processArguments(args); if (!arguments.isValid()) { EKnife.printHelp(); System.exit(3); } EKnife.run(arguments); } private static Args processArguments(String[] args) { Args kArgs = new Args(); for (int argIndex = 0; argIndex < args.length; argIndex++) { final String arg = args[argIndex]; switch (arg) { case "-i": case "--input": case "-o": case "--output": case "-f": case "--file": case "-l": case "--line": case "-v": case "--var": case "-n": case "--occurrence": case "-G": case "--print-graph": if (argIndex == args.length - 1) { System.out.printf("Parameter %s requires an argument\n", arg); printHelp(); System.exit(1); } } switch (arg) { case "--help": printHelp(); System.exit(0); case "-i": case "--input": kArgs.inputPath = args[argIndex + 1]; break; case "-o": case "--output": kArgs.outputFile = new File(args[argIndex + 1]); break; case "-f": case "--file": kArgs.file = args[argIndex + 1]; break; case "-l": case "--line": kArgs.line = Integer.parseInt(args[argIndex + 1]); break; case "-v": case "--var": kArgs.name = args[argIndex + 1]; break; case "-n": case "--occurrence": kArgs.occurrence = Integer.parseInt(args[argIndex + 1]); break; case "-G": case "--print-graph": kArgs.setGraphFile(new File(args[argIndex + 1])); break; } } kArgs.completeData(); return kArgs; } private static void printHelp() { String help = ""; help += "Use the following options:\n"; help += " -i,--input The file/folder where the source code is\n"; help += " -o,--output The file/folder where the slice will be stored\n"; help += " -f,--file The file (relative to -i) where the slicing criterion is\n"; help += " -l,--line The line of the slicing criterion\n"; help += " -v,--var The name of the slicing criterion (must be a variable)\n"; help += " -n,--occurrence The occurrence of the slicing criterion in that line\n"; help += " -G,--print-graph Exports the graph as a dot file\n"; help += " -G,--print-graph Exports the graph as a PDF file\n"; help += " --help Show this message.\n"; System.out.print(help); } private static void run(Args a) { // boolean showIP = false; // Map edgeFlags = new HashMap<>(); // edgeFlags.put(Edge.Type.Value, true); // edgeFlags.put(Edge.Type.ControlFlow, false); // edgeFlags.put(Edge.Type.Control, false); // edgeFlags.put(Edge.Type.Flow, false); // edgeFlags.put(Edge.Type.Input, showIP); // edgeFlags.put(Edge.Type.Call, showIP); // edgeFlags.put(Edge.Type.Output, showIP); // edgeFlags.put(Edge.Type.Summary, false); final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true); //DotFactory.createDot(new File("/Users/serperu/Desktop/SlicerOutput/graph.dot"), new EDG(last), edgeFlags); // PdfFactory.createPdf(new File("/Users/serperu/Desktop/SlicerOutput/last.pdf"), new EDG(last), edgeFlags); final EDG edg = new EDGFactory(last).createEDG(); // edg.getGrammar().printGrammarInFile("/Users/serperu/Desktop/SlicerOutput/grammar.txt"); // DotFactory.createDot(new File("/Users/serperu/Desktop/SlicerOutput/graph.dot"), new EDG(last), edgeFlags); final SlicingCriterion slicingCriterion = new SlicingCriterion(a.file, a.line, a.name, a.occurrence); final Node SC = edg.getNode(slicingCriterion); if (SC == null) { System.out.println("Error: the slicing criterion could not be found! " + slicingCriterion); System.exit(1); } // final SlicingAlgorithm slicingAlgorithm = new AdaptedStandardAlgorithm(edg); final SlicingAlgorithm slicingAlgorithm = new OnePassConstrainedAlgorithm(edg); final Set slice = slicingAlgorithm.slice(SC); if (slice.isEmpty()) { System.out.println("Warning: no files will be written, as the slice is empty."); System.exit(2); } // DotFactory.createDot(new File("/Users/serperu/Desktop/SlicerOutput/graphSliced.dot"), edg, SC, slice, edgeFlags); // PdfFactory.createPdf(new File("/Users/serperu/Desktop/SlicerOutput/graphSliced.pdf"), edg, SC, slice, edgeFlags); if (a.graphFile != null) { switch (a.graphFormat) { case DOT: DotFactory.createDot(a.graphFile, edg, SC, slice); break; case PDF: PdfFactory.createPdf(a.graphFile, edg, SC, slice); break; } } CodeFactory.createCode(Language.Erlang, a.outputFile, edg, slice); } private static void timedRun(Args a) { // CONFIGURE MEASURED DIMENSIONS boolean measureGenerationTime = true; boolean measureNodes = false; boolean performAllSCs = true; /* ***************************************************** */ /* ** MEASUREMENT OF GENERATION TIME (100 executions) ** */ /* ***************************************************** */ int numberOfIterations = 100; if (measureGenerationTime) { double[] StructuralTime = new double[numberOfIterations]; double[] CFGTime = new double[numberOfIterations]; double[] ValueTime = new double[numberOfIterations]; double[] CompositeTime = new double[numberOfIterations]; double[] ControlTime = new double[numberOfIterations]; double[] FlowTime = new double[numberOfIterations]; double[] IPTime = new double[numberOfIterations]; // double totalStructural, totalCFG, totalValue, totalComposite, totalControl, totalFlow; // totalStructural = totalCFG = totalValue = totalComposite = totalControl = totalFlow = 0.0; double[] standardTime = new double[numberOfIterations]; double[] constrainedTime = new double[numberOfIterations]; for (int i = -1; i < numberOfIterations; i++) { final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true); final EDG edg = new EDGFactory(last).createEDG(); if (i == -1) continue; // totalStructural += edg.getGenerationTime().getStructureTime(); // totalCFG += edg.getGenerationTime().getControlFlowTime(); // totalValue += edg.getGenerationTime().getValueTime(); // totalComposite += edg.getGenerationTime().getCompositeTime(); // totalControl += edg.getGenerationTime().getControlTime(); // totalFlow += edg.getGenerationTime().getFlowTime(); StructuralTime[i] = edg.getGenerationTime().getStructureTime(); CFGTime[i] = edg.getGenerationTime().getControlFlowTime(); ValueTime[i] = edg.getGenerationTime().getValueTime(); CompositeTime[i] = edg.getGenerationTime().getCompositeTime(); ControlTime[i] = edg.getGenerationTime().getControlTime(); FlowTime[i] = edg.getGenerationTime().getFlowTime(); IPTime[i] = edg.getGenerationTime().getInterproceduralTime(); standardTime[i] = StructuralTime[i] + CFGTime[i] + ValueTime[i] - CompositeTime[i] + ControlTime[i] + FlowTime[i] + IPTime[i]; constrainedTime[i] = StructuralTime[i] + CFGTime[i] + ValueTime[i] + ControlTime[i] + FlowTime[i] + IPTime[i]; // printArray("/Users/serperu/Desktop/SlicerOutput/Times/ArrayContent.txt",constrainedTime); } // double totalStructural, totalCFG, totalValue, totalControl, totalFlow; // totalStructural = totalCFG = totalValue = totalControl = totalFlow = 0.0; // for (int i = 0; i < 100; i++){ // totalStructural += StructuralTime[i]; // totalCFG += CFGTime[i]; // totalValue += ValueTime[i]; // totalControl += ControlTime[i]; // totalFlow += FlowTime[i]; // } // INTRAPROCEDURAL GENERATION TIME // TIME MEASSUREMENT: printCSVGenerationTime(a.file, standardTime, constrainedTime); // printGenerationTime(a.file, numberOfIterations, totalStructural, totalCFG, totalValue, // totalComposite, totalControl, totalFlow, false); // printGenerationTime(a.file, numberOfIterations, totalStructural, totalCFG, totalValue, // totalComposite, totalControl, totalFlow, true); } final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true); final EDG edg = new EDGFactory(last).createEDG(); /* *************************** */ /* ** MEASUREMENT OF NODES: ** */ /* *************************** */ if (measureNodes) { int SDGNodeCounter = countSDGNodes(edg); int EDGNodeCounter = countEDGNodes(edg); printNodeCounter(a.file, SDGNodeCounter, EDGNodeCounter); } /* ************************ */ /* ** MEASUREMENT OF SCs ** */ /* ************************ */ if (performAllSCs) { // SC SELECTION List clauses = edg.getNodes(Node.Type.Clause); clauses.removeIf(c -> edg.getParent(c).getType() != Node.Type.Routine); // printHeadings("/Users/serperu/Desktop/SlicerOutput/Times/slicingStatistics.txt", a.file); for (Node clause : clauses) { int arity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size(); String functionName = edg.getParent(clause).getName() + "/" + arity; // printFunction("/Users/serperu/Desktop/SlicerOutput/Times/slicingStatistics.txt", edg.getParent(clause).getName() + "/" + arity); List descendants = edg.getDescendants(clause); descendants.add(clause); List resultNodes = new LinkedList<>(); List nonResultNodes = new LinkedList<>(); for (Node n : descendants) if (n.getType() == Node.Type.Result) { if (edg.getNodeFromRes(n).getType() != Node.Type.Callee) resultNodes.add(n); } else nonResultNodes.add(n); nonResultNodes.add(clause); resultNodes.add(edg.getResFromNode(clause)); // IGNORE FUNCTIONS WITHOUT COMPOSITE STRUCTURES if (nonResultNodes.stream() .noneMatch( n -> { if (n.getType() == Node.Type.DataConstructor) return true; if (n.getType() == Node.Type.List) if (edg.getChildren(n).size() != 0 || edg.getParent(n).getType() == Node.Type.List) return true; return false;})) { System.out.println("File Name: " + a.file); int functionArity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size(); System.out.println("Function " + edg.getParent(clause).getName() + "/" + functionArity + " has no valid slicing criteria."); continue; } /* FILTER SC NODES BY A CRITERION (CONSIDER ONLY VARIABLES) */ resultNodes.removeIf(n -> edg.getNodeFromRes(n).getType() != Node.Type.Variable); // SlicingCriterionState[] allCriteriaStandard = new SlicingCriterionState[resultNodes.size()]; // SlicingCriterionState[] allCriteriaConstrained = new SlicingCriterionState[resultNodes.size()]; // CONFIGURE MEASURED DIMENSIONS boolean measureSlicingTime = true; boolean measureSlicingPerformance = true; final SlicingAlgorithm standardAlgorithm = new AdaptedStandardAlgorithm(edg); final SlicingAlgorithm constrainedAlgorithm = new ConstrainedAlgorithm(edg); int scCounter = 0; int scConstrainedImprovements = 0; double[] stdAvgArray = new double[resultNodes.size()]; double[] consAvgArray = new double[resultNodes.size()]; double[] stdVarArray = new double[resultNodes.size()]; double[] consVarArray = new double[resultNodes.size()]; int[] standardNodes = new int[resultNodes.size()]; int[] constrainedNodes = new int[resultNodes.size()]; for (Node SC : resultNodes) { // INITIALIZATIONS // PERFORMANCE double standardSlicePercentage = 0.0; double constrainedSlicePercentage = 0.0; // TIME double totalStandardTime = 0.0; double totalConstrainedTime = 0.0; double[] standardTime = new double[numberOfIterations]; double[] constrainedTime = new double[numberOfIterations]; // MEASURE TIME FOR EACH SC if (measureSlicingTime) { for (int j = -1; j < numberOfIterations; j++) { long initialStandardTime = System.nanoTime(); standardAlgorithm.slice(SC); long finalStandardTime = System.nanoTime(); if (j == -1) continue; standardTime[j] = (finalStandardTime - initialStandardTime) / 1000.0; totalStandardTime += standardTime[j]; } for (int j = -1; j < numberOfIterations; j++){ long initialConstrainedTime = System.nanoTime(); constrainedAlgorithm.slice(SC); long finalConstrainedTime = System.nanoTime(); if (j == -1) continue; constrainedTime[j] = (finalConstrainedTime - initialConstrainedTime) / 1000.0 ; totalConstrainedTime += constrainedTime[j]; } // COMPUTE AVG stdAvgArray[scCounter] = totalStandardTime / numberOfIterations; consAvgArray[scCounter] = totalConstrainedTime / numberOfIterations; // COMPUTE VARIANCE double varianceAccStd = 0.0; double varianceAccCons = 0.0; // printArray("/Users/serperu/Desktop/SlicerOutput/Times/ArrayContent.txt",constrainedTime); for (int l = 0; l < numberOfIterations; l++) { varianceAccStd += Math.pow((standardTime[l] - stdAvgArray[scCounter]), 2); varianceAccCons += Math.pow((constrainedTime[l] - consAvgArray[scCounter]), 2); } stdVarArray[scCounter] = varianceAccStd / numberOfIterations; consVarArray[scCounter] = varianceAccCons / numberOfIterations; } // MEASURE PERFORMARNCE final Set standardSlice = standardAlgorithm.slice(SC); final Set constrainedSlice = constrainedAlgorithm.slice(SC); if (measureSlicingPerformance) { standardSlice.removeIf(n -> n.getType() == Node.Type.Result); standardSlicePercentage = standardSlice.size() * 100.0 / nonResultNodes.size(); constrainedSlice.removeIf(n -> n.getType() == Node.Type.Result); constrainedSlicePercentage = constrainedSlice.size() * 100.0 / nonResultNodes.size(); standardNodes[scCounter] = standardSlice.size(); constrainedNodes[scCounter] = constrainedSlice.size(); if (constrainedSlice.size() < standardSlice.size()) scConstrainedImprovements++; if (standardSlicePercentage < constrainedSlicePercentage) throw new IllegalStateException("The SDG cannot be more precise than the EDG"); } // allCriteriaStandard[scCounter] = new SlicingCriterionState(standardSlicePercentage, 0); // allCriteriaConstrained[scCounter] = new SlicingCriterionState(constrainedSlicePercentage, 0); scCounter++; } int edgNodes = (int) edg.vertexSet().stream() .filter(n -> n.getType() != Node.Type.Result) .count(); printEachSCData(a.file, functionName, stdAvgArray, stdVarArray, consAvgArray, consVarArray, edgNodes, standardNodes, constrainedNodes); // int arity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size(); // printSlicingResults(edg.getParent(clause).getName() + "/" + arity, // resultNodes.size(), allCriteriaStandard, allCriteriaConstrained, // scConstrainedImprovements, measureSlicingPerformance, measureSlicingTime); } } // DotFactory.createDot(new File("/Users/serperu/Desktop/SlicerOutput/graphSliced.dot"), edg, SC, slice, edgeFlags); // CodeFactory.createCode(Language.Erlang, a.outputFile, edg, slice); } private static void sliceGenerationRun(Args a) { final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true); final EDG edg = new EDGFactory(last).createEDG(); int scFunctionCounter = 0; /* ************************ */ /* ** MEASUREMENT OF SCs ** */ /* ************************ */ // SC SELECTION List clauses = edg.getNodes(Node.Type.Clause); clauses.removeIf(c -> edg.getParent(c).getType() != Node.Type.Routine); // printHeadings("/Users/serperu/Desktop/SlicerOutput/Times/slicingStatistics.txt", a.file); for (Node clause : clauses) { Map functionCriteria = new HashMap<>(); List descendants = edg.getDescendants(clause); descendants.add(clause); List resultNodes = new LinkedList<>(); List nonResultNodes = new LinkedList<>(); for (Node n : descendants) if (n.getType() == Node.Type.Result) { if (edg.getNodeFromRes(n).getType() != Node.Type.Callee) resultNodes.add(n); } else nonResultNodes.add(n); nonResultNodes.add(clause); resultNodes.add(edg.getResFromNode(clause)); // IGNORE FUNCTIONS WITHOUT COMPOSITE STRUCTURES if (nonResultNodes.stream() .noneMatch( n -> { if (n.getType() == Node.Type.DataConstructor) return true; if (n.getType() == Node.Type.List) if (edg.getChildren(n).size() != 0 || edg.getParent(n).getType() == Node.Type.List) return true; return false;})) { System.out.println("File Name: " + a.file); int functionArity = edg.getChildrenNonResult(edg.getChild(clause, Node.Type.Parameters)).size(); System.out.println("Function " + edg.getParent(clause).getName() + "/" + functionArity + " has no valid slicing criteria."); continue; } /* FILTER SC NODES BY A CRITERION (CONSIDER ONLY VARIABLES) */ resultNodes.removeIf(n -> edg.getNodeFromRes(n).getType() != Node.Type.Variable); String moduleName = edg.getParent(edg.getParent(clause)).getName(); new File(outputSliceGenerationFolder+moduleName).mkdirs(); final SlicingAlgorithm standardAlgorithm = new AdaptedTwoPassStandardAlgorithm(edg); final SlicingAlgorithm constrainedAlgorithm = new ConstrainedAlgorithm(edg); for (Node SC : resultNodes) { // System.out.println("ID: "+SC.getId()+" Line: "+SC.getInfo().getLine()+" Name "+edg.getNodeFromRes(SC).getName()); Node normalNodeSC = edg.getNodeFromRes(SC); String scString = "<"+normalNodeSC.getInfo().getLine()+","+normalNodeSC.getName()+">"; functionCriteria.put("#"+scFunctionCounter,scString); // MEASURE PERFORMARNCE final Set standardSlice = standardAlgorithm.slice(SC); // final Set constrainedSlice = constrainedAlgorithm.slice(SC); // PDG PRINT CodeFactory.createCode(Language.Erlang, new File(outputSliceGenerationFolder+moduleName+"/SDG"+"#"+scFunctionCounter+".erl"), edg, standardSlice); // CE-PDG PRINT // CodeFactory.createCode(Language.Erlang, // new File(outputSliceGenerationFolder+moduleName+"/CE-SDG"+"#"+scFunctionCounter+".erl"), // edg, constrainedSlice); scFunctionCounter++; } try { File txt = new File(outputSliceGenerationFolder+moduleName+"/criteria_map.txt"); txt.createNewFile(); FileWriter fw = new FileWriter(txt,true); for(String k : functionCriteria.keySet()){ fw.append(k +" => "+ functionCriteria.get(k)+"\n"); } fw.close(); } catch (IOException e) { System.out.println("An error occurred."); e.printStackTrace(); } } } public static int countSDGNodes(EDG edg) { Node root = edg.getRootNode(); return countSDGNodes(edg, root); } public static int countSDGNodes(EDG edg, Node node) { int counter = 1; List children = edg.getChildren(node); for (Node child : children) { if (child.getType() == Node.Type.Result) continue; if (child.getType() == Node.Type.List ||child.getType() == Node.Type.DataConstructor) counter++; else { counter += countSDGNodes(edg, child); } } return counter; } public static int countEDGNodes(EDG edg) { Set nodes = new HashSet<>(); nodes.addAll(edg.vertexSet()); nodes.removeIf(n -> n.getType() == Node.Type.Result); return nodes.size(); } /* *********************** *********************** *********************** *********************** */ /* *********************** ****************** PRINT METHODS ************** *********************** */ /* *********************** *********************** *********************** *********************** */ public static void printCSVGenerationTime(String file, double[] stdTimes, double[] consTimes){ FileWriter timeFileWriter; PrintWriter timeWriter = null; int numberOfElems = stdTimes.length; try { timeFileWriter = new FileWriter(graphGenerationCsv, true); timeWriter = new PrintWriter(timeFileWriter); for (int i = 0; i < numberOfElems; i++) timeWriter.printf("%s;GEN_%d;%.5f;%.5f\n",file,i,stdTimes[i],consTimes[i]); } catch (IOException e) { System.out.println("FILE NOT FOUND ERROR"); } finally { if (timeWriter != null) timeWriter.close(); } } public static void printNodeCounter(String programName, int SDGNodes, int EDGNodes) { FileWriter timeFileWriter; PrintWriter timeWriter = null; try { timeFileWriter = new FileWriter(nodeCounterFile, true); timeWriter = new PrintWriter(timeFileWriter); timeWriter.println("---------------------------"); timeWriter.println("Program Name: " + programName); timeWriter.println("---------------------------"); timeWriter.println(" SDG Nodes: " + SDGNodes); timeWriter.println(" EDG Nodes: " + EDGNodes + "\n"); } catch (IOException e) { System.out.println("FILE NOT FOUND ERROR"); } finally { if (timeWriter != null) timeWriter.close(); } } public static void printHeadings(String outputFile1, String outputFile2){ FileWriter timeFileWriter; PrintWriter timeWriter = null; try { timeFileWriter = new FileWriter(outputFile1, true); timeWriter = new PrintWriter(timeFileWriter); timeWriter.println("PROGRAM;GEN_NUMBER;STD_AVG_GEN_TIME;CONS_GEN_TIME"); } catch (IOException e) { System.out.println("FILE NOT FOUND ERROR"); } finally { if (timeWriter != null) timeWriter.close(); } try { timeFileWriter = new FileWriter(outputFile2, true); timeWriter = new PrintWriter(timeFileWriter); timeWriter.println("PROGRAM;FUNCTION;SC;STD_AVG;STD_VAR;CONS_AVG;CONS_VAR;FUNC_NODES;STD_NODES;CONS_NODES"); } catch (IOException e) { System.out.println("FILE NOT FOUND ERROR"); } finally { if (timeWriter != null) timeWriter.close(); } } public static void printEachSCData(String file, String funName, double[] stdAvg, double[] stdVar, double[] consAvg, double[] consVar, int funNodeSize, int[] stdNodeSize, int[] consNodeSize) { FileWriter timeFileWriter; PrintWriter timeWriter = null; int numberOfElems = stdAvg.length; try { timeFileWriter = new FileWriter(sliceGenerationCsv, true); timeWriter = new PrintWriter(timeFileWriter); for (int i = 0; i < numberOfElems; i++) { timeWriter.printf("%s;%s;SC_%d;%.5f;%.5f;%.5f;%.5f;%d;%d;%d\n",file,funName,i,stdAvg[i],stdVar[i], consAvg[i],consVar[i],funNodeSize,stdNodeSize[i],consNodeSize[i]); } } catch (IOException e) { System.out.println("FILE NOT FOUND ERROR"); } finally { if (timeWriter != null) timeWriter.close(); } } // public static void printEachSCData(String file, String funName, int funNodeSize) { // // FileWriter timeFileWriter; // PrintWriter timeWriter = null; // try { // timeFileWriter = new FileWriter(sliceGenerationCsv, true); // timeWriter = new PrintWriter(timeFileWriter); // timeWriter.printf("%s;%s;%d\n",file,funName,funNodeSize); // // } catch (IOException e) { // System.out.println("FILE NOT FOUND ERROR"); // } finally { // if (timeWriter != null) // timeWriter.close(); // } // } /* *********************** *********************** *********************** *********************** */ /* *********************** *********************** *********************** *********************** */ /* *********************** *********************** *********************** *********************** */ static class Args { enum GraphFormat { PDF, DOT } String inputPath; File outputFile; String file; int line; String name; int occurrence = 1; File graphFile; GraphFormat graphFormat; void setGraphFile(File graphFile) { if (graphFile.getName().endsWith(".dot")) graphFormat = GraphFormat.DOT; else if (graphFile.getName().endsWith(".pdf")) graphFormat = GraphFormat.PDF; else { System.out.println("The graph file must end in .dot or .pdf, you set it to " + graphFile); System.exit(1); } this.graphFile = graphFile; } void completeData() { if (file == null && inputPath != null && new File(inputPath).isFile()) file = new File(inputPath).getName(); } boolean isValid() { List errors = new LinkedList<>(); if (inputPath == null) errors.add("You must specify a file to analyze with '-i'."); else if (!new File(inputPath).exists()) errors.add("The input file you've specified does not exist or isn't readable(" + inputPath + ")."); else if (file == null) errors.add("The input file is a folder, so you must specify a the file that contains the slicing criterion with '-f'."); if (outputFile == null) errors.add("You must specify a location for the output with '-o'."); else if (!outputFile.exists() && !outputFile.getAbsoluteFile().getParentFile().isDirectory()) errors.add("The output file's parent folder does not exist, or the output folder does not exist."); if (line <= 0) errors.add("You must specify a line number greater than 0 with '-l'."); if (name == null || name.isEmpty()) errors.add("You must specify a valid variable name with '-v'."); if (occurrence <= 0) errors.add("You must specify an occurrence greater than 0 with '-n'."); for (String error : errors) System.out.println(error); return errors.isEmpty(); } } public static class SlicingCriterionState{ private final double slicingPerformance; private final double slicingTime; public SlicingCriterionState(double performance, double time) { slicingPerformance = performance; slicingTime = time; } public double getPerformance() { return this.slicingPerformance; } public double getTime() { return this.slicingTime; } } }