diff --git a/.gitignore b/.gitignore index d627c53c44b41750991e76b0b5c0a6300840fa36..ac48bd7604e2575a2691a9ffde715b5b1b4667c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,176 @@ +# Created by https://www.gitignore.io/api/java,linux,macos,maven,intellij +# Edit at https://www.gitignore.io/?templates=java,linux,macos,maven,intellij + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +.idea + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +.idea/modules.xml +.idea/*.iml +.idea/modules *.iml -.idea/ -target/ +*.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ out/ -.settings + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# End of https://www.gitignore.io/api/java,linux,macos,maven,intellij .attach* diff --git a/.gitmodules b/.gitmodules index 46394f31083b0e1b8c7e764a168cf31eca891e60..ee5ecc4b02d0fb2fde48ac80e034d213d2fe97c9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "src/test/res/java-slicing-benchmarks"] - path = src/test/res/java-slicing-benchmarks - url = kaz:repos/java-slicing-benchmarks.git +[submodule "sdg-core/src/test/res/java-slicing-benchmarks"] + path = sdg-core/src/test/res/java-slicing-benchmarks + url = https://kaz.dsic.upv.es/git/program-slicing/java-benchmarks.git diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..26d33521af10bcc7fd8cea344038eaaeb78d0ef5 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000000000000000000000000000000..2f4b56835b31b2d541d1edbb0aee718d72852d0e --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1 @@ +Manifest-Version: 1.0 diff --git a/pom.xml b/pom.xml index 44ab23ebfbcf34e8a6194830a1a9285f0ec4a27d..ebed3bf8b38659dec4eb6d51d2c217077142e64d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,50 +7,14 @@ tfm tfm 1.0-SNAPSHOT - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - - - - com.github.javaparser - javaparser-symbol-solver-core - 3.9.1 - + + 11 + 11 + - - org.jetbrains - annotations-java5 - RELEASE - compile - - - - org.jgrapht - jgrapht-core - 1.3.0 - - - - org.jgrapht - jgrapht-io - 1.3.0 - - - - org.junit.jupiter - junit-jupiter - RELEASE - test - - - \ No newline at end of file + + sdg-core + sdg-cli + + diff --git a/sdg-cli/pom.xml b/sdg-cli/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..09842784ad5ed95b0c83a4ca5d0b39f06f7bc49a --- /dev/null +++ b/sdg-cli/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + tfm + sdg-cli + 1.0-SNAPSHOT + + + 11 + 11 + + + + + commons-cli + commons-cli + 1.4 + + + com.github.javaparser + javaparser-core + 3.9.1 + + + tfm + sdg-core + 1.0-SNAPSHOT + compile + + + diff --git a/src/main/java/tfm/exec/CFGLog.java b/sdg-cli/src/main/java/tfm/cli/CFGLog.java similarity index 90% rename from src/main/java/tfm/exec/CFGLog.java rename to sdg-cli/src/main/java/tfm/cli/CFGLog.java index 396953513ab30e0b159c91827699ac9bcda04345..af8cf106ce08c098e7832e757db369335c8c25c1 100644 --- a/src/main/java/tfm/exec/CFGLog.java +++ b/sdg-cli/src/main/java/tfm/cli/CFGLog.java @@ -1,4 +1,4 @@ -package tfm.exec; +package tfm.cli; import tfm.graphs.cfg.CFG; diff --git a/src/main/java/tfm/exec/GraphLog.java b/sdg-cli/src/main/java/tfm/cli/GraphLog.java similarity index 99% rename from src/main/java/tfm/exec/GraphLog.java rename to sdg-cli/src/main/java/tfm/cli/GraphLog.java index 0fc1fe2851c2101872fe19290919456190c286ea..baaa4c84415528067dfb4dfaea5a1616dd36a1f9 100644 --- a/src/main/java/tfm/exec/GraphLog.java +++ b/sdg-cli/src/main/java/tfm/cli/GraphLog.java @@ -1,4 +1,4 @@ -package tfm.exec; +package tfm.cli; import tfm.graphs.Graph; import tfm.utils.FileUtil; diff --git a/src/main/java/tfm/exec/PDGLog.java b/sdg-cli/src/main/java/tfm/cli/PDGLog.java similarity index 98% rename from src/main/java/tfm/exec/PDGLog.java rename to sdg-cli/src/main/java/tfm/cli/PDGLog.java index af36803c54f5cf8db6137d44411f37f351ef6278..a50a51ca7d0ef9f24d604de32a9b06ecf951b77c 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/sdg-cli/src/main/java/tfm/cli/PDGLog.java @@ -1,4 +1,4 @@ -package tfm.exec; +package tfm.cli; import tfm.graphs.pdg.PDG; import tfm.nodes.GraphNode; diff --git a/src/main/java/tfm/exec/SDGLog.java b/sdg-cli/src/main/java/tfm/cli/SDGLog.java similarity index 90% rename from src/main/java/tfm/exec/SDGLog.java rename to sdg-cli/src/main/java/tfm/cli/SDGLog.java index cdeae275973139a049d4ddd741318af161a46e24..6c8e3e9fc6ce0beab0858cfc16f232eca7ec3f98 100644 --- a/src/main/java/tfm/exec/SDGLog.java +++ b/sdg-cli/src/main/java/tfm/cli/SDGLog.java @@ -1,4 +1,4 @@ -package tfm.exec; +package tfm.cli; import tfm.graphs.sdg.SDG; diff --git a/sdg-cli/src/main/java/tfm/cli/Slicer.java b/sdg-cli/src/main/java/tfm/cli/Slicer.java new file mode 100644 index 0000000000000000000000000000000000000000..f6c46c9a1a30fc42bd801be041cf412d7e6bb071 --- /dev/null +++ b/sdg-cli/src/main/java/tfm/cli/Slicer.java @@ -0,0 +1,258 @@ +package tfm.cli; + +import com.github.javaparser.JavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.comments.BlockComment; +import com.github.javaparser.ast.nodeTypes.NodeWithName; +import com.github.javaparser.symbolsolver.JavaSymbolSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; +import org.apache.commons.cli.*; +import tfm.graphs.sdg.SDG; +import tfm.slicing.FileLineSlicingCriterion; +import tfm.slicing.Slice; +import tfm.slicing.SlicingCriterion; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Slicer { + protected static final Pattern SC_PATTERN; + protected static final File DEFAULT_OUTPUT_DIR = new File("./slice/"); + protected static final Options OPTIONS = new Options(); + + static { + String fileRe = "(?[^#]+\\.java)"; + String lineRe = "(?[1-9]\\d*)"; + String varsRe = "(?[a-zA-Z_]\\w*(?:,[a-zA-Z_]\\w*)*)"; + String numsRe = "(?[1-9]\\d*(?:,[1-9]\\d*)*)"; + SC_PATTERN = Pattern.compile(fileRe + "#" + lineRe + "(?::" + varsRe + "(?:!" + numsRe + ")?)?"); + } + + static { + OptionGroup criterionOptionGroup = new OptionGroup(); + criterionOptionGroup.addOption(Option + .builder("f").longOpt("file") + .hasArg().argName("CriterionFile.java").type(File.class) + .desc("The file that contains the slicing criterion.") + .build()); + criterionOptionGroup.addOption(Option + .builder("l").longOpt("line") + .hasArg().argName("lineNumber").type(Integer.class) + .desc("The line that contains the statement of the slicing criterion.") + .build()); + criterionOptionGroup.addOption(Option + .builder("v").longOpt("var") + .hasArgs().argName("variableName").valueSeparator(',') + .desc("The name of the variable of the slicing criterion. Not setting this option is" + + " equivalent to selecting an empty set; setting multiple variables is allowed," + + " separated by commas") + .build()); + criterionOptionGroup.addOption(Option + .builder("n").longOpt("number") + .hasArgs().argName("occurrenceNumber").valueSeparator(',') + .desc("The occurrence number of the variable(s) selected. If this argument is not set, it will" + + " default to the first appearance of each variable. If the occurrence number must be set" + + " for every variable in the same order.") + .build()); + OPTIONS.addOptionGroup(criterionOptionGroup); + OPTIONS.addOption(Option + .builder("c").longOpt("criterion") + .hasArg().argName("file#line[:var[!occurrence]]") + .desc("The slicing criterion, in the format \"file#line:var\". Optionally, the occurrence can be" + + " appended as \"!occurrence\". This option replaces \"-f\", \"-l\", \"-v\" and \"-n\", and" + + " functions in a similar way: the variable and occurrence may be skipped or declared multiple times.") + .build()); + OPTIONS.addOption(Option + .builder("i").longOpt("include") + .hasArgs().argName("directory[,directory,...]").valueSeparator(',') + .desc("Includes the directories listed in the search for methods called from the slicing criterion " + + "(directly or transitively). Methods that are not included here or part of the JRE, including" + + " third party libraries will not be analyzed, resulting in less precise slicing.") + .build()); + OPTIONS.addOption(Option + .builder("o").longOpt("output") + .hasArg().argName("outputDir") + .desc("The directory where the sliced source code should be placed. By default, it is placed at " + + DEFAULT_OUTPUT_DIR) + .build()); + OPTIONS.addOption(Option + .builder("h").longOpt("help") + .desc("Shows this text") + .build()); + } + + private final Set dirIncludeSet = new HashSet<>(); + private File outputDir = DEFAULT_OUTPUT_DIR; + private File scFile; + private int scLine; + private final List scVars = new ArrayList<>(); + private final List scVarOccurrences = new ArrayList<>(); + + public Slicer(String... cliArgs) throws ParseException { + CommandLine cl = new DefaultParser().parse(OPTIONS, cliArgs); + if (cl.hasOption('h')) + throw new ParseException(OPTIONS.toString()); + if (cl.hasOption('c')) { + Matcher matcher = SC_PATTERN.matcher(cl.getOptionValue("criterion")); + if (!matcher.matches()) + throw new ParseException("Invalid format for slicing criterion, see --help for more details"); + setScFile(matcher.group("file")); + setScLine(Integer.parseInt(matcher.group("line"))); + String vars = matcher.group("vars"); + String nums = matcher.group("nums"); + if (vars != null) { + if (nums != null) + setScVars(vars.split(","), nums.split(",")); + else + setScVars(vars.split(",")); + } + } else if (cl.hasOption('f') && cl.hasOption('l')) { + setScFile(cl.getOptionValue('f')); + setScLine((Integer) cl.getParsedOptionValue("l")); + if (cl.hasOption('v')) { + if (cl.hasOption('n')) + setScVars(cl.getOptionValues('v'), cl.getOptionValues('n')); + else + setScVars(cl.getOptionValues('v')); + } + } else { + throw new ParseException("Slicing criterion not specified: either use \"-c\" or \"-f\" and \"l\"."); + } + + if (cl.hasOption('o')) + outputDir = (File) cl.getParsedOptionValue("o"); + + if (cl.hasOption('i')) { + for (String str : cl.getOptionValues('i')) { + File dir = new File(str); + if (!dir.isDirectory()) + throw new ParseException("One of the include directories is not a directory or isn't accesible: " + str); + dirIncludeSet.add(dir); + } + } + } + + private void setScFile(String fileName) throws ParseException { + File file = new File(fileName); + if (!(file.exists() && file.isFile())) + throw new ParseException("Slicing criterion file is not an existing file."); + scFile = file; + } + + private void setScLine(int line) throws ParseException { + if (line <= 0) + throw new ParseException("The line of the slicing criterion must be strictly greater than zero."); + scLine = line; + } + + private void setScVars(String[] scVars) throws ParseException { + String[] array = new String[scVars.length]; + Arrays.fill(array, "1"); + setScVars(scVars, array); + } + + private void setScVars(String[] scVars, String[] scOccurrences) throws ParseException { + if (scVars.length != scOccurrences.length) + throw new ParseException("If the number of occurrence is specified, it must be specified once per variable."); + try { + for (int i = 0; i < scVars.length; i++) { + this.scVars.add(scVars[i]); + int n = Integer.parseUnsignedInt(scOccurrences[i]); + if (n <= 0) + throw new ParseException("The number of occurrence must be larger than 0."); + this.scVarOccurrences.add(n); + } + } catch (NumberFormatException e) { + throw new ParseException(e.getMessage()); + } + } + + public Set getDirIncludeSet() { + return Collections.unmodifiableSet(dirIncludeSet); + } + + public File getOutputDir() { + return outputDir; + } + + public File getScFile() { + return scFile; + } + + public int getScLine() { + return scLine; + } + + public List getScVars() { + return Collections.unmodifiableList(scVars); + } + + public List getScVarOccurrences() { + return Collections.unmodifiableList(scVarOccurrences); + } + + public void slice() throws ParseException { + // Configure JavaParser + CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); + combinedTypeSolver.add(new ReflectionTypeSolver(true)); + for (File directory : dirIncludeSet) + combinedTypeSolver.add(new JavaParserTypeSolver(directory)); + JavaParser.getStaticConfiguration().setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver)); + JavaParser.getStaticConfiguration().setAttributeComments(false); + + // Build the SDG + NodeList units = new NodeList<>(); + try { + for (File directory : dirIncludeSet) + units.add(JavaParser.parse(directory)); + CompilationUnit scUnit = JavaParser.parse(scFile); + if (!units.contains(scUnit)) + units.add(scUnit); + } catch (FileNotFoundException e) { + throw new ParseException(e.getMessage()); + } + SDG sdg = new SDG(); + sdg.build(units); + + // Slice the SDG + SlicingCriterion sc = new FileLineSlicingCriterion(scFile, scLine); + Slice slice = sdg.slice(sc); + + // Convert the slice to code and output the result to `outputDir` + for (CompilationUnit cu : slice.toAst()) { + if (cu.getStorage().isEmpty()) + throw new IllegalStateException("A synthetic CompilationUnit was discovered, with no file associated to it."); + String packagePath = cu.getPackageDeclaration().map(NodeWithName::getNameAsString).orElse("").replace(".", "/"); + File packageDir = new File(outputDir, packagePath); + packageDir.mkdirs(); + File javaFile = new File(packageDir, cu.getStorage().get().getFileName()); + try (PrintWriter pw = new PrintWriter(javaFile)) { + pw.print(new BlockComment(getDisclaimer(cu.getStorage().get()))); + pw.print(cu); + } catch (FileNotFoundException e) { + System.err.println("Could not write file " + javaFile); + } + } + } + + protected String getDisclaimer(CompilationUnit.Storage s) { + return String.format("\n\tThis file was automatically generated as part of a slice with criterion" + + "\n\tfile: %s, line: %d, variable(s): %s\n\tOriginal file: %s\n", + scFile, scLine, String.join(", ", scVars), s.getPath()); + } + + public static void main(String... args) { + try { + new Slicer(args).slice(); + } catch (ParseException e) { + System.err.println("Error parsing the arguments!\n" + e.getMessage()); + } + } +} diff --git a/cfg/Eval_1_main.ff3 b/sdg-core/cfg/Eval_1_main.ff3 similarity index 100% rename from cfg/Eval_1_main.ff3 rename to sdg-core/cfg/Eval_1_main.ff3 diff --git a/sdg-core/pom.xml b/sdg-core/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..88d56ba6630f6db693fb2fe869b28477da5ec9bc --- /dev/null +++ b/sdg-core/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + tfm + sdg-core + 1.0-SNAPSHOT + + + 11 + 11 + + + + + com.github.javaparser + javaparser-symbol-solver-core + 3.9.1 + + + + org.jetbrains + annotations-java5 + RELEASE + compile + + + + org.jgrapht + jgrapht-core + 1.3.0 + + + + org.jgrapht + jgrapht-io + 1.3.0 + + + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + diff --git a/src/main/java/tfm/arcs/Arc.java b/sdg-core/src/main/java/tfm/arcs/Arc.java similarity index 96% rename from src/main/java/tfm/arcs/Arc.java rename to sdg-core/src/main/java/tfm/arcs/Arc.java index ef0ffd55e98bc6b6301fa8dde9726c8fbd9eca5f..e9ecd300639910508c20d6e3cb6ea8d61e87e23b 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/sdg-core/src/main/java/tfm/arcs/Arc.java @@ -64,6 +64,14 @@ public abstract class Arc extends DefaultEdge { throw new UnsupportedOperationException("Not a DataDependencyArc"); } + public boolean isInterproceduralInputArc() { + return false; + } + + public boolean isInterproceduralOutputArc() { + return false; + } + /** @see CallArc */ public final boolean isCallArc() { return this instanceof CallArc; diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/sdg-core/src/main/java/tfm/arcs/cfg/ControlFlowArc.java similarity index 100% rename from src/main/java/tfm/arcs/cfg/ControlFlowArc.java rename to sdg-core/src/main/java/tfm/arcs/cfg/ControlFlowArc.java diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/sdg-core/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java similarity index 100% rename from src/main/java/tfm/arcs/pdg/ControlDependencyArc.java rename to sdg-core/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/sdg-core/src/main/java/tfm/arcs/pdg/DataDependencyArc.java similarity index 100% rename from src/main/java/tfm/arcs/pdg/DataDependencyArc.java rename to sdg-core/src/main/java/tfm/arcs/pdg/DataDependencyArc.java diff --git a/src/main/java/tfm/arcs/sdg/CallArc.java b/sdg-core/src/main/java/tfm/arcs/sdg/CallArc.java similarity index 59% rename from src/main/java/tfm/arcs/sdg/CallArc.java rename to sdg-core/src/main/java/tfm/arcs/sdg/CallArc.java index 43c41382a6f644d6eae191c281ab5cdacc920856..a6af4b579dc0ccf1a44f4e7dc421cf05e3efaefb 100644 --- a/src/main/java/tfm/arcs/sdg/CallArc.java +++ b/sdg-core/src/main/java/tfm/arcs/sdg/CallArc.java @@ -2,15 +2,24 @@ package tfm.arcs.sdg; import org.jgrapht.io.Attribute; import org.jgrapht.io.DefaultAttribute; -import tfm.arcs.Arc; import java.util.Map; -public class CallArc extends Arc { +public class CallArc extends InterproceduralArc { @Override public Map getDotAttributes() { Map map = super.getDotAttributes(); map.put("style", DefaultAttribute.createAttribute("dashed")); return map; } + + @Override + public boolean isInterproceduralInputArc() { + return true; + } + + @Override + public boolean isInterproceduralOutputArc() { + return false; + } } diff --git a/sdg-core/src/main/java/tfm/arcs/sdg/InterproceduralArc.java b/sdg-core/src/main/java/tfm/arcs/sdg/InterproceduralArc.java new file mode 100644 index 0000000000000000000000000000000000000000..13c74714bd81bc7f0fc03551eb5210e71bc0f7fc --- /dev/null +++ b/sdg-core/src/main/java/tfm/arcs/sdg/InterproceduralArc.java @@ -0,0 +1,15 @@ +package tfm.arcs.sdg; + +import tfm.arcs.Arc; + +public abstract class InterproceduralArc extends Arc { + protected InterproceduralArc() { + super(); + } + + @Override + public abstract boolean isInterproceduralInputArc(); + + @Override + public abstract boolean isInterproceduralOutputArc(); +} diff --git a/sdg-core/src/main/java/tfm/arcs/sdg/ParameterInOutArc.java b/sdg-core/src/main/java/tfm/arcs/sdg/ParameterInOutArc.java new file mode 100644 index 0000000000000000000000000000000000000000..4f377d7537ca22d66f7030f6d42efebfe90ed860 --- /dev/null +++ b/sdg-core/src/main/java/tfm/arcs/sdg/ParameterInOutArc.java @@ -0,0 +1,29 @@ +package tfm.arcs.sdg; + +import org.jgrapht.io.Attribute; +import org.jgrapht.io.DefaultAttribute; +import tfm.nodes.GraphNode; +import tfm.nodes.type.NodeType; + +import java.util.Map; + +public class ParameterInOutArc extends InterproceduralArc { + @Override + public Map getDotAttributes() { + Map map = super.getDotAttributes(); + map.put("style", DefaultAttribute.createAttribute("dashed")); + return map; + } + + @Override + public boolean isInterproceduralInputArc() { + return ((GraphNode) getSource()).getNodeType() == NodeType.ACTUAL_IN && + ((GraphNode) getTarget()).getNodeType() == NodeType.FORMAL_IN; + } + + @Override + public boolean isInterproceduralOutputArc() { + return ((GraphNode) getSource()).getNodeType() == NodeType.FORMAL_OUT && + ((GraphNode) getTarget()).getNodeType() == NodeType.ACTUAL_OUT; + } +} diff --git a/src/main/java/tfm/arcs/sdg/SummaryArc.java b/sdg-core/src/main/java/tfm/arcs/sdg/SummaryArc.java similarity index 68% rename from src/main/java/tfm/arcs/sdg/SummaryArc.java rename to sdg-core/src/main/java/tfm/arcs/sdg/SummaryArc.java index bde9724c0026bc919cfbe4c317618bf93db644af..1eb583dfa2ddb9acfd028573d3a631cefd2bd66f 100644 --- a/src/main/java/tfm/arcs/sdg/SummaryArc.java +++ b/sdg-core/src/main/java/tfm/arcs/sdg/SummaryArc.java @@ -13,4 +13,14 @@ public class SummaryArc extends Arc { map.put("style", DefaultAttribute.createAttribute("bold")); return map; } + + @Override + public boolean isInterproceduralInputArc() { + return false; + } + + @Override + public boolean isInterproceduralOutputArc() { + return false; + } } diff --git a/src/main/java/tfm/graphs/Buildable.java b/sdg-core/src/main/java/tfm/graphs/Buildable.java similarity index 100% rename from src/main/java/tfm/graphs/Buildable.java rename to sdg-core/src/main/java/tfm/graphs/Buildable.java diff --git a/src/main/java/tfm/graphs/Graph.java b/sdg-core/src/main/java/tfm/graphs/Graph.java similarity index 97% rename from src/main/java/tfm/graphs/Graph.java rename to sdg-core/src/main/java/tfm/graphs/Graph.java index 9326553a2022f1fad16a9a1c53d8dc0209e8feff..bb0fab6aa0e13f29f882138d5900e16f3e66ee4b 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/sdg-core/src/main/java/tfm/graphs/Graph.java @@ -9,7 +9,8 @@ import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; import tfm.utils.ASTUtils; -import java.util.*; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; /** diff --git a/src/main/java/tfm/graphs/GraphWithRootNode.java b/sdg-core/src/main/java/tfm/graphs/GraphWithRootNode.java similarity index 100% rename from src/main/java/tfm/graphs/GraphWithRootNode.java rename to sdg-core/src/main/java/tfm/graphs/GraphWithRootNode.java diff --git a/src/main/java/tfm/graphs/Sliceable.java b/sdg-core/src/main/java/tfm/graphs/Sliceable.java similarity index 100% rename from src/main/java/tfm/graphs/Sliceable.java rename to sdg-core/src/main/java/tfm/graphs/Sliceable.java diff --git a/src/main/java/tfm/graphs/augmented/ACFG.java b/sdg-core/src/main/java/tfm/graphs/augmented/ACFG.java similarity index 100% rename from src/main/java/tfm/graphs/augmented/ACFG.java rename to sdg-core/src/main/java/tfm/graphs/augmented/ACFG.java diff --git a/src/main/java/tfm/graphs/augmented/ACFGBuilder.java b/sdg-core/src/main/java/tfm/graphs/augmented/ACFGBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/augmented/ACFGBuilder.java rename to sdg-core/src/main/java/tfm/graphs/augmented/ACFGBuilder.java diff --git a/src/main/java/tfm/graphs/augmented/APDG.java b/sdg-core/src/main/java/tfm/graphs/augmented/APDG.java similarity index 100% rename from src/main/java/tfm/graphs/augmented/APDG.java rename to sdg-core/src/main/java/tfm/graphs/augmented/APDG.java diff --git a/sdg-core/src/main/java/tfm/graphs/augmented/PPDG.java b/sdg-core/src/main/java/tfm/graphs/augmented/PPDG.java new file mode 100644 index 0000000000000000000000000000000000000000..6dd57cfd565ccf66745eb2e0049e05351d0ba08e --- /dev/null +++ b/sdg-core/src/main/java/tfm/graphs/augmented/PPDG.java @@ -0,0 +1,27 @@ +package tfm.graphs.augmented; + +import tfm.nodes.GraphNode; +import tfm.slicing.PseudoPredicateSlicingAlgorithm; +import tfm.slicing.Slice; +import tfm.slicing.SlicingCriterion; +import tfm.utils.NodeNotFoundException; + +import java.util.Optional; + +public class PPDG extends APDG { + public PPDG() { + this(new ACFG()); + } + + public PPDG(ACFG acfg) { + super(acfg); + } + + @Override + public Slice slice(SlicingCriterion slicingCriterion) { + Optional> node = slicingCriterion.findNode(this); + if (node.isEmpty()) + throw new NodeNotFoundException(slicingCriterion); + return new PseudoPredicateSlicingAlgorithm(this).traverse(node.get()); + } +} diff --git a/src/main/java/tfm/graphs/cfg/CFG.java b/sdg-core/src/main/java/tfm/graphs/cfg/CFG.java similarity index 100% rename from src/main/java/tfm/graphs/cfg/CFG.java rename to sdg-core/src/main/java/tfm/graphs/cfg/CFG.java diff --git a/src/main/java/tfm/graphs/cfg/CFGBuilder.java b/sdg-core/src/main/java/tfm/graphs/cfg/CFGBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/cfg/CFGBuilder.java rename to sdg-core/src/main/java/tfm/graphs/cfg/CFGBuilder.java diff --git a/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java b/sdg-core/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java rename to sdg-core/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java diff --git a/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java b/sdg-core/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java rename to sdg-core/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java diff --git a/src/main/java/tfm/graphs/pdg/PDG.java b/sdg-core/src/main/java/tfm/graphs/pdg/PDG.java similarity index 82% rename from src/main/java/tfm/graphs/pdg/PDG.java rename to sdg-core/src/main/java/tfm/graphs/pdg/PDG.java index 328281af6ebb27a13f3189cff6a9c96fe56dca2a..976ee6490a444d197e585db6785e49a2bfd58003 100644 --- a/src/main/java/tfm/graphs/pdg/PDG.java +++ b/sdg-core/src/main/java/tfm/graphs/pdg/PDG.java @@ -1,13 +1,13 @@ package tfm.graphs.pdg; import com.github.javaparser.ast.body.MethodDeclaration; -import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; import tfm.graphs.GraphWithRootNode; import tfm.graphs.Sliceable; import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; +import tfm.slicing.ClassicSlicingAlgorithm; import tfm.slicing.Slice; import tfm.slicing.SlicingCriterion; import tfm.utils.NodeNotFoundException; @@ -47,22 +47,9 @@ public class PDG extends GraphWithRootNode implements Sliceab @Override public Slice slice(SlicingCriterion slicingCriterion) { Optional> node = slicingCriterion.findNode(this); - if (!node.isPresent()) + if (node.isEmpty()) throw new NodeNotFoundException(slicingCriterion); - Slice slice = new Slice(); - getSliceNodes(slice, node.get()); - return slice; - } - - protected void getSliceNodes(Slice slice, GraphNode node) { - slice.add(node); - - for (Arc arc : incomingEdgesOf(node)) { - GraphNode from = getEdgeSource(arc); - if (slice.contains(from)) - continue; - getSliceNodes(slice, from); - } + return new ClassicSlicingAlgorithm(this).traverse(node.get()); } public CFG getCfg() { diff --git a/src/main/java/tfm/graphs/pdg/PDGBuilder.java b/sdg-core/src/main/java/tfm/graphs/pdg/PDGBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/pdg/PDGBuilder.java rename to sdg-core/src/main/java/tfm/graphs/pdg/PDGBuilder.java diff --git a/src/main/java/tfm/graphs/sdg/MethodCallReplacer.java b/sdg-core/src/main/java/tfm/graphs/sdg/MethodCallReplacer.java similarity index 79% rename from src/main/java/tfm/graphs/sdg/MethodCallReplacer.java rename to sdg-core/src/main/java/tfm/graphs/sdg/MethodCallReplacer.java index e8290fdec0024402f6e1f0ae4687a7f3c700f099..c3bc8affac2b29ed1af653d2e9d85f37f697887e 100644 --- a/src/main/java/tfm/graphs/sdg/MethodCallReplacer.java +++ b/sdg-core/src/main/java/tfm/graphs/sdg/MethodCallReplacer.java @@ -1,12 +1,7 @@ package tfm.graphs.sdg; import com.github.javaparser.ast.body.MethodDeclaration; -import tfm.graphs.GraphWithRootNode; -import tfm.nodes.GraphNode; import tfm.utils.Context; -import tfm.utils.Logger; - -import java.util.Optional; class MethodCallReplacer { diff --git a/src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java b/sdg-core/src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java similarity index 82% rename from src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java rename to sdg-core/src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java index e6f334ae64c1975733897d7eee20b75d5394dd70..9b991a55a1fcb905cc950eddc41ac6b1c941f29e 100644 --- a/src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java +++ b/sdg-core/src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java @@ -9,18 +9,16 @@ import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.expr.*; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; +import com.github.javaparser.resolution.UnsolvedSymbolException; import tfm.arcs.Arc; -import tfm.arcs.pdg.DataDependencyArc; import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; import tfm.nodes.TypeNodeFactory; import tfm.nodes.type.NodeType; import tfm.utils.Context; import tfm.utils.Logger; -import tfm.utils.MethodDeclarationSolver; import java.util.*; -import java.util.stream.Collectors; class MethodCallReplacerVisitor extends VoidVisitorAdapter { @@ -95,19 +93,16 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter { // .filter(Expression::isMethodCallExpr) // .forEach(expression -> expression.accept(this, context)); - Logger.log("MethodCallReplacerVisitor", context); - - Optional> optionalNethodDeclarationNode = - MethodDeclarationSolver.getInstance() - .findDeclarationFrom(methodCallExpr) - .flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration)); - - if (!optionalNethodDeclarationNode.isPresent()) { - Logger.format("Not found: '%s'. Discarding", methodCallExpr); + GraphNode methodDeclarationNode; + try { + methodDeclarationNode = methodCallExpr.resolve().toAst() + .flatMap(sdg::findNodeByASTNode) + .orElseThrow(() -> new UnsolvedSymbolException("")); + } catch (UnsolvedSymbolException e) { + Logger.format("Method declaration not found: '%s'. Discarding", methodCallExpr); return; } - GraphNode methodDeclarationNode = optionalNethodDeclarationNode.get(); MethodDeclaration methodDeclaration = methodDeclarationNode.getAstNode(); GraphNode methodCallNode = sdg.addNode("CALL " + methodCallExpr.toString(), methodCallExpr, TypeNodeFactory.fromType(NodeType.METHOD_CALL)); @@ -150,16 +145,10 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter { // Handle data dependency: Remove arc from method call node and add it to IN node - List inDataDependencies = sdg.incomingEdgesOf(originalMethodCallNode).stream() - .filter(arc -> arc.isDataDependencyArc() && Objects.equals(arc.getLabel(), argument.toString())) - .map(Arc::asDataDependencyArc) - .collect(Collectors.toList()); - - for (DataDependencyArc arc : inDataDependencies) { - GraphNode dataDependencySource = sdg.getEdgeSource(arc); - sdg.removeEdge(arc); - sdg.addDataDependencyArc(dataDependencySource, argumentInNode, argument.toString()); - } + sdg.incomingEdgesOf(originalMethodCallNode).stream() + .filter(Arc::isDataDependencyArc) + .filter(arc -> Objects.equals(arc.getLabel(), argument.toString())) + .forEach(arc -> sdg.addDataDependencyArc(sdg.getEdgeSource(arc), argumentInNode, argument.toString())); // Now, find the corresponding method declaration's in node and link argument node with it @@ -205,16 +194,10 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter { // Handle data dependency: remove arc from method call node and add it to OUT node - List outDataDependencies = sdg.outgoingEdgesOf(originalMethodCallNode).stream() - .filter(arc -> arc.isDataDependencyArc() && Objects.equals(arc.getLabel(), argument.toString())) - .map(Arc::asDataDependencyArc) - .collect(Collectors.toList()); - - for (DataDependencyArc arc : outDataDependencies) { - GraphNode dataDependencyTarget = sdg.getEdgeTarget(arc); - sdg.removeEdge(arc); - sdg.addDataDependencyArc(argumentOutNode, dataDependencyTarget, argument.toString()); - } + sdg.outgoingEdgesOf(originalMethodCallNode).stream() + .filter(Arc::isDataDependencyArc) + .filter(arc -> Objects.equals(arc.getLabel(), argument.toString())) + .forEach(arc -> sdg.addDataDependencyArc(argumentOutNode, sdg.getEdgeTarget(arc), argument.toString())); if (optionalParameterOutNode.isPresent()) { sdg.addParameterInOutArc(optionalParameterOutNode.get(), argumentOutNode); diff --git a/src/main/java/tfm/graphs/sdg/OutNodeVariableVisitor.java b/sdg-core/src/main/java/tfm/graphs/sdg/OutNodeVariableVisitor.java similarity index 100% rename from src/main/java/tfm/graphs/sdg/OutNodeVariableVisitor.java rename to sdg-core/src/main/java/tfm/graphs/sdg/OutNodeVariableVisitor.java diff --git a/src/main/java/tfm/graphs/sdg/SDG.java b/sdg-core/src/main/java/tfm/graphs/sdg/SDG.java similarity index 85% rename from src/main/java/tfm/graphs/sdg/SDG.java rename to sdg-core/src/main/java/tfm/graphs/sdg/SDG.java index 8f524de5361c80f8ab232f8a2dd36be69354effd..05ea563c61238780ceddfdfe097745079db36623 100644 --- a/src/main/java/tfm/graphs/sdg/SDG.java +++ b/sdg-core/src/main/java/tfm/graphs/sdg/SDG.java @@ -13,7 +13,8 @@ import tfm.arcs.sdg.SummaryArc; import tfm.graphs.Buildable; import tfm.graphs.Graph; import tfm.graphs.cfg.CFG; -import tfm.nodes.*; +import tfm.nodes.GraphNode; +import tfm.slicing.ClassicSlicingAlgorithm; import tfm.slicing.Slice; import tfm.slicing.Sliceable; import tfm.slicing.SlicingCriterion; @@ -26,19 +27,29 @@ public class SDG extends Graph implements Sliceable, Buildable methodCFGMap; + private NodeList compilationUnits; public SDG() { this.methodCFGMap = new HashMap<>(); } + public NodeList getCompilationUnits() { + return compilationUnits; + } + @Override public Slice slice(SlicingCriterion slicingCriterion) { - throw new RuntimeException("Slicing not implemented for the SDG"); + Optional> optSlicingNode = slicingCriterion.findNode(this); + if (optSlicingNode.isEmpty()) + throw new IllegalArgumentException("Could not locate the slicing criterion in the SDG"); + return new ClassicSlicingAlgorithm(this).traverse(optSlicingNode.get()); } @Override public void build(NodeList nodeList) { nodeList.accept(new SDGBuilder(this), new Context()); + compilationUnits = nodeList; + built = true; } @Override diff --git a/src/main/java/tfm/graphs/sdg/SDGBuilder.java b/sdg-core/src/main/java/tfm/graphs/sdg/SDGBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/sdg/SDGBuilder.java rename to sdg-core/src/main/java/tfm/graphs/sdg/SDGBuilder.java diff --git a/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java b/sdg-core/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java rename to sdg-core/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java diff --git a/src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java b/sdg-core/src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java similarity index 100% rename from src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java rename to sdg-core/src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java diff --git a/src/main/java/tfm/nodes/GraphNode.java b/sdg-core/src/main/java/tfm/nodes/GraphNode.java similarity index 100% rename from src/main/java/tfm/nodes/GraphNode.java rename to sdg-core/src/main/java/tfm/nodes/GraphNode.java diff --git a/src/main/java/tfm/nodes/IdHelper.java b/sdg-core/src/main/java/tfm/nodes/IdHelper.java similarity index 100% rename from src/main/java/tfm/nodes/IdHelper.java rename to sdg-core/src/main/java/tfm/nodes/IdHelper.java diff --git a/src/main/java/tfm/nodes/NodeFactory.java b/sdg-core/src/main/java/tfm/nodes/NodeFactory.java similarity index 98% rename from src/main/java/tfm/nodes/NodeFactory.java rename to sdg-core/src/main/java/tfm/nodes/NodeFactory.java index b54b2efb8a07d6978b34ca83a4c279cbff078f5a..b0c588923a45196939a9b9b7cda0a57bffc52124 100644 --- a/src/main/java/tfm/nodes/NodeFactory.java +++ b/sdg-core/src/main/java/tfm/nodes/NodeFactory.java @@ -2,7 +2,6 @@ package tfm.nodes; import com.github.javaparser.ast.Node; import org.jetbrains.annotations.NotNull; -import tfm.nodes.GraphNode; import java.util.Collection; diff --git a/src/main/java/tfm/nodes/TypeNodeFactory.java b/sdg-core/src/main/java/tfm/nodes/TypeNodeFactory.java similarity index 100% rename from src/main/java/tfm/nodes/TypeNodeFactory.java rename to sdg-core/src/main/java/tfm/nodes/TypeNodeFactory.java diff --git a/src/main/java/tfm/nodes/type/NodeType.java b/sdg-core/src/main/java/tfm/nodes/type/NodeType.java similarity index 100% rename from src/main/java/tfm/nodes/type/NodeType.java rename to sdg-core/src/main/java/tfm/nodes/type/NodeType.java diff --git a/sdg-core/src/main/java/tfm/slicing/ClassicSlicingAlgorithm.java b/sdg-core/src/main/java/tfm/slicing/ClassicSlicingAlgorithm.java new file mode 100644 index 0000000000000000000000000000000000000000..e608af4cecd091a899ac60baa48599c63b92d6d5 --- /dev/null +++ b/sdg-core/src/main/java/tfm/slicing/ClassicSlicingAlgorithm.java @@ -0,0 +1,68 @@ +package tfm.slicing; + +import tfm.arcs.Arc; +import tfm.graphs.Graph; +import tfm.nodes.GraphNode; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.Predicate; + +public class ClassicSlicingAlgorithm implements SlicingAlgorithm { + protected final Graph graph; + + public ClassicSlicingAlgorithm(Graph graph) { + this.graph = graph; + } + + @Override + public Slice traverse(GraphNode slicingCriterion) { + Slice slice = new Slice(); + slice.add(slicingCriterion); + pass(slice, this::ignorePass1); + pass(slice, this::ignorePass2); + return slice; + } + + protected boolean ignorePass1(Arc arc) { + return arc.isInterproceduralOutputArc(); + } + + protected boolean ignorePass2(Arc arc) { + return arc.isInterproceduralInputArc(); + } + + protected void pass(Slice slice, Predicate ignoreCondition) { + // `toVisit` behaves like a set and using iterable we can use it as a queue + // More info: https://stackoverflow.com/a/2319126 + LinkedHashSet> toVisit = new LinkedHashSet<>(slice.getGraphNodes()); + Set> visited = new HashSet<>(); + + while (!toVisit.isEmpty()) { + GraphNode node = removeFirst(toVisit); + // Avoid duplicate traversal + if (visited.contains(node)) + continue; + visited.add(node); + // Traverse all edges backwards + for (Arc arc : graph.incomingEdgesOf(node)) { + if (ignoreCondition.test(arc)) + continue; + GraphNode source = graph.getEdgeSource(arc); + if (!visited.contains(source)) + toVisit.add(source); + } + } + + visited.forEach(slice::add); + } + + protected static E removeFirst(Set set) { + Iterator i = set.iterator(); + E e = i.next(); + i.remove(); + return e; + } +} diff --git a/sdg-core/src/main/java/tfm/slicing/FileLineSlicingCriterion.java b/sdg-core/src/main/java/tfm/slicing/FileLineSlicingCriterion.java new file mode 100644 index 0000000000000000000000000000000000000000..df01201720eedefc0a24106d60a61d644d5cbb84 --- /dev/null +++ b/sdg-core/src/main/java/tfm/slicing/FileLineSlicingCriterion.java @@ -0,0 +1,42 @@ +package tfm.slicing; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.stmt.Statement; +import tfm.graphs.sdg.SDG; +import tfm.nodes.GraphNode; + +import java.io.File; +import java.util.Optional; + +public class FileLineSlicingCriterion extends LineNumberCriterion { + protected final File file; + + public FileLineSlicingCriterion(File file, int lineNumber) { + super(lineNumber, null); + this.file = file; + } + + @Override + public Optional> findNode(SDG graph) { + Optional optCu = findCompilationUnit(graph.getCompilationUnits()); + if (optCu.isEmpty()) + return Optional.empty(); + return optCu.get().findFirst(Statement.class, this::matchesLine).flatMap(graph::findNodeByASTNode); + } + + protected Optional findCompilationUnit(NodeList cus) { + for (CompilationUnit cu : cus) { + Optional optStorage = cu.getStorage(); + if (optStorage.isPresent() && optStorage.get().getFileName().equals(file.getName()) + && optStorage.get().getDirectory().toAbsolutePath().equals(file.getParentFile().toPath().toAbsolutePath())) + return Optional.of(cu); + } + return Optional.empty(); + } + + @Override + public String toString() { + return file + "#" + lineNumber + ":" + variable; + } +} diff --git a/src/main/java/tfm/slicing/GraphNodeCriterion.java b/sdg-core/src/main/java/tfm/slicing/GraphNodeCriterion.java similarity index 100% rename from src/main/java/tfm/slicing/GraphNodeCriterion.java rename to sdg-core/src/main/java/tfm/slicing/GraphNodeCriterion.java diff --git a/src/main/java/tfm/slicing/LineNumberCriterion.java b/sdg-core/src/main/java/tfm/slicing/LineNumberCriterion.java similarity index 78% rename from src/main/java/tfm/slicing/LineNumberCriterion.java rename to sdg-core/src/main/java/tfm/slicing/LineNumberCriterion.java index 3eb8ead496dc6c3bde450244e5f66f1a7b6807d4..f7a238588cc35c9b6d6f3e6b6a31b8441c11b432 100644 --- a/src/main/java/tfm/slicing/LineNumberCriterion.java +++ b/sdg-core/src/main/java/tfm/slicing/LineNumberCriterion.java @@ -1,5 +1,6 @@ package tfm.slicing; +import com.github.javaparser.Position; import com.github.javaparser.ast.Node; import tfm.graphs.cfg.CFG; import tfm.graphs.pdg.PDG; @@ -10,8 +11,9 @@ import tfm.utils.Logger; import java.util.Optional; public class LineNumberCriterion extends SlicingCriterion { + protected static final Position DEFAULT_POSITION = new Position(0, 0); - private int lineNumber; + protected int lineNumber; public LineNumberCriterion(int lineNumber, String variable) { super(variable); @@ -30,7 +32,7 @@ public class LineNumberCriterion extends SlicingCriterion { return graph.vertexSet().stream().filter(node -> { Node astNode = node.getAstNode(); - if (!astNode.getBegin().isPresent() || !astNode.getEnd().isPresent()) + if (astNode.getBegin().isEmpty() || astNode.getEnd().isEmpty()) return false; int begin = astNode.getBegin().get().line; @@ -47,6 +49,10 @@ public class LineNumberCriterion extends SlicingCriterion { return Optional.empty(); } + protected boolean matchesLine(Node node) { + return node.getBegin().orElse(DEFAULT_POSITION).line == lineNumber; + } + @Override public String toString() { return String.format("(%s, %s)", lineNumber, variable); diff --git a/sdg-core/src/main/java/tfm/slicing/PseudoPredicateSlicingAlgorithm.java b/sdg-core/src/main/java/tfm/slicing/PseudoPredicateSlicingAlgorithm.java new file mode 100644 index 0000000000000000000000000000000000000000..8f66c4378e9f011738658f8791062c21e743d6dd --- /dev/null +++ b/sdg-core/src/main/java/tfm/slicing/PseudoPredicateSlicingAlgorithm.java @@ -0,0 +1,35 @@ +package tfm.slicing; + +import tfm.arcs.Arc; +import tfm.graphs.Graph; +import tfm.nodes.GraphNode; +import tfm.utils.ASTUtils; + +public class PseudoPredicateSlicingAlgorithm extends ClassicSlicingAlgorithm { + protected GraphNode slicingCriterion; + + public PseudoPredicateSlicingAlgorithm(Graph graph) { + super(graph); + } + + @Override + public Slice traverse(GraphNode slicingCriterion) { + this.slicingCriterion = slicingCriterion; + return super.traverse(slicingCriterion); + } + + @Override + protected boolean ignorePass1(Arc arc) { + return super.ignorePass1(arc) || ignorePseudoPredicate(arc); + } + + @Override + protected boolean ignorePass2(Arc arc) { + return super.ignorePass2(arc) || ignorePseudoPredicate(arc); + } + + protected boolean ignorePseudoPredicate(Arc arc) { + GraphNode target = graph.getEdgeTarget(arc); + return ASTUtils.isPseudoPredicate(target.getAstNode()) && target != slicingCriterion; + } +} diff --git a/src/main/java/tfm/slicing/Slice.java b/sdg-core/src/main/java/tfm/slicing/Slice.java similarity index 54% rename from src/main/java/tfm/slicing/Slice.java rename to sdg-core/src/main/java/tfm/slicing/Slice.java index 91563f30a02fb85421dc3da02d4d957e85ad9adb..485a5da437bdf452e6e5530870091364c4295898 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/sdg-core/src/main/java/tfm/slicing/Slice.java @@ -1,6 +1,8 @@ package tfm.slicing; +import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.CloneVisitor; import com.github.javaparser.ast.visitor.Visitable; @@ -39,6 +41,41 @@ public class Slice { return obj instanceof Slice && map.equals(((Slice) obj).map); } + public Set> getGraphNodes() { + return Set.copyOf(map.values()); + } + + /** + * Organize all nodes pertaining to this slice in one or more CompilationUnits. + * CompilationUnits themselves need not be part of the slice to be included if any of their + * components are present. + */ + public NodeList toAst() { + Map> cuMap = new HashMap<>(); + // Add each node to the corresponding bucket of the map + // Nodes may not belong to a compilation unit (fictional nodes), and they are skipped for the slice. + for (Node node : nodes) { + Optional cu = node.findCompilationUnit(); + if (cu.isEmpty()) continue; + cuMap.putIfAbsent(cu.get(), new HashSet<>()); + cuMap.get(cu.get()).add(node); + } + // Traverse the AST of each compilation unit, creating a copy and + // removing any element not present in the slice. + NodeList cus = new NodeList<>(); + SlicePruneVisitor sliceVisitor = new SlicePruneVisitor(); + CloneVisitor cloneVisitor = new CloneVisitor(); + for (Map.Entry> entry : cuMap.entrySet()) { + CompilationUnit clone = (CompilationUnit) entry.getKey().accept(cloneVisitor, null); + assert entry.getKey().getStorage().isPresent(); + clone.setStorage(entry.getKey().getStorage().get().getPath()); + clone.accept(sliceVisitor, entry.getValue()); + cus.add(clone); + } + return cus; + } + + @Deprecated public Node getAst() { List> methods = map.values().stream().filter(e -> e.getAstNode() instanceof MethodDeclaration).collect(Collectors.toList()); if (methods.size() == 1) { @@ -59,7 +96,7 @@ public class Slice { private MethodDeclaration getMethodAst(Node node) { Visitable clone = node.accept(new CloneVisitor(), null); assert clone instanceof MethodDeclaration; - clone.accept(new SliceAstVisitor(), this); + clone.accept(new SlicePruneVisitor(), nodes); return ((MethodDeclaration) clone); } } diff --git a/sdg-core/src/main/java/tfm/slicing/SlicePruneVisitor.java b/sdg-core/src/main/java/tfm/slicing/SlicePruneVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..f78e870019c588bbcfef2860b3a9fb7dd81fa6cd --- /dev/null +++ b/sdg-core/src/main/java/tfm/slicing/SlicePruneVisitor.java @@ -0,0 +1,171 @@ +package tfm.slicing; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.ConstructorDeclaration; +import com.github.javaparser.ast.body.FieldDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.expr.BooleanLiteralExpr; +import com.github.javaparser.ast.nodeTypes.NodeWithBody; +import com.github.javaparser.ast.stmt.*; +import com.github.javaparser.ast.visitor.ModifierVisitor; +import com.github.javaparser.ast.visitor.Visitable; + +import java.util.Set; +import java.util.stream.Collectors; + +public class SlicePruneVisitor extends ModifierVisitor> { + // ========== Utility methods ========== + + protected void fillBody(Node n) { + if (!(n instanceof NodeWithBody)) + return; + NodeWithBody nb = ((NodeWithBody) n); + if (nb.getBody() == null) + nb.setBody(new EmptyStmt()); + } + + // ========== File visitors ========== + + @Override + public Visitable visit(CompilationUnit n, Set arg) { + boolean keep = arg.contains(n); + Visitable v = super.visit(n, arg); + return keep || !((Node) v).getChildNodes().isEmpty() ? v : null; + } + + @Override + public Visitable visit(ClassOrInterfaceDeclaration n, Set arg) { + boolean keep = arg.contains(n); + Visitable v = super.visit(n, arg); + return keep || !((Node) v).getChildNodes().isEmpty() ? v : null; + } + + // ========== Class body visitors ========== + + @Override + public Visitable visit(MethodDeclaration n, Set arg) { + boolean keep = arg.contains(n); + Visitable v = super.visit(n, arg); + return keep ? v : null; + } + + @Override + public Visitable visit(ConstructorDeclaration n, Set arg) { + boolean keep = arg.contains(n); + Visitable v = super.visit(n, arg); + return keep ? v : null; + } + + @Override + public Visitable visit(FieldDeclaration n, Set arg) { + boolean keep = arg.contains(n); + Visitable v = super.visit(n, arg); + return keep ? v : null; + } + +// ========== Method body visitors ========== + // 3 alternatives: + // a. Without relevant children and included if on the slice or not (e.g. ExpressionStmt) + // b. With relevant children and included if of the slice or not, children are discarded if not included (e.g. WhileStmt) + // c. With relevant children and included if any children is included OR if on the slice (e.g. SwitchEntryStmt, LabeledStmt) + + @Override + public Visitable visit(BreakStmt n, Set arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(ContinueStmt n, Set arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(DoStmt n, Set arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + fillBody(n); + return keep ? n : null; + } + + @Override + public Visitable visit(ForEachStmt n, Set arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + fillBody(n); + return keep ? n : null; + } + + @Override + public Visitable visit(ForStmt n, Set arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + n.setInitialization(new NodeList<>(n.getInitialization().stream() + .filter(arg::contains).collect(Collectors.toList()))); + n.setUpdate(new NodeList<>(n.getUpdate().stream() + .filter(arg::contains).collect(Collectors.toList()))); + fillBody(n); + if (keep) + return n; + if (n.getInitialization().isEmpty() && n.getUpdate().isEmpty()) + return null; + return new ForStmt(n.getInitialization(), new BooleanLiteralExpr(false), + n.getUpdate(), n.getBody()); + } + + @Override + public Visitable visit(WhileStmt n, Set arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + fillBody(n); + return keep ? n : null; + } + + @Override + public Visitable visit(IfStmt n, Set arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + if (n.getThenStmt() == null) + n.setThenStmt(new EmptyStmt()); + return keep ? n : null; + } + + @Override + public Visitable visit(LabeledStmt n, Set arg) { + super.visit(n, arg); + return n.getStatement() != null ? n : null; + } + + @Override + public Visitable visit(ReturnStmt n, Set arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(ThrowStmt n, Set arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(SwitchEntryStmt n, Set arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + if (!n.getStatements().isEmpty()) + return n; + return keep ? n : null; + } + + @Override + public Visitable visit(SwitchStmt n, Set arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + return keep ? n : null; + } + + @Override + public Visitable visit(ExpressionStmt n, Set arg) { + return arg.contains(n) ? n : null; + } +} diff --git a/src/main/java/tfm/slicing/Sliceable.java b/sdg-core/src/main/java/tfm/slicing/Sliceable.java similarity index 100% rename from src/main/java/tfm/slicing/Sliceable.java rename to sdg-core/src/main/java/tfm/slicing/Sliceable.java diff --git a/sdg-core/src/main/java/tfm/slicing/SlicingAlgorithm.java b/sdg-core/src/main/java/tfm/slicing/SlicingAlgorithm.java new file mode 100644 index 0000000000000000000000000000000000000000..8ad7c4aa7fd74d035e3d3bb691f830db8c5765fe --- /dev/null +++ b/sdg-core/src/main/java/tfm/slicing/SlicingAlgorithm.java @@ -0,0 +1,7 @@ +package tfm.slicing; + +import tfm.nodes.GraphNode; + +public interface SlicingAlgorithm { + Slice traverse(GraphNode slicingCriterion); +} diff --git a/src/main/java/tfm/slicing/SlicingCriterion.java b/sdg-core/src/main/java/tfm/slicing/SlicingCriterion.java similarity index 100% rename from src/main/java/tfm/slicing/SlicingCriterion.java rename to sdg-core/src/main/java/tfm/slicing/SlicingCriterion.java diff --git a/src/main/java/tfm/utils/ASTUtils.java b/sdg-core/src/main/java/tfm/utils/ASTUtils.java similarity index 98% rename from src/main/java/tfm/utils/ASTUtils.java rename to sdg-core/src/main/java/tfm/utils/ASTUtils.java index 7744e8b349e7873193689f81f1558a57aa6fe238..dc3de70289dc493423704b02c427314e1a4d6510 100644 --- a/src/main/java/tfm/utils/ASTUtils.java +++ b/sdg-core/src/main/java/tfm/utils/ASTUtils.java @@ -3,7 +3,6 @@ package tfm.utils; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.stmt.*; import java.util.Objects; diff --git a/src/main/java/tfm/utils/Context.java b/sdg-core/src/main/java/tfm/utils/Context.java similarity index 100% rename from src/main/java/tfm/utils/Context.java rename to sdg-core/src/main/java/tfm/utils/Context.java diff --git a/src/main/java/tfm/utils/FileUtil.java b/sdg-core/src/main/java/tfm/utils/FileUtil.java similarity index 100% rename from src/main/java/tfm/utils/FileUtil.java rename to sdg-core/src/main/java/tfm/utils/FileUtil.java diff --git a/src/main/java/tfm/utils/Logger.java b/sdg-core/src/main/java/tfm/utils/Logger.java similarity index 100% rename from src/main/java/tfm/utils/Logger.java rename to sdg-core/src/main/java/tfm/utils/Logger.java diff --git a/src/main/java/tfm/utils/NodeNotFoundException.java b/sdg-core/src/main/java/tfm/utils/NodeNotFoundException.java similarity index 100% rename from src/main/java/tfm/utils/NodeNotFoundException.java rename to sdg-core/src/main/java/tfm/utils/NodeNotFoundException.java diff --git a/src/main/java/tfm/utils/Utils.java b/sdg-core/src/main/java/tfm/utils/Utils.java similarity index 100% rename from src/main/java/tfm/utils/Utils.java rename to sdg-core/src/main/java/tfm/utils/Utils.java diff --git a/src/main/java/tfm/variables/VariableExtractor.java b/sdg-core/src/main/java/tfm/variables/VariableExtractor.java similarity index 97% rename from src/main/java/tfm/variables/VariableExtractor.java rename to sdg-core/src/main/java/tfm/variables/VariableExtractor.java index 962e5389061ee8d147a894fcee956e07f829c772..d4828495c327f98c14c7524adca7dca7f5f2f8fb 100644 --- a/src/main/java/tfm/variables/VariableExtractor.java +++ b/sdg-core/src/main/java/tfm/variables/VariableExtractor.java @@ -1,7 +1,6 @@ package tfm.variables; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.expr.Expression; import org.checkerframework.checker.nullness.qual.NonNull; import tfm.variables.actions.VariableAction; diff --git a/src/main/java/tfm/variables/VariableVisitor.java b/sdg-core/src/main/java/tfm/variables/VariableVisitor.java similarity index 99% rename from src/main/java/tfm/variables/VariableVisitor.java rename to sdg-core/src/main/java/tfm/variables/VariableVisitor.java index fd2f639071f991b04a2a8c9c35427e09f7ee84cb..fb629984de2662143d576b83b148d7a49391c897 100644 --- a/src/main/java/tfm/variables/VariableVisitor.java +++ b/sdg-core/src/main/java/tfm/variables/VariableVisitor.java @@ -7,8 +7,6 @@ import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import org.checkerframework.checker.nullness.qual.NonNull; import tfm.variables.actions.VariableAction; -import java.awt.*; - abstract class VariableVisitor extends VoidVisitorAdapter { @Override diff --git a/src/main/java/tfm/variables/actions/VariableAction.java b/sdg-core/src/main/java/tfm/variables/actions/VariableAction.java similarity index 100% rename from src/main/java/tfm/variables/actions/VariableAction.java rename to sdg-core/src/main/java/tfm/variables/actions/VariableAction.java diff --git a/src/main/java/tfm/variables/actions/VariableDeclaration.java b/sdg-core/src/main/java/tfm/variables/actions/VariableDeclaration.java similarity index 100% rename from src/main/java/tfm/variables/actions/VariableDeclaration.java rename to sdg-core/src/main/java/tfm/variables/actions/VariableDeclaration.java diff --git a/src/main/java/tfm/variables/actions/VariableDefinition.java b/sdg-core/src/main/java/tfm/variables/actions/VariableDefinition.java similarity index 100% rename from src/main/java/tfm/variables/actions/VariableDefinition.java rename to sdg-core/src/main/java/tfm/variables/actions/VariableDefinition.java diff --git a/src/main/java/tfm/variables/actions/VariableUse.java b/sdg-core/src/main/java/tfm/variables/actions/VariableUse.java similarity index 100% rename from src/main/java/tfm/variables/actions/VariableUse.java rename to sdg-core/src/main/java/tfm/variables/actions/VariableUse.java diff --git a/src/test/java/tfm/graphs/pdg/HandCraftedGraphs.java b/sdg-core/src/test/java/tfm/graphs/pdg/HandCraftedGraphs.java similarity index 100% rename from src/test/java/tfm/graphs/pdg/HandCraftedGraphs.java rename to sdg-core/src/test/java/tfm/graphs/pdg/HandCraftedGraphs.java diff --git a/src/test/java/tfm/graphs/pdg/PDGTests.java b/sdg-core/src/test/java/tfm/graphs/pdg/PDGTests.java similarity index 95% rename from src/test/java/tfm/graphs/pdg/PDGTests.java rename to sdg-core/src/test/java/tfm/graphs/pdg/PDGTests.java index 3063df63c4869b0841dd6db0a6987beafc005146..106858df22ba724736c8bedfa6819fc671756681 100644 --- a/src/test/java/tfm/graphs/pdg/PDGTests.java +++ b/sdg-core/src/test/java/tfm/graphs/pdg/PDGTests.java @@ -9,8 +9,6 @@ import com.github.javaparser.ast.stmt.ThrowStmt; import com.github.javaparser.ast.stmt.TryStmt; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import tfm.exec.GraphLog; -import tfm.exec.PDGLog; import tfm.graphs.augmented.ACFG; import tfm.graphs.augmented.APDG; import tfm.graphs.augmented.PPDG; @@ -59,14 +57,14 @@ public class PDGTests { private void runPdg(File file, String methodName, MethodDeclaration root, PDG pdg) throws IOException { pdg.build(root); - GraphLog graphLog = new PDGLog(pdg); - graphLog.log(); - try { - graphLog.generateImages(file.getPath() + "-" + methodName); - } catch (Exception e) { - System.err.println("Could not generate PNG"); - System.err.println(e.getMessage()); - } +// GraphLog graphLog = new PDGLog(pdg); +// graphLog.log(); +// try { +// graphLog.generateImages(file.getPath() + "-" + methodName); +// } catch (Exception e) { +// System.err.println("Could not generate PNG"); +// System.err.println(e.getMessage()); +// } } @ParameterizedTest(name = "[{index}] {0} ({1})") diff --git a/src/test/java/tfm/utils/FileFinder.java b/sdg-core/src/test/java/tfm/utils/FileFinder.java similarity index 100% rename from src/test/java/tfm/utils/FileFinder.java rename to sdg-core/src/test/java/tfm/utils/FileFinder.java diff --git a/src/test/res/carlos/Problem1.java b/sdg-core/src/test/res/carlos/Problem1.java similarity index 100% rename from src/test/res/carlos/Problem1.java rename to sdg-core/src/test/res/carlos/Problem1.java diff --git a/src/test/res/carlos/Problem2.java b/sdg-core/src/test/res/carlos/Problem2.java similarity index 100% rename from src/test/res/carlos/Problem2.java rename to sdg-core/src/test/res/carlos/Problem2.java diff --git a/src/test/res/carlos/Problem3.java b/sdg-core/src/test/res/carlos/Problem3.java similarity index 100% rename from src/test/res/carlos/Problem3.java rename to sdg-core/src/test/res/carlos/Problem3.java diff --git a/src/test/res/carlos/Test1.java b/sdg-core/src/test/res/carlos/Test1.java similarity index 100% rename from src/test/res/carlos/Test1.java rename to sdg-core/src/test/res/carlos/Test1.java diff --git a/src/test/res/java-slicing-benchmarks b/sdg-core/src/test/res/java-slicing-benchmarks similarity index 100% rename from src/test/res/java-slicing-benchmarks rename to sdg-core/src/test/res/java-slicing-benchmarks diff --git a/src/test/res/ltd-samples/BasicBreak.java b/sdg-core/src/test/res/ltd-samples/BasicBreak.java similarity index 100% rename from src/test/res/ltd-samples/BasicBreak.java rename to sdg-core/src/test/res/ltd-samples/BasicBreak.java diff --git a/src/test/res/ltd-samples/BasicContinue.java b/sdg-core/src/test/res/ltd-samples/BasicContinue.java similarity index 100% rename from src/test/res/ltd-samples/BasicContinue.java rename to sdg-core/src/test/res/ltd-samples/BasicContinue.java diff --git a/src/test/res/ltd-samples/BasicForeach.java b/sdg-core/src/test/res/ltd-samples/BasicForeach.java similarity index 100% rename from src/test/res/ltd-samples/BasicForeach.java rename to sdg-core/src/test/res/ltd-samples/BasicForeach.java diff --git a/src/test/res/ltd-samples/BasicIf.java b/sdg-core/src/test/res/ltd-samples/BasicIf.java similarity index 100% rename from src/test/res/ltd-samples/BasicIf.java rename to sdg-core/src/test/res/ltd-samples/BasicIf.java diff --git a/src/test/res/ltd-samples/BasicIfElse.java b/sdg-core/src/test/res/ltd-samples/BasicIfElse.java similarity index 100% rename from src/test/res/ltd-samples/BasicIfElse.java rename to sdg-core/src/test/res/ltd-samples/BasicIfElse.java diff --git a/src/test/res/ltd-samples/BasicSwitch.java b/sdg-core/src/test/res/ltd-samples/BasicSwitch.java similarity index 100% rename from src/test/res/ltd-samples/BasicSwitch.java rename to sdg-core/src/test/res/ltd-samples/BasicSwitch.java diff --git a/src/test/res/ltd-samples/BasicSwitchDefault.java b/sdg-core/src/test/res/ltd-samples/BasicSwitchDefault.java similarity index 100% rename from src/test/res/ltd-samples/BasicSwitchDefault.java rename to sdg-core/src/test/res/ltd-samples/BasicSwitchDefault.java diff --git a/src/test/res/ltd-samples/BasicSwitchNoBreak.java b/sdg-core/src/test/res/ltd-samples/BasicSwitchNoBreak.java similarity index 100% rename from src/test/res/ltd-samples/BasicSwitchNoBreak.java rename to sdg-core/src/test/res/ltd-samples/BasicSwitchNoBreak.java diff --git a/src/test/res/ltd-samples/Bucles_1.java b/sdg-core/src/test/res/ltd-samples/Bucles_1.java similarity index 100% rename from src/test/res/ltd-samples/Bucles_1.java rename to sdg-core/src/test/res/ltd-samples/Bucles_1.java diff --git a/src/test/res/ltd-samples/Bucles_2.java b/sdg-core/src/test/res/ltd-samples/Bucles_2.java similarity index 100% rename from src/test/res/ltd-samples/Bucles_2.java rename to sdg-core/src/test/res/ltd-samples/Bucles_2.java diff --git a/src/test/res/ltd-samples/Bucles_3.java b/sdg-core/src/test/res/ltd-samples/Bucles_3.java similarity index 100% rename from src/test/res/ltd-samples/Bucles_3.java rename to sdg-core/src/test/res/ltd-samples/Bucles_3.java diff --git a/src/test/res/ltd-samples/Bucles_4.java b/sdg-core/src/test/res/ltd-samples/Bucles_4.java similarity index 100% rename from src/test/res/ltd-samples/Bucles_4.java rename to sdg-core/src/test/res/ltd-samples/Bucles_4.java diff --git a/src/test/res/ltd-samples/Bucles_5.java b/sdg-core/src/test/res/ltd-samples/Bucles_5.java similarity index 100% rename from src/test/res/ltd-samples/Bucles_5.java rename to sdg-core/src/test/res/ltd-samples/Bucles_5.java diff --git a/src/test/res/ltd-samples/Bucles_6.java b/sdg-core/src/test/res/ltd-samples/Bucles_6.java similarity index 100% rename from src/test/res/ltd-samples/Bucles_6.java rename to sdg-core/src/test/res/ltd-samples/Bucles_6.java diff --git a/src/test/res/ltd-samples/Bucles_Josep.java b/sdg-core/src/test/res/ltd-samples/Bucles_Josep.java similarity index 100% rename from src/test/res/ltd-samples/Bucles_Josep.java rename to sdg-core/src/test/res/ltd-samples/Bucles_Josep.java diff --git a/src/test/res/ltd-samples/ReturnTest.java b/sdg-core/src/test/res/ltd-samples/ReturnTest.java similarity index 100% rename from src/test/res/ltd-samples/ReturnTest.java rename to sdg-core/src/test/res/ltd-samples/ReturnTest.java diff --git a/src/test/res/ltd-samples/Test_1.java b/sdg-core/src/test/res/ltd-samples/Test_1.java similarity index 100% rename from src/test/res/ltd-samples/Test_1.java rename to sdg-core/src/test/res/ltd-samples/Test_1.java diff --git a/src/test/res/ltd-samples/Test_2.java b/sdg-core/src/test/res/ltd-samples/Test_2.java similarity index 100% rename from src/test/res/ltd-samples/Test_2.java rename to sdg-core/src/test/res/ltd-samples/Test_2.java diff --git a/src/test/res/ltd-samples/Test_3.java b/sdg-core/src/test/res/ltd-samples/Test_3.java similarity index 100% rename from src/test/res/ltd-samples/Test_3.java rename to sdg-core/src/test/res/ltd-samples/Test_3.java diff --git a/src/test/res/ltd-samples/Test_4.java b/sdg-core/src/test/res/ltd-samples/Test_4.java similarity index 100% rename from src/test/res/ltd-samples/Test_4.java rename to sdg-core/src/test/res/ltd-samples/Test_4.java diff --git a/src/test/res/ltd-samples/Test_5.java b/sdg-core/src/test/res/ltd-samples/Test_5.java similarity index 100% rename from src/test/res/ltd-samples/Test_5.java rename to sdg-core/src/test/res/ltd-samples/Test_5.java diff --git a/src/test/res/ltd-samples/Test_6.java b/sdg-core/src/test/res/ltd-samples/Test_6.java similarity index 100% rename from src/test/res/ltd-samples/Test_6.java rename to sdg-core/src/test/res/ltd-samples/Test_6.java diff --git a/src/test/res/ltd-samples/Test_7.java b/sdg-core/src/test/res/ltd-samples/Test_7.java similarity index 100% rename from src/test/res/ltd-samples/Test_7.java rename to sdg-core/src/test/res/ltd-samples/Test_7.java diff --git a/src/test/res/ltd-samples/Test_8.java b/sdg-core/src/test/res/ltd-samples/Test_8.java similarity index 100% rename from src/test/res/ltd-samples/Test_8.java rename to sdg-core/src/test/res/ltd-samples/Test_8.java diff --git a/src/test/res/ltd-samples/Test_9.java b/sdg-core/src/test/res/ltd-samples/Test_9.java similarity index 100% rename from src/test/res/ltd-samples/Test_9.java rename to sdg-core/src/test/res/ltd-samples/Test_9.java diff --git a/src/test/res/papers/Example1_Horwitz_PPDG.java b/sdg-core/src/test/res/papers/Example1_Horwitz_PPDG.java similarity index 100% rename from src/test/res/papers/Example1_Horwitz_PPDG.java rename to sdg-core/src/test/res/papers/Example1_Horwitz_PPDG.java diff --git a/src/test/res/programs/WhileLoop.java b/sdg-core/src/test/res/programs/WhileLoop.java similarity index 100% rename from src/test/res/programs/WhileLoop.java rename to sdg-core/src/test/res/programs/WhileLoop.java diff --git a/src/test/res/programs/cfg/CFG_Test1.java b/sdg-core/src/test/res/programs/cfg/CFG_Test1.java similarity index 100% rename from src/test/res/programs/cfg/CFG_Test1.java rename to sdg-core/src/test/res/programs/cfg/CFG_Test1.java diff --git a/src/test/res/programs/cfg/CFG_Test2.java b/sdg-core/src/test/res/programs/cfg/CFG_Test2.java similarity index 100% rename from src/test/res/programs/cfg/CFG_Test2.java rename to sdg-core/src/test/res/programs/cfg/CFG_Test2.java diff --git a/src/test/res/programs/cfg/CFG_Test3.java b/sdg-core/src/test/res/programs/cfg/CFG_Test3.java similarity index 100% rename from src/test/res/programs/cfg/CFG_Test3.java rename to sdg-core/src/test/res/programs/cfg/CFG_Test3.java diff --git a/src/test/res/programs/cfg/CFG_Test4.java b/sdg-core/src/test/res/programs/cfg/CFG_Test4.java similarity index 100% rename from src/test/res/programs/cfg/CFG_Test4.java rename to sdg-core/src/test/res/programs/cfg/CFG_Test4.java diff --git a/src/test/res/programs/cfg/CFG_Test5.java b/sdg-core/src/test/res/programs/cfg/CFG_Test5.java similarity index 100% rename from src/test/res/programs/cfg/CFG_Test5.java rename to sdg-core/src/test/res/programs/cfg/CFG_Test5.java diff --git a/src/test/res/programs/cfg/Eval_1.java b/sdg-core/src/test/res/programs/cfg/Eval_1.java similarity index 100% rename from src/test/res/programs/cfg/Eval_1.java rename to sdg-core/src/test/res/programs/cfg/Eval_1.java diff --git a/src/test/res/programs/cfg/Eval_2.java b/sdg-core/src/test/res/programs/cfg/Eval_2.java similarity index 100% rename from src/test/res/programs/cfg/Eval_2.java rename to sdg-core/src/test/res/programs/cfg/Eval_2.java diff --git a/src/test/res/programs/cfg/Eval_3.java b/sdg-core/src/test/res/programs/cfg/Eval_3.java similarity index 100% rename from src/test/res/programs/cfg/Eval_3.java rename to sdg-core/src/test/res/programs/cfg/Eval_3.java diff --git a/src/test/res/programs/cfg/Eval_4.java b/sdg-core/src/test/res/programs/cfg/Eval_4.java similarity index 100% rename from src/test/res/programs/cfg/Eval_4.java rename to sdg-core/src/test/res/programs/cfg/Eval_4.java diff --git a/src/test/res/programs/pdg/Example1.java b/sdg-core/src/test/res/programs/pdg/Example1.java similarity index 100% rename from src/test/res/programs/pdg/Example1.java rename to sdg-core/src/test/res/programs/pdg/Example1.java diff --git a/src/test/res/programs/pdg/Example2.java b/sdg-core/src/test/res/programs/pdg/Example2.java similarity index 100% rename from src/test/res/programs/pdg/Example2.java rename to sdg-core/src/test/res/programs/pdg/Example2.java diff --git a/src/test/res/programs/pdg/Example3.java b/sdg-core/src/test/res/programs/pdg/Example3.java similarity index 100% rename from src/test/res/programs/pdg/Example3.java rename to sdg-core/src/test/res/programs/pdg/Example3.java diff --git a/src/test/res/programs/pdg/Test.java b/sdg-core/src/test/res/programs/pdg/Test.java similarity index 100% rename from src/test/res/programs/pdg/Test.java rename to sdg-core/src/test/res/programs/pdg/Test.java diff --git a/src/test/res/programs/sdg/Example1.java b/sdg-core/src/test/res/programs/sdg/Example1.java similarity index 100% rename from src/test/res/programs/sdg/Example1.java rename to sdg-core/src/test/res/programs/sdg/Example1.java diff --git a/src/test/res/programs/sdg/Example2.java b/sdg-core/src/test/res/programs/sdg/Example2.java similarity index 100% rename from src/test/res/programs/sdg/Example2.java rename to sdg-core/src/test/res/programs/sdg/Example2.java diff --git a/src/main/java/tfm/arcs/sdg/ParameterInOutArc.java b/src/main/java/tfm/arcs/sdg/ParameterInOutArc.java deleted file mode 100644 index 50673b700ca84ca8f7e556f209334b5376298f70..0000000000000000000000000000000000000000 --- a/src/main/java/tfm/arcs/sdg/ParameterInOutArc.java +++ /dev/null @@ -1,16 +0,0 @@ -package tfm.arcs.sdg; - -import org.jgrapht.io.Attribute; -import org.jgrapht.io.DefaultAttribute; -import tfm.arcs.Arc; - -import java.util.Map; - -public class ParameterInOutArc extends Arc { - @Override - public Map getDotAttributes() { - Map map = super.getDotAttributes(); - map.put("style", DefaultAttribute.createAttribute("dashed")); - return map; - } -} diff --git a/src/main/java/tfm/exec/Main.java b/src/main/java/tfm/exec/Main.java deleted file mode 100644 index 6d7a54e41a450a85e931b32efde677cbb82f27c4..0000000000000000000000000000000000000000 --- a/src/main/java/tfm/exec/Main.java +++ /dev/null @@ -1,94 +0,0 @@ -package tfm.exec; - -import com.github.javaparser.JavaParser; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.type.Type; -import com.github.javaparser.ast.visitor.GenericVisitor; -import com.github.javaparser.ast.visitor.VoidVisitor; -import com.github.javaparser.resolution.types.ResolvedType; -import tfm.graphs.cfg.CFG; -import tfm.graphs.Graph; -import tfm.graphs.pdg.PDG; -import tfm.graphs.sdg.SDG; -import tfm.utils.Logger; -import tfm.utils.Utils; - -import java.io.File; -import java.io.IOException; -import java.util.Objects; -import java.util.Optional; - -public class Main { - - public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "sdg/Example1.java"; - public static final String GRAPH = GraphLog.PDG; - public static final String METHOD = "main"; - - public static void main(String[] args) throws IOException { - JavaParser.getStaticConfiguration().setAttributeComments(false); - - // File - File file = new File(PROGRAM); - Node root = JavaParser.parse(file); - - if (!METHOD.isEmpty()) { - Optional methodDeclarationOptional = root.findFirst(MethodDeclaration.class, - methodDeclaration -> Objects.equals(methodDeclaration.getNameAsString(), METHOD)); - - if (!methodDeclarationOptional.isPresent()) { - Logger.format("Method '%s' not found in '%s'. Exiting...", METHOD, PROGRAM); - return; - } - - root = methodDeclarationOptional.get(); - } - - // GraphLog - long t0 = System.nanoTime(); - Graph graph = getBuiltGraph(args.length == 1 ? args[0] : GRAPH, (MethodDeclaration) root); - long tf = System.nanoTime(); - long tt = tf - t0; - - GraphLog graphLog = getGraphLog(graph); - graphLog.log(); - graphLog.openVisualRepresentation(); - - Logger.log(); - Logger.format("Graph generated in %.2f ms", tt / 10e6); - } - - private static Graph getBuiltGraph(String graph, MethodDeclaration method) { - switch (graph) { - case GraphLog.CFG: - CFG cfg = new CFG(); - cfg.build(method); - return cfg; - case GraphLog.PDG: - PDG pdg = new PDG(); - pdg.build(method); - return pdg; - case GraphLog.SDG: - SDG sdg = new SDG(); - sdg.build(new NodeList<>(method.findCompilationUnit().get())); - return sdg; - default: - Logger.log("Unkown graph type"); - System.exit(1); - return null; - } - } - - private static GraphLog getGraphLog(Graph graph) { - if (graph instanceof CFG) - return new CFGLog((CFG) graph); - else if (graph instanceof PDG) - return new PDGLog((PDG) graph); - else if (graph instanceof SDG) - return new SDGLog((SDG) graph); - Logger.log("Unknown graph type"); - System.exit(1); - return null; - } -} diff --git a/src/main/java/tfm/exec/MethodResolver.java b/src/main/java/tfm/exec/MethodResolver.java deleted file mode 100644 index e2d28d6ccb7267ca43d700e6b042a3d7ce0cb09b..0000000000000000000000000000000000000000 --- a/src/main/java/tfm/exec/MethodResolver.java +++ /dev/null @@ -1,105 +0,0 @@ -package tfm.exec; - -import com.github.javaparser.JavaParser; -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.body.AnnotationDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.expr.MethodCallExpr; -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import com.github.javaparser.resolution.UnsolvedSymbolException; -import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; -import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; -import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; -import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; -import tfm.graphs.sdg.SDG; -import tfm.nodes.GraphNode; -import tfm.utils.Context; -import tfm.utils.Logger; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.Arrays; -import java.util.Optional; - -public class MethodResolver { - - private static class Args { - String file; - String method; - } - - public static void main(String[] inputArgs) throws FileNotFoundException { - Args args = parseArgs(inputArgs); - - CompilationUnit cu = JavaParser.parse(new File(args.file)); - - SDG sdg = new SDG(); - sdg.build(new NodeList<>(cu)); - - VoidVisitorAdapter visitor = new VoidVisitorAdapter() { - @Override - public void visit(MethodCallExpr n, Void arg) { - TypeSolver solver = new JavaParserTypeSolver(args.file.substring(0, args.file.lastIndexOf('/'))); - - Logger.log("-- Trying to solve method " + n.getNameAsString() + " --"); - - Optional optionalResolvedMethod; - - try { - optionalResolvedMethod = getMethodCallWithJavaParserSymbolSolver(n, solver, new ReflectionTypeSolver()); - } catch (UnsolvedSymbolException e) { - optionalResolvedMethod = Optional.empty(); - } - - if (!optionalResolvedMethod.isPresent()) { - Logger.format("Not found: %s", n); - return; - } - - Logger.format("Found: %s", n.getNameAsString()); - Logger.log(optionalResolvedMethod.get().getSignature().asString()); - - Logger.log("-- Trying to match with a node from SDG --"); - Optional> methodDeclarationNode = optionalResolvedMethod.flatMap(sdg::findNodeByASTNode); - - if (!methodDeclarationNode.isPresent()) { - Logger.log("Failed to find node in SDG"); - return; - } - - Logger.format("SDG node: %s", methodDeclarationNode.get()); - - } - }; - - cu.accept(visitor, null); - } - - private static Args parseArgs(String[] args) { - Args res = new Args(); - - Logger.log(Arrays.asList(args)); - - try { - res.file = args[0]; - // res.method = args[2]; - } catch (Exception e) { - Logger.log("Incorrect syntax: java MethodResolver.class "); - System.exit(1); - } - - return res; - } - - private static Optional getMethodCallWithJavaParserSymbolSolver(MethodCallExpr methodCallExpr, TypeSolver... solvers) { - CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(solvers); - - SymbolReference solver = JavaParserFacade.get(combinedTypeSolver).solve(methodCallExpr); - - return solver.isSolved() ? solver.getCorrespondingDeclaration().toAst() : Optional.empty(); - } -} diff --git a/src/main/java/tfm/graphs/augmented/PPDG.java b/src/main/java/tfm/graphs/augmented/PPDG.java deleted file mode 100644 index c864533e2a48e947e1fb45cf8c432284b26264a1..0000000000000000000000000000000000000000 --- a/src/main/java/tfm/graphs/augmented/PPDG.java +++ /dev/null @@ -1,41 +0,0 @@ -package tfm.graphs.augmented; - -import tfm.arcs.Arc; -import tfm.nodes.GraphNode; -import tfm.slicing.Slice; -import tfm.utils.ASTUtils; - -public class PPDG extends APDG { - public PPDG() { - this(new ACFG()); - } - - public PPDG(ACFG acfg) { - super(acfg); - } - - @Override - protected void getSliceNodes(Slice slice, GraphNode node) { - slice.add(node); - - for (Arc arc : incomingEdgesOf(node)) { - GraphNode from = getEdgeSource(arc); - if (slice.contains(from)) - continue; - getSliceNodesPPDG(slice, from); - } - } - - protected void getSliceNodesPPDG(Slice slice, GraphNode node) { - slice.add(node); - if (ASTUtils.isPseudoPredicate(node.getAstNode())) - return; - - for (Arc arc : incomingEdgesOf(node)) { - GraphNode from = getEdgeSource(arc); - if (slice.contains(from)) - continue; - getSliceNodesPPDG(slice, from); - } - } -} diff --git a/src/main/java/tfm/slicing/SliceAstVisitor.java b/src/main/java/tfm/slicing/SliceAstVisitor.java deleted file mode 100644 index 63f187c59d408a94a75f465a7be139a76996c8eb..0000000000000000000000000000000000000000 --- a/src/main/java/tfm/slicing/SliceAstVisitor.java +++ /dev/null @@ -1,118 +0,0 @@ -package tfm.slicing; - -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.expr.BooleanLiteralExpr; -import com.github.javaparser.ast.nodeTypes.NodeWithBody; -import com.github.javaparser.ast.stmt.*; -import com.github.javaparser.ast.visitor.ModifierVisitor; -import com.github.javaparser.ast.visitor.Visitable; - -import java.util.stream.Collectors; - -public class SliceAstVisitor extends ModifierVisitor { - @Override - public Visitable visit(BreakStmt n, Slice arg) { - return arg.contains(n) ? n : null; - } - - @Override - public Visitable visit(ContinueStmt n, Slice arg) { - return arg.contains(n) ? n : null; - } - - @Override - public Visitable visit(DoStmt n, Slice arg) { - boolean keep = arg.contains(n); - super.visit(n, arg); - fillBody(n); - return keep ? n : null; - } - - @Override - public Visitable visit(ForEachStmt n, Slice arg) { - boolean keep = arg.contains(n); - super.visit(n, arg); - fillBody(n); - return keep ? n : null; - } - - @Override - public Visitable visit(ForStmt n, Slice arg) { - boolean keep = arg.contains(n); - super.visit(n, arg); - n.setInitialization(new NodeList<>(n.getInitialization().stream() - .filter(arg::contains).collect(Collectors.toList()))); - n.setUpdate(new NodeList<>(n.getUpdate().stream() - .filter(arg::contains).collect(Collectors.toList()))); - fillBody(n); - if (keep) - return n; - if (n.getInitialization().isEmpty() && n.getUpdate().isEmpty()) - return null; - return new ForStmt(n.getInitialization(), new BooleanLiteralExpr(false), - n.getUpdate(), n.getBody()); - } - - @Override - public Visitable visit(WhileStmt n, Slice arg) { - boolean keep = arg.contains(n); - super.visit(n, arg); - fillBody(n); - return keep ? n : null; - } - - @Override - public Visitable visit(IfStmt n, Slice arg) { - boolean keep = arg.contains(n); - super.visit(n, arg); - if (n.getThenStmt() == null) - n.setThenStmt(new EmptyStmt()); - return keep ? n : null; - } - - @Override - public Visitable visit(LabeledStmt n, Slice arg) { - super.visit(n, arg); - return n.getStatement() != null ? n : null; - } - - @Override - public Visitable visit(ReturnStmt n, Slice arg) { - return arg.contains(n) ? n : null; - } - - @Override - public Visitable visit(ThrowStmt n, Slice arg) { - return arg.contains(n) ? n : null; - } - - @Override - public Visitable visit(SwitchEntryStmt n, Slice arg) { - boolean keep = arg.contains(n); - super.visit(n, arg); - if (!n.getStatements().isEmpty()) - return n; - return keep ? n : null; - } - - @Override - public Visitable visit(SwitchStmt n, Slice arg) { - boolean keep = arg.contains(n); - super.visit(n, arg); - return keep ? n : null; - } - - @Override - public Visitable visit(ExpressionStmt n, Slice arg) { - return arg.contains(n) ? n : null; - } - - private void fillBody(Node n) { - if (!(n instanceof NodeWithBody)) - return; - NodeWithBody nb = ((NodeWithBody) n); - if (nb.getBody() == null) - nb.setBody(new EmptyStmt()); - } -} diff --git a/src/main/java/tfm/utils/MethodDeclarationSolver.java b/src/main/java/tfm/utils/MethodDeclarationSolver.java deleted file mode 100644 index b6e7ebab3061ada67e5115dab52bc4bae6afad1a..0000000000000000000000000000000000000000 --- a/src/main/java/tfm/utils/MethodDeclarationSolver.java +++ /dev/null @@ -1,48 +0,0 @@ -package tfm.utils; - -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.expr.MethodCallExpr; -import com.github.javaparser.resolution.UnsolvedSymbolException; -import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; -import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; -import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; -import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; - -import java.util.*; - -public class MethodDeclarationSolver { - - private static final MethodDeclarationSolver instance = new MethodDeclarationSolver(); - private static final List usedTypeSolvers = new ArrayList<>(); - - private MethodDeclarationSolver() { - - } - - public static void addTypeSolvers(TypeSolver... typeSolvers) { - usedTypeSolvers.addAll(Arrays.asList(typeSolvers)); - } - - public static MethodDeclarationSolver getInstance() { - return instance; - } - - public Optional findDeclarationFrom(MethodCallExpr methodCallExpr) { - return this.findDeclarationFrom(methodCallExpr, usedTypeSolvers); - } - - public Optional findDeclarationFrom(MethodCallExpr methodCallExpr, Collection customTypeSolvers) { - CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(customTypeSolvers.toArray(new TypeSolver[0])); - - try { - SymbolReference solver = JavaParserFacade.get(combinedTypeSolver).solve(methodCallExpr); - - return solver.isSolved() - ? solver.getCorrespondingDeclaration().toAst() - : Optional.empty(); - } catch (UnsolvedSymbolException e) { - return Optional.empty(); - } - } -}