From 07e1c5a55c893ecc6fdad5be73096d6d6e079870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Lars=C3=A9n?= Date: Wed, 4 Mar 2020 10:57:32 +0100 Subject: [PATCH] [feat] Compare with gumtree-spoon, ignoring comments, fix #45 --- src/main/java/se/kth/spork/cli/Cli.java | 28 +++++++++++++------ src/main/java/se/kth/spork/spoon/Compare.java | 14 ++++++++++ src/main/java/se/kth/spork/spoon/Parser.java | 17 +++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/main/java/se/kth/spork/cli/Cli.java b/src/main/java/se/kth/spork/cli/Cli.java index 5f92d5c5..05cc5f63 100644 --- a/src/main/java/se/kth/spork/cli/Cli.java +++ b/src/main/java/se/kth/spork/cli/Cli.java @@ -1,5 +1,7 @@ package se.kth.spork.cli; +import gumtree.spoon.AstComparator; +import gumtree.spoon.diff.Diff; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import picocli.CommandLine; @@ -69,7 +71,7 @@ public Integer call() { } @CommandLine.Command(name = "compare", mixinStandardHelpOptions = true, - description = "Compare the ASTs of two Java files, disregarding the order of unordered elements") + description = "Compare the ASTs of two Java files, disregarding comments and the order of unordered elements") private static class CompareCommand implements Callable { @CommandLine.Parameters(index = "0", paramLabel = "LEFT", description = "Path to a Java file") File left; @@ -79,16 +81,26 @@ private static class CompareCommand implements Callable { @Override public Integer call() { - CtModule leftModule = Parser.parse(left.toPath()); - CtModule rightModule = Parser.parse(right.toPath()); + CtModule leftModule = Parser.parseWithoutComments(left.toPath()); + CtModule rightModule = Parser.parseWithoutComments(right.toPath()); + + Compare.sortUnorderedElements(leftModule); + Compare.sortUnorderedElements(rightModule); - if (Compare.compare(leftModule, rightModule)) { - LOGGER.info("The ASTs are equal"); - return 0; + Object leftImports = leftModule.getMetadata(Parser.IMPORT_STATEMENTS); + Object rightImports = rightModule.getMetadata(Parser.IMPORT_STATEMENTS); + + Diff diff = new AstComparator().compare(leftModule, rightModule); + System.out.println(diff); + + boolean importsEqual = leftImports.equals(rightImports); + if (!importsEqual) { + LOGGER.warn("Import statements differ"); + LOGGER.info("Left: " + leftImports); + LOGGER.info("Right: " + rightImports); } - LOGGER.info("The ASTs differ"); - return 1; + return diff.getRootOperations().isEmpty() && importsEqual ? 0 : 1; } } diff --git a/src/main/java/se/kth/spork/spoon/Compare.java b/src/main/java/se/kth/spork/spoon/Compare.java index acb382ab..d3659417 100644 --- a/src/main/java/se/kth/spork/spoon/Compare.java +++ b/src/main/java/se/kth/spork/spoon/Compare.java @@ -40,6 +40,20 @@ public static boolean compare(CtModule left, CtModule right) { compare(left.getRootPackage().clone(), right.getRootPackage().clone()); } + /** + * Sort the unordered elements of the provided module. + * + * @param mod A Spoon unnamed module. + */ + public static void sortUnorderedElements(CtModule mod) { + sortUnorderedElements(mod.getRootPackage()); + } + + private static void sortUnorderedElements(CtPackage pkg) { + pkg.getTypes().forEach(Compare::sortTypeMembers); + pkg.getPackages().forEach(Compare::sortUnorderedElements); + } + /** * Compare the left package with the right package, without regard to the order of unordered type * members. diff --git a/src/main/java/se/kth/spork/spoon/Parser.java b/src/main/java/se/kth/spork/spoon/Parser.java index 7be7beeb..e144feae 100644 --- a/src/main/java/se/kth/spork/spoon/Parser.java +++ b/src/main/java/se/kth/spork/spoon/Parser.java @@ -44,6 +44,23 @@ public static CtModule parse(String javaFileContents) { return parse(launcher -> launcher.addInputResource(new VirtualFile(javaFileContents))); } + /** + * Parse a Java file to a Spoon tree. Any import statements in the file are attached to the returned module's + * metadata with the {@link Parser#IMPORT_STATEMENTS} key. The imports are sorted in ascending lexicographical + * order. + * + * Comments are ignored + * + * @param javaFile Path to a Java file. + * @return The root module of the Spoon tree. + */ + public static CtModule parseWithoutComments(Path javaFile) { + return parse(launcher -> { + launcher.getEnvironment().setCommentEnabled(false); + launcher.addInputResource(new VirtualFile(read(javaFile))); + }); + } + private static CtModule parse(Consumer addResource) { Launcher launcher = new Launcher(); launcher.getEnvironment().setPrettyPrinterCreator(