From 40f6fef078275d3ca43f02918200a2d6076fef9d Mon Sep 17 00:00:00 2001 From: Thomas Leu Date: Sat, 19 May 2018 01:51:14 +0200 Subject: [PATCH] Moved DifferenceElement classes and static methods to new class DifferenceElementCalculator --- .../lexicalpreservation/DifferenceTest.java | 92 +-- .../LexicalDifferenceCalculatorTest.java | 14 +- .../lexicalpreservation/Difference.java | 523 +----------------- .../DifferenceElementCalculator.java | 474 ++++++++++++++++ .../LexicalDifferenceCalculator.java | 8 +- 5 files changed, 560 insertions(+), 551 deletions(-) create mode 100644 javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/DifferenceElementCalculator.java diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/DifferenceTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/DifferenceTest.java index 2fb98c1f5d..0d985f6354 100644 --- a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/DifferenceTest.java +++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/DifferenceTest.java @@ -27,7 +27,7 @@ import static com.github.javaparser.TokenTypes.eolTokenKind; import static com.github.javaparser.TokenTypes.spaceTokenKind; -import static com.github.javaparser.printer.lexicalpreservation.Difference.DifferenceElement.*; +import static com.github.javaparser.printer.lexicalpreservation.DifferenceElementCalculator.DifferenceElement.*; import static org.junit.Assert.assertEquals; public class DifferenceTest extends AbstractLexicalPreservingTest { @@ -36,7 +36,7 @@ public class DifferenceTest extends AbstractLexicalPreservingTest { public void calculateDifferenceEmpty() { LexicalDifferenceCalculator.CalculatedSyntaxModel a = new LexicalDifferenceCalculator.CalculatedSyntaxModel(Collections.emptyList()); LexicalDifferenceCalculator.CalculatedSyntaxModel b = new LexicalDifferenceCalculator.CalculatedSyntaxModel(Collections.emptyList()); - Difference diff = Difference.calculate(a, b); + Difference diff = DifferenceElementCalculator.calculate(a, b); assertEquals(0, diff.getElements().size()); } @@ -51,7 +51,7 @@ public void calculateDifferenceAIsEmpty() { new CsmChild(n1), new CsmToken(GeneratedJavaParserConstants.RPAREN), new CsmChild(n2))); - Difference diff = Difference.calculate(a, b); + Difference diff = DifferenceElementCalculator.calculate(a, b); assertEquals(4, diff.getElements().size()); assertEquals(added(new CsmToken(GeneratedJavaParserConstants.LPAREN)), diff.getElements().get(0)); assertEquals(added(new CsmChild(n1)), diff.getElements().get(1)); @@ -70,7 +70,7 @@ public void calculateDifferenceBIsEmpty() { new CsmToken(GeneratedJavaParserConstants.RPAREN), new CsmChild(n2))); LexicalDifferenceCalculator.CalculatedSyntaxModel b = new LexicalDifferenceCalculator.CalculatedSyntaxModel(Collections.emptyList()); - Difference diff = Difference.calculate(a, b); + Difference diff = DifferenceElementCalculator.calculate(a, b); assertEquals(4, diff.getElements().size()); assertEquals(removed(new CsmToken(GeneratedJavaParserConstants.LPAREN)), diff.getElements().get(0)); assertEquals(removed(new CsmChild(n1)), diff.getElements().get(1)); @@ -85,7 +85,7 @@ public void compilationUnitExampleWithPackageSetDiff() { PackageDeclaration packageDeclaration = new PackageDeclaration(new Name(new Name("foo"), "bar")); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, cu); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, cu, ObservableProperty.PACKAGE_DECLARATION, null, packageDeclaration); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); assertEquals(3, diff.getElements().size()); assertEquals(added(new CsmChild(packageDeclaration)), diff.getElements().get(0)); assertEquals(kept(new CsmChild(cu.getType(0))), diff.getElements().get(1)); @@ -99,7 +99,7 @@ public void annotationDeclarationExampleWithModifierAdded() throws IOException { CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, annotationDeclaration); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.MODIFIERS, EnumSet.noneOf(Modifier.class), EnumSet.of(Modifier.PUBLIC)); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); diff.removeIndentationElements(); int i = 0; assertEquals(added(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); @@ -136,7 +136,7 @@ public void annotationDeclarationExampleWithNameChanged() throws IOException { SimpleName newName = new SimpleName("NewName"); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.NAME, annotationDeclaration.getName(), newName); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); diff.removeIndentationElements(); int i = 0; assertEquals(kept(new CsmToken(GeneratedJavaParserConstants.AT)), diff.getElements().get(i++)); @@ -171,7 +171,7 @@ public void annotationDeclarationExampleWithJavadocAdded() throws IOException { JavadocComment comment = new JavadocComment("Cool this annotation!"); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, annotationDeclaration); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.COMMENT, null, comment); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); diff.removeIndentationElements(); int i = 0; assertEquals(kept(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); @@ -206,7 +206,7 @@ public void annotationDeclarationExampleWithJavadocRemoved() throws IOException CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, annotationDeclaration); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.COMMENT, annotationDeclaration.getComment().get(), null); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); diff.removeIndentationElements(); int i = 0; assertEquals(kept(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); @@ -241,7 +241,7 @@ public void annotationDeclarationExampleWithModifierRemoved() throws IOException CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, annotationDeclaration); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.MODIFIERS, EnumSet.of(Modifier.PUBLIC), EnumSet.noneOf(Modifier.class)); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); diff.removeIndentationElements(); int i = 0; assertEquals(removed(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); @@ -274,7 +274,7 @@ public void removeDefaultValueInAnnotationMemberDeclaration() { AnnotationMemberDeclaration md = considerAmd("int foo() default 10;"); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(md); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(md, ObservableProperty.DEFAULT_VALUE, md.getDefaultValue(), null); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); int i = 0; assertEquals(kept(new CsmChild(md.getType())), diff.getElements().get(i++)); assertEquals(kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); @@ -295,7 +295,7 @@ public void addedDefaultValueInAnnotationMemberDeclaration() { LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(md); Expression defaultValue = new IntegerLiteralExpr(("10")); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(md, ObservableProperty.DEFAULT_VALUE, null, defaultValue); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); int i = 0; assertEquals(kept(new CsmChild(md.getType())), diff.getElements().get(i++)); assertEquals(kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); @@ -316,7 +316,7 @@ public void addedModifierToConstructorDeclaration() { LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(cd); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(cd, ObservableProperty.MODIFIERS, EnumSet.noneOf(Modifier.class), EnumSet.of(Modifier.PUBLIC)); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); int i = 0; assertEquals(added(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); assertEquals(added(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); @@ -335,10 +335,10 @@ public void replacingNameForEnumConstantDeclaration() throws IOException { LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(ecd); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(ecd, ObservableProperty.NAME, ecd.getName(), newName); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); int i = 0; - assertEquals(Difference.DifferenceElement.removed(new CsmChild(ecd.getName())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.added(new CsmChild(newName)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.removed(new CsmChild(ecd.getName())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(new CsmChild(newName)), diff.getElements().get(i++)); assertEquals(i, diff.getElements().size()); } @@ -353,15 +353,15 @@ public void addingStatementToEmptyMethodBody() { MethodDeclaration m = cu.getClassByName("A").get().getMethodsByName("foo").get(0); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(m.getBody().get()); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterListAddition(m.getBody().get(), ObservableProperty.STATEMENTS, 0, s); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); int i = 0; - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.LBRACE)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(eolTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.added(new CsmIndent()), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.added(new CsmChild(s)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.added(new CsmToken(eolTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.added(new CsmUnindent()), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.RBRACE)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.LBRACE)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(eolTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(new CsmIndent()), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(new CsmChild(s)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(new CsmToken(eolTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(new CsmUnindent()), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.RBRACE)), diff.getElements().get(i++)); assertEquals(i, diff.getElements().size()); } @@ -370,18 +370,18 @@ public void methodDeclarationRemovingParameter() { MethodDeclaration md = considerMd("public void foo(float f){}"); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(md); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterListRemoval(md, ObservableProperty.PARAMETERS, 0); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); int i = 0; - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmChild(md.getType())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmChild(md.getName())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.LPAREN)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.removed(new CsmChild(md.getParameter(0))), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.RPAREN)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmChild(md.getBody().get())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmChild(md.getType())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmChild(md.getName())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.LPAREN)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.removed(new CsmChild(md.getParameter(0))), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.RPAREN)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmChild(md.getBody().get())), diff.getElements().get(i++)); assertEquals(i, diff.getElements().size()); } @@ -391,18 +391,18 @@ public void methodDeclarationAddingParameter() { Parameter newParameter = new Parameter(new ArrayType(PrimitiveType.intType()), new SimpleName("foo")); LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(md); LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterListAddition(md, ObservableProperty.PARAMETERS, 0, newParameter); - Difference diff = Difference.calculate(csmOriginal, csmChanged); + Difference diff = DifferenceElementCalculator.calculate(csmOriginal, csmChanged); int i = 0; - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmChild(md.getType())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmChild(md.getName())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.LPAREN)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.added(new CsmChild(newParameter)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.RPAREN)), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); - assertEquals(Difference.DifferenceElement.kept(new CsmChild(md.getBody().get())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.PUBLIC)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmChild(md.getType())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmChild(md.getName())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.LPAREN)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(new CsmChild(newParameter)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(GeneratedJavaParserConstants.RPAREN)), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmToken(spaceTokenKind())), diff.getElements().get(i++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(new CsmChild(md.getBody().get())), diff.getElements().get(i++)); assertEquals(i, diff.getElements().size()); } diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculatorTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculatorTest.java index d3e5490c0b..776e42dbbc 100644 --- a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculatorTest.java +++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculatorTest.java @@ -275,17 +275,17 @@ public void differenceAfterddingStatementToEmptyBlock() throws IOException { 0, assignStatement); int index = 0; - assertEquals(Difference.DifferenceElement.kept(CsmElement.token(GeneratedJavaParserConstants.LBRACE)), diff.getElements().get(index++)); - assertEquals(Difference.DifferenceElement.kept(CsmElement.newline()), diff.getElements().get(index++)); - assertEquals(Difference.DifferenceElement.added(CsmElement.indent()), diff.getElements().get(index++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(CsmElement.token(GeneratedJavaParserConstants.LBRACE)), diff.getElements().get(index++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(CsmElement.newline()), diff.getElements().get(index++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(CsmElement.indent()), diff.getElements().get(index++)); assertTrue(isAddedChild(diff.getElements().get(index++), ExpressionStmt.class)); - assertEquals(Difference.DifferenceElement.added(CsmElement.newline()), diff.getElements().get(index++)); - assertEquals(Difference.DifferenceElement.added(CsmElement.unindent()), diff.getElements().get(index++)); - assertEquals(Difference.DifferenceElement.kept(CsmElement.token(GeneratedJavaParserConstants.RBRACE)), diff.getElements().get(index++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(CsmElement.newline()), diff.getElements().get(index++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.added(CsmElement.unindent()), diff.getElements().get(index++)); + assertEquals(DifferenceElementCalculator.DifferenceElement.kept(CsmElement.token(GeneratedJavaParserConstants.RBRACE)), diff.getElements().get(index++)); assertEquals(index, diff.getElements().size()); } - private boolean isAddedChild(Difference.DifferenceElement element, Class childClass) { + private boolean isAddedChild(DifferenceElementCalculator.DifferenceElement element, Class childClass) { return element.isAdded() && isChild(element.getElement(), childClass); } diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java index 3b60accb62..3e20087648 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java +++ b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java @@ -4,7 +4,6 @@ import com.github.javaparser.TokenTypes; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.comments.Comment; -import com.github.javaparser.ast.type.PrimitiveType; import com.github.javaparser.printer.concretesyntaxmodel.*; import com.github.javaparser.printer.lexicalpreservation.LexicalDifferenceCalculator.CsmChild; @@ -22,476 +21,12 @@ public class Difference { private static final int STANDARD_INDENTATION_SIZE = 4; - private final List elements; + private final List elements; - private Difference(List elements) { + Difference(List elements) { this.elements = elements; } - interface DifferenceElement { - static DifferenceElement added(CsmElement element) { - return new Added(element); - } - - static DifferenceElement removed(CsmElement element) { - return new Removed(element); - } - - static DifferenceElement kept(CsmElement element) { - return new Kept(element); - } - - /** - * Return the CsmElement considered in this DifferenceElement. - */ - CsmElement getElement(); - - boolean isAdded(); - } - - private static class Added implements DifferenceElement { - final CsmElement element; - - Added(CsmElement element) { - this.element = element; - } - - @Override - public String toString() { - return "Added{" + element + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Added added = (Added) o; - - return element.equals(added.element); - } - - @Override - public int hashCode() { - return element.hashCode(); - } - - @Override - public CsmElement getElement() { - return element; - } - - @Override - public boolean isAdded() { - return true; - } - - boolean isIndent() { return element instanceof CsmIndent; } - - boolean isUnindent() { return element instanceof CsmUnindent; } - - TextElement toTextElement() { - if (element instanceof CsmChild) { - return new ChildTextElement(((CsmChild) element).getChild()); - } else if (element instanceof CsmToken) { - return new TokenTextElement(((CsmToken) element).getTokenType(), ((CsmToken) element).getContent(null)); - } else { - throw new UnsupportedOperationException(element.getClass().getSimpleName()); - } - } - } - - /** - * Elements in a CsmMix have been reshuffled. It could also mean that - * some new elements have been added or removed to the mix. - */ - private static class Reshuffled implements DifferenceElement { - final CsmMix previousOrder; - final CsmMix element; - - Reshuffled(CsmMix previousOrder, CsmMix element) { - this.previousOrder = previousOrder; - this.element = element; - } - - @Override - public String toString() { - return "Reshuffled{" + element + ", previous="+ previousOrder+ '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Reshuffled that = (Reshuffled) o; - - if (!previousOrder.equals(that.previousOrder)) return false; - return element.equals(that.element); - } - - @Override - public int hashCode() { - int result = previousOrder.hashCode(); - result = 31 * result + element.hashCode(); - return result; - } - - @Override - public CsmMix getElement() { - return element; - } - - @Override - public boolean isAdded() { - return false; - } - } - - private static class Kept implements DifferenceElement { - final CsmElement element; - - Kept(CsmElement element) { - this.element = element; - } - - @Override - public String toString() { - return "Kept{" + element + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Kept kept = (Kept) o; - - return element.equals(kept.element); - } - - @Override - public int hashCode() { - return element.hashCode(); - } - - @Override - public CsmElement getElement() { - return element; - } - - int getTokenType() { - if (isToken()) { - CsmToken csmToken = (CsmToken) element; - return csmToken.getTokenType(); - } - - throw new IllegalStateException("Kept is not a " + CsmToken.class.getSimpleName()); - } - - @Override - public boolean isAdded() { - return false; - } - - boolean isIndent() { return element instanceof CsmIndent; } - - boolean isUnindent() { return element instanceof CsmUnindent; } - - boolean isToken() { return element instanceof CsmToken; } - - boolean isChild() { return element instanceof CsmChild; } - - boolean isPrimitiveType() { - if (isChild()) { - CsmChild csmChild = (CsmChild) element; - return csmChild.getChild() instanceof PrimitiveType; - } - - return false; - } - - boolean isWhiteSpace() { - if(isToken()) { - CsmToken csmToken = (CsmToken) element; - return csmToken.isWhiteSpace(); - } - - return false; - } - - boolean isWhiteSpaceOrComment() { - if (isToken()) { - CsmToken csmToken = (CsmToken) element; - return TokenTypes.isWhitespaceOrComment(csmToken.getTokenType()); - } - - return false; - } - } - - private static class Removed implements DifferenceElement { - final CsmElement element; - - Removed(CsmElement element) { - this.element = element; - } - - @Override - public String toString() { - return "Removed{" + element + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Removed removed = (Removed) o; - - return element.equals(removed.element); - } - - @Override - public int hashCode() { - return element.hashCode(); - } - - @Override - public CsmElement getElement() { - return element; - } - - Node getChild() { - if (isChild()) { - CsmChild csmChild = (CsmChild) element; - return csmChild.getChild(); - } - - throw new IllegalStateException("Removed is not a " + CsmChild.class.getSimpleName()); - } - - int getTokenType() { - if (isToken()) { - CsmToken csmToken = (CsmToken) element; - return csmToken.getTokenType(); - } - - throw new IllegalStateException("Removed is not a " + CsmToken.class.getSimpleName()); - } - - @Override - public boolean isAdded() { - return false; - } - - boolean isToken() { return element instanceof CsmToken; } - - boolean isChild() { return element instanceof CsmChild; } - - boolean isPrimitiveType() { - if (isChild()) { - CsmChild csmChild = (CsmChild) element; - return csmChild.getChild() instanceof PrimitiveType; - } - - return false; - } - - boolean isWhiteSpace() { - if(isToken()) { - CsmToken csmToken = (CsmToken) element; - return csmToken.isWhiteSpace(); - } - - return false; - } - } - - private static boolean matching(CsmElement a, CsmElement b) { - if (a instanceof CsmChild) { - if (b instanceof CsmChild) { - CsmChild childA = (CsmChild) a; - CsmChild childB = (CsmChild) b; - return childA.getChild().equals(childB.getChild()); - } else if (b instanceof CsmToken) { - return false; - } else if (b instanceof CsmIndent) { - return false; - } else if (b instanceof CsmUnindent) { - return false; - } else { - throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); - } - } else if (a instanceof CsmToken) { - if (b instanceof CsmToken) { - CsmToken childA = (CsmToken)a; - CsmToken childB = (CsmToken)b; - return childA.getTokenType() == childB.getTokenType(); - } else if (b instanceof CsmChild) { - return false; - } else if (b instanceof CsmIndent) { - return false; - } else if (b instanceof CsmUnindent) { - return false; - } else { - throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); - } - } else if (a instanceof CsmIndent) { - return b instanceof CsmIndent; - } else if (a instanceof CsmUnindent) { - return b instanceof CsmUnindent; - } - throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); - } - - private static boolean replacement(CsmElement a, CsmElement b) { - if (a instanceof CsmIndent || b instanceof CsmIndent || a instanceof CsmUnindent || b instanceof CsmUnindent) { - return false; - } - if (a instanceof CsmChild) { - if (b instanceof CsmChild) { - CsmChild childA = (CsmChild) a; - CsmChild childB = (CsmChild) b; - return childA.getChild().getClass().equals(childB.getChild().getClass()); - } else if (b instanceof CsmToken) { - return false; - } else { - throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); - } - } else if (a instanceof CsmToken) { - if (b instanceof CsmToken) { - CsmToken childA = (CsmToken)a; - CsmToken childB = (CsmToken)b; - return childA.getTokenType() == childB.getTokenType(); - } else if (b instanceof CsmChild) { - return false; - } - } - throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); - } - - /** - * Find the positions of all the given children. - */ - private static Map findChildrenPositions(LexicalDifferenceCalculator.CalculatedSyntaxModel calculatedSyntaxModel) { - Map positions = new HashMap<>(); - for (int i=0;i childrenInOriginal = findChildrenPositions(original); - Map childrenInAfter = findChildrenPositions(after); - - List commonChildren = new LinkedList<>(childrenInOriginal.keySet()); - commonChildren.retainAll(childrenInAfter.keySet()); - commonChildren.sort(Comparator.comparingInt(childrenInOriginal::get)); - - List elements = new LinkedList<>(); - - int originalIndex = 0; - int afterIndex = 0; - int commonChildrenIndex = 0; - while (commonChildrenIndex < commonChildren.size()) { - Node child = commonChildren.get(commonChildrenIndex++); - int posOfNextChildInOriginal = childrenInOriginal.get(child); - int posOfNextChildInAfter = childrenInAfter.get(child); - if (originalIndex < posOfNextChildInOriginal || afterIndex < posOfNextChildInAfter) { - elements.addAll(calculateImpl(original.sub(originalIndex, posOfNextChildInOriginal), after.sub(afterIndex, posOfNextChildInAfter)).elements); - } - elements.add(new Kept(new CsmChild(child))); - originalIndex = posOfNextChildInOriginal + 1; - afterIndex = posOfNextChildInAfter + 1; - } - - if (originalIndex < original.elements.size() || afterIndex < after.elements.size()) { - elements.addAll(calculateImpl(original.sub(originalIndex, original.elements.size()), after.sub(afterIndex, after.elements.size())).elements); - } - return new Difference(elements); - } - - private static Difference calculateImpl(LexicalDifferenceCalculator.CalculatedSyntaxModel original, LexicalDifferenceCalculator.CalculatedSyntaxModel after) { - List elements = new LinkedList<>(); - - int originalIndex = 0; - int afterIndex = 0; - - // We move through the two CalculatedSyntaxModel, moving both forward when we have a match - // and moving just one side forward when we have an element kept or removed - - do { - if (originalIndex < original.elements.size() && afterIndex >= after.elements.size()) { - elements.add(new Removed(original.elements.get(originalIndex))); - originalIndex++; - } else if (originalIndex >= original.elements.size() && afterIndex < after.elements.size()) { - elements.add(new Added(after.elements.get(afterIndex))); - afterIndex++; - } else { - CsmElement nextOriginal = original.elements.get(originalIndex); - CsmElement nextAfter = after.elements.get(afterIndex); - - if ((nextOriginal instanceof CsmMix) && (nextAfter instanceof CsmMix)) { - if (((CsmMix) nextAfter).getElements().equals(((CsmMix) nextOriginal).getElements())) { - // No reason to deal with a reshuffled, we are just going to keep everything as it is - ((CsmMix) nextAfter).getElements().forEach(el -> elements.add(new Kept(el))); - } else { - elements.add(new Reshuffled((CsmMix)nextOriginal, (CsmMix)nextAfter)); - } - originalIndex++; - afterIndex++; - } else if (matching(nextOriginal, nextAfter)) { - elements.add(new Kept(nextOriginal)); - originalIndex++; - afterIndex++; - } else if (replacement(nextOriginal, nextAfter)) { - elements.add(new Removed(nextOriginal)); - elements.add(new Added(nextAfter)); - originalIndex++; - afterIndex++; - } else { - // We can try to remove the element or add it and look which one leads to the lower difference - Difference adding = calculate(original.from(originalIndex), after.from(afterIndex + 1)); - Difference removing = null; - if (adding.cost() > 0) { - removing = calculate(original.from(originalIndex + 1), after.from(afterIndex)); - } - - if (removing == null || removing.cost() > adding.cost()) { - elements.add(new Added(nextAfter)); - afterIndex++; - } else { - elements.add(new Removed(nextOriginal)); - originalIndex++; - } - } - } - } while (originalIndex < original.elements.size() || afterIndex < after.elements.size()); - - return new Difference(elements); - } - private List processIndentation(List indentation, List prevElements) { List res = new LinkedList<>(); res.addAll(indentation); @@ -577,13 +112,13 @@ void apply(NodeText nodeText, Node node) { List originalElements = nodeText.getElements(); int originalIndex = 0; - List diffElements = getElements(); + List diffElements = getElements(); int diffIndex = 0; do { if (diffIndex < diffElements.size() && originalIndex >= originalElements.size()) { - DifferenceElement diffElement = diffElements.get(diffIndex); - if (diffElement instanceof Kept) { - Kept kept = (Kept) diffElement; + DifferenceElementCalculator.DifferenceElement diffElement = diffElements.get(diffIndex); + if (diffElement instanceof DifferenceElementCalculator.Kept) { + DifferenceElementCalculator.Kept kept = (DifferenceElementCalculator.Kept) diffElement; if (kept.isWhiteSpaceOrComment()) { diffIndex++; @@ -591,8 +126,8 @@ void apply(NodeText nodeText, Node node) { throw new IllegalStateException("Cannot keep element because we reached the end of nodetext: " + nodeText + ". Difference: " + this); } - } else if (diffElement instanceof Added) { - Added addedElement = (Added) diffElement; + } else if (diffElement instanceof DifferenceElementCalculator.Added) { + DifferenceElementCalculator.Added addedElement = (DifferenceElementCalculator.Added) diffElement; nodeText.addElement(originalIndex, addedElement.toTextElement()); originalIndex++; @@ -610,10 +145,10 @@ void apply(NodeText nodeText, Node node) { + this + " " + originalElement); } } else { - DifferenceElement diffElement = diffElements.get(diffIndex); + DifferenceElementCalculator.DifferenceElement diffElement = diffElements.get(diffIndex); - if (diffElement instanceof Added) { - Added addedElement = (Added) diffElement; + if (diffElement instanceof DifferenceElementCalculator.Added) { + DifferenceElementCalculator.Added addedElement = (DifferenceElementCalculator.Added) diffElement; if (addedElement.isIndent()) { for (int i=0;i= this.getElements().size() || !(this.getElements().get(diffIndex + 1) instanceof Added)) { + if (diffIndex + 1 >= this.getElements().size() || !(this.getElements().get(diffIndex + 1) instanceof DifferenceElementCalculator.Added)) { originalIndex = considerEnforcingIndentation(nodeText, originalIndex); } // If in front we have one space and before also we had space let's drop one space @@ -750,7 +285,7 @@ void apply(NodeText nodeText, Node node) { if (originalElements.get(originalIndex).isWhiteSpace() && originalElements.get(originalIndex - 1).isWhiteSpace()) { // However we do not want to do that when we are about to adding or removing elements - if ((diffIndex + 1) == diffElements.size() || (diffElements.get(diffIndex + 1) instanceof Kept)) { + if ((diffIndex + 1) == diffElements.size() || (diffElements.get(diffIndex + 1) instanceof DifferenceElementCalculator.Kept)) { originalElements.remove(originalIndex--); } } @@ -778,9 +313,9 @@ void apply(NodeText nodeText, Node node) { } else { throw new UnsupportedOperationException("removed " + removed.element + " vs " + originalElement); } - } else if (diffElement instanceof Reshuffled) { + } else if (diffElement instanceof DifferenceElementCalculator.Reshuffled) { // First, let's see how many tokens we need to attribute to the previous version of the of the CsmMix - Reshuffled reshuffled = (Reshuffled)diffElement; + DifferenceElementCalculator.Reshuffled reshuffled = (DifferenceElementCalculator.Reshuffled)diffElement; CsmMix elementsFromPreviousOrder = reshuffled.previousOrder; CsmMix elementsFromNextOrder = reshuffled.element; @@ -844,16 +379,16 @@ void apply(NodeText nodeText, Node node) { int indexOfOriginalCSMElement = nodeTextIndexToPreviousCSMIndex.get(ntIndex); if (elementsToAddBeforeGivenOriginalCSMElement.containsKey(indexOfOriginalCSMElement)) { for (CsmElement elementToAdd : elementsToAddBeforeGivenOriginalCSMElement.get(indexOfOriginalCSMElement)) { - diffElements.add(diffElIterator++, new Added(elementToAdd)); + diffElements.add(diffElIterator++, new DifferenceElementCalculator.Added(elementToAdd)); } } CsmElement originalCSMElement = elementsFromPreviousOrder.getElements().get(indexOfOriginalCSMElement); boolean toBeKept = correspondanceBetweenNextOrderAndPreviousOrder.containsValue(indexOfOriginalCSMElement); if (toBeKept) { - diffElements.add(diffElIterator++, new Kept(originalCSMElement)); + diffElements.add(diffElIterator++, new DifferenceElementCalculator.Kept(originalCSMElement)); } else { - diffElements.add(diffElIterator++, new Removed(originalCSMElement)); + diffElements.add(diffElIterator++, new DifferenceElementCalculator.Removed(originalCSMElement)); } } // else we have a simple node text element, without associated csm element, just keep ignore it @@ -863,7 +398,7 @@ void apply(NodeText nodeText, Node node) { // Finally we look for the remaining new elements that were not yet added and // add all of them for (CsmElement elementToAdd : elementsToBeAddedAtTheEnd) { - diffElements.add(diffElIterator++, new Added(elementToAdd)); + diffElements.add(diffElIterator++, new DifferenceElementCalculator.Added(elementToAdd)); } } else { throw new UnsupportedOperationException("" + diffElement + " vs " + originalElement); @@ -885,7 +420,7 @@ private Map getCorrespondanceBetweenNextOrderAndPreviousOrder( for (int pi = 0; pi< previousOrderElements.size() && !found; pi++) { CsmElement pe = previousOrderElements.get(pi); if (!correspondanceBetweenNextOrderAndPreviousOrder.values().contains(pi) - && matching(ne, pe)) { + && DifferenceElementCalculator.matching(ne, pe)) { found = true; correspondanceBetweenNextOrderAndPreviousOrder.put(ni, pi); } @@ -895,7 +430,7 @@ && matching(ne, pe)) { return correspondanceBetweenNextOrderAndPreviousOrder; } - private boolean isFollowedByUnindent(List diffElements, int diffIndex) { + private boolean isFollowedByUnindent(List diffElements, int diffIndex) { return (diffIndex + 1) < diffElements.size() && diffElements.get(diffIndex + 1).isAdded() && diffElements.get(diffIndex + 1).getElement() instanceof CsmUnindent; @@ -1009,7 +544,7 @@ private int adjustIndentation(List indentation, NodeText nodeT } private boolean isAReplacement(int diffIndex) { - return (diffIndex > 0) && getElements().get(diffIndex) instanceof Added && getElements().get(diffIndex - 1) instanceof Removed; + return (diffIndex > 0) && getElements().get(diffIndex) instanceof DifferenceElementCalculator.Added && getElements().get(diffIndex - 1) instanceof DifferenceElementCalculator.Removed; } private boolean isPrimitiveType(TextElement textElement) { @@ -1028,8 +563,8 @@ private boolean isPrimitiveType(TextElement textElement) { } } - private long cost() { - return elements.stream().filter(e -> !(e instanceof Kept)).count(); + long cost() { + return elements.stream().filter(e -> !(e instanceof DifferenceElementCalculator.Kept)).count(); } @Override @@ -1037,7 +572,7 @@ public String toString() { return "Difference{" + elements + '}'; } - List getElements() { + List getElements() { return elements; } diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/DifferenceElementCalculator.java b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/DifferenceElementCalculator.java new file mode 100644 index 0000000000..045843b3a8 --- /dev/null +++ b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/DifferenceElementCalculator.java @@ -0,0 +1,474 @@ +package com.github.javaparser.printer.lexicalpreservation; + +import com.github.javaparser.TokenTypes; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.type.PrimitiveType; +import com.github.javaparser.printer.concretesyntaxmodel.*; + +import java.util.*; + +public class DifferenceElementCalculator { + static boolean matching(CsmElement a, CsmElement b) { + if (a instanceof LexicalDifferenceCalculator.CsmChild) { + if (b instanceof LexicalDifferenceCalculator.CsmChild) { + LexicalDifferenceCalculator.CsmChild childA = (LexicalDifferenceCalculator.CsmChild) a; + LexicalDifferenceCalculator.CsmChild childB = (LexicalDifferenceCalculator.CsmChild) b; + return childA.getChild().equals(childB.getChild()); + } else if (b instanceof CsmToken) { + return false; + } else if (b instanceof CsmIndent) { + return false; + } else if (b instanceof CsmUnindent) { + return false; + } else { + throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); + } + } else if (a instanceof CsmToken) { + if (b instanceof CsmToken) { + CsmToken childA = (CsmToken)a; + CsmToken childB = (CsmToken)b; + return childA.getTokenType() == childB.getTokenType(); + } else if (b instanceof LexicalDifferenceCalculator.CsmChild) { + return false; + } else if (b instanceof CsmIndent) { + return false; + } else if (b instanceof CsmUnindent) { + return false; + } else { + throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); + } + } else if (a instanceof CsmIndent) { + return b instanceof CsmIndent; + } else if (a instanceof CsmUnindent) { + return b instanceof CsmUnindent; + } + throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); + } + + private static boolean replacement(CsmElement a, CsmElement b) { + if (a instanceof CsmIndent || b instanceof CsmIndent || a instanceof CsmUnindent || b instanceof CsmUnindent) { + return false; + } + if (a instanceof LexicalDifferenceCalculator.CsmChild) { + if (b instanceof LexicalDifferenceCalculator.CsmChild) { + LexicalDifferenceCalculator.CsmChild childA = (LexicalDifferenceCalculator.CsmChild) a; + LexicalDifferenceCalculator.CsmChild childB = (LexicalDifferenceCalculator.CsmChild) b; + return childA.getChild().getClass().equals(childB.getChild().getClass()); + } else if (b instanceof CsmToken) { + return false; + } else { + throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); + } + } else if (a instanceof CsmToken) { + if (b instanceof CsmToken) { + CsmToken childA = (CsmToken)a; + CsmToken childB = (CsmToken)b; + return childA.getTokenType() == childB.getTokenType(); + } else if (b instanceof LexicalDifferenceCalculator.CsmChild) { + return false; + } + } + throw new UnsupportedOperationException(a.getClass().getSimpleName()+ " "+b.getClass().getSimpleName()); + } + + /** + * Find the positions of all the given children. + */ + private static Map findChildrenPositions(LexicalDifferenceCalculator.CalculatedSyntaxModel calculatedSyntaxModel) { + Map positions = new HashMap<>(); + for (int i=0;i childrenInOriginal = findChildrenPositions(original); + Map childrenInAfter = findChildrenPositions(after); + + List commonChildren = new LinkedList<>(childrenInOriginal.keySet()); + commonChildren.retainAll(childrenInAfter.keySet()); + commonChildren.sort(Comparator.comparingInt(childrenInOriginal::get)); + + List elements = new LinkedList<>(); + + int originalIndex = 0; + int afterIndex = 0; + int commonChildrenIndex = 0; + while (commonChildrenIndex < commonChildren.size()) { + Node child = commonChildren.get(commonChildrenIndex++); + int posOfNextChildInOriginal = childrenInOriginal.get(child); + int posOfNextChildInAfter = childrenInAfter.get(child); + if (originalIndex < posOfNextChildInOriginal || afterIndex < posOfNextChildInAfter) { + elements.addAll(calculateImpl(original.sub(originalIndex, posOfNextChildInOriginal), after.sub(afterIndex, posOfNextChildInAfter)).getElements()); + } + elements.add(new Kept(new LexicalDifferenceCalculator.CsmChild(child))); + originalIndex = posOfNextChildInOriginal + 1; + afterIndex = posOfNextChildInAfter + 1; + } + + if (originalIndex < original.elements.size() || afterIndex < after.elements.size()) { + elements.addAll(calculateImpl(original.sub(originalIndex, original.elements.size()), after.sub(afterIndex, after.elements.size())).getElements()); + } + return new Difference(elements); + } + + private static Difference calculateImpl(LexicalDifferenceCalculator.CalculatedSyntaxModel original, LexicalDifferenceCalculator.CalculatedSyntaxModel after) { + List elements = new LinkedList<>(); + + int originalIndex = 0; + int afterIndex = 0; + + // We move through the two CalculatedSyntaxModel, moving both forward when we have a match + // and moving just one side forward when we have an element kept or removed + + do { + if (originalIndex < original.elements.size() && afterIndex >= after.elements.size()) { + elements.add(new Removed(original.elements.get(originalIndex))); + originalIndex++; + } else if (originalIndex >= original.elements.size() && afterIndex < after.elements.size()) { + elements.add(new Added(after.elements.get(afterIndex))); + afterIndex++; + } else { + CsmElement nextOriginal = original.elements.get(originalIndex); + CsmElement nextAfter = after.elements.get(afterIndex); + + if ((nextOriginal instanceof CsmMix) && (nextAfter instanceof CsmMix)) { + if (((CsmMix) nextAfter).getElements().equals(((CsmMix) nextOriginal).getElements())) { + // No reason to deal with a reshuffled, we are just going to keep everything as it is + ((CsmMix) nextAfter).getElements().forEach(el -> elements.add(new Kept(el))); + } else { + elements.add(new Reshuffled((CsmMix)nextOriginal, (CsmMix)nextAfter)); + } + originalIndex++; + afterIndex++; + } else if (matching(nextOriginal, nextAfter)) { + elements.add(new Kept(nextOriginal)); + originalIndex++; + afterIndex++; + } else if (replacement(nextOriginal, nextAfter)) { + elements.add(new Removed(nextOriginal)); + elements.add(new Added(nextAfter)); + originalIndex++; + afterIndex++; + } else { + // We can try to remove the element or add it and look which one leads to the lower difference + Difference adding = calculate(original.from(originalIndex), after.from(afterIndex + 1)); + Difference removing = null; + if (adding.cost() > 0) { + removing = calculate(original.from(originalIndex + 1), after.from(afterIndex)); + } + + if (removing == null || removing.cost() > adding.cost()) { + elements.add(new Added(nextAfter)); + afterIndex++; + } else { + elements.add(new Removed(nextOriginal)); + originalIndex++; + } + } + } + } while (originalIndex < original.elements.size() || afterIndex < after.elements.size()); + + return new Difference(elements); + } + + interface DifferenceElement { + static DifferenceElement added(CsmElement element) { + return new Added(element); + } + + static DifferenceElement removed(CsmElement element) { + return new Removed(element); + } + + static DifferenceElement kept(CsmElement element) { + return new Kept(element); + } + + /** + * Return the CsmElement considered in this DifferenceElement. + */ + CsmElement getElement(); + + boolean isAdded(); + } + + static class Added implements DifferenceElement { + final CsmElement element; + + Added(CsmElement element) { + this.element = element; + } + + @Override + public String toString() { + return "Added{" + element + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Added added = (Added) o; + + return element.equals(added.element); + } + + @Override + public int hashCode() { + return element.hashCode(); + } + + @Override + public CsmElement getElement() { + return element; + } + + @Override + public boolean isAdded() { + return true; + } + + boolean isIndent() { return element instanceof CsmIndent; } + + boolean isUnindent() { return element instanceof CsmUnindent; } + + TextElement toTextElement() { + if (element instanceof LexicalDifferenceCalculator.CsmChild) { + return new ChildTextElement(((LexicalDifferenceCalculator.CsmChild) element).getChild()); + } else if (element instanceof CsmToken) { + return new TokenTextElement(((CsmToken) element).getTokenType(), ((CsmToken) element).getContent(null)); + } else { + throw new UnsupportedOperationException(element.getClass().getSimpleName()); + } + } + } + + /** + * Elements in a CsmMix have been reshuffled. It could also mean that + * some new elements have been added or removed to the mix. + */ + static class Reshuffled implements DifferenceElement { + final CsmMix previousOrder; + final CsmMix element; + + Reshuffled(CsmMix previousOrder, CsmMix element) { + this.previousOrder = previousOrder; + this.element = element; + } + + @Override + public String toString() { + return "Reshuffled{" + element + ", previous="+ previousOrder+ '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Reshuffled that = (Reshuffled) o; + + if (!previousOrder.equals(that.previousOrder)) return false; + return element.equals(that.element); + } + + @Override + public int hashCode() { + int result = previousOrder.hashCode(); + result = 31 * result + element.hashCode(); + return result; + } + + @Override + public CsmMix getElement() { + return element; + } + + @Override + public boolean isAdded() { + return false; + } + } + + static class Kept implements DifferenceElement { + final CsmElement element; + + Kept(CsmElement element) { + this.element = element; + } + + @Override + public String toString() { + return "Kept{" + element + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Kept kept = (Kept) o; + + return element.equals(kept.element); + } + + @Override + public int hashCode() { + return element.hashCode(); + } + + @Override + public CsmElement getElement() { + return element; + } + + int getTokenType() { + if (isToken()) { + CsmToken csmToken = (CsmToken) element; + return csmToken.getTokenType(); + } + + throw new IllegalStateException("Kept is not a " + CsmToken.class.getSimpleName()); + } + + @Override + public boolean isAdded() { + return false; + } + + boolean isIndent() { return element instanceof CsmIndent; } + + boolean isUnindent() { return element instanceof CsmUnindent; } + + boolean isToken() { return element instanceof CsmToken; } + + boolean isChild() { return element instanceof LexicalDifferenceCalculator.CsmChild; } + + boolean isPrimitiveType() { + if (isChild()) { + LexicalDifferenceCalculator.CsmChild csmChild = (LexicalDifferenceCalculator.CsmChild) element; + return csmChild.getChild() instanceof PrimitiveType; + } + + return false; + } + + boolean isWhiteSpace() { + if(isToken()) { + CsmToken csmToken = (CsmToken) element; + return csmToken.isWhiteSpace(); + } + + return false; + } + + boolean isWhiteSpaceOrComment() { + if (isToken()) { + CsmToken csmToken = (CsmToken) element; + return TokenTypes.isWhitespaceOrComment(csmToken.getTokenType()); + } + + return false; + } + } + + static class Removed implements DifferenceElement { + final CsmElement element; + + Removed(CsmElement element) { + this.element = element; + } + + @Override + public String toString() { + return "Removed{" + element + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Removed removed = (Removed) o; + + return element.equals(removed.element); + } + + @Override + public int hashCode() { + return element.hashCode(); + } + + @Override + public CsmElement getElement() { + return element; + } + + Node getChild() { + if (isChild()) { + LexicalDifferenceCalculator.CsmChild csmChild = (LexicalDifferenceCalculator.CsmChild) element; + return csmChild.getChild(); + } + + throw new IllegalStateException("Removed is not a " + LexicalDifferenceCalculator.CsmChild.class.getSimpleName()); + } + + int getTokenType() { + if (isToken()) { + CsmToken csmToken = (CsmToken) element; + return csmToken.getTokenType(); + } + + throw new IllegalStateException("Removed is not a " + CsmToken.class.getSimpleName()); + } + + @Override + public boolean isAdded() { + return false; + } + + boolean isToken() { return element instanceof CsmToken; } + + boolean isChild() { return element instanceof LexicalDifferenceCalculator.CsmChild; } + + boolean isPrimitiveType() { + if (isChild()) { + LexicalDifferenceCalculator.CsmChild csmChild = (LexicalDifferenceCalculator.CsmChild) element; + return csmChild.getChild() instanceof PrimitiveType; + } + + return false; + } + + boolean isWhiteSpace() { + if(isToken()) { + CsmToken csmToken = (CsmToken) element; + return csmToken.isWhiteSpace(); + } + + return false; + } + } +} diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculator.java b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculator.java index 9263dfd8aa..3df63d54d4 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculator.java +++ b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalDifferenceCalculator.java @@ -91,7 +91,7 @@ Difference calculateListRemovalDifference(ObservableProperty observableProperty, CsmElement element = ConcreteSyntaxModel.forClass(container.getClass()); CalculatedSyntaxModel original = calculatedSyntaxModelForNode(element, container); CalculatedSyntaxModel after = calculatedSyntaxModelAfterListRemoval(element, observableProperty, nodeList, index); - return Difference.calculate(original, after); + return DifferenceElementCalculator.calculate(original, after); } Difference calculateListAdditionDifference(ObservableProperty observableProperty, NodeList nodeList, int index, Node nodeAdded) { @@ -99,7 +99,7 @@ Difference calculateListAdditionDifference(ObservableProperty observableProperty CsmElement element = ConcreteSyntaxModel.forClass(container.getClass()); CalculatedSyntaxModel original = calculatedSyntaxModelForNode(element, container); CalculatedSyntaxModel after = calculatedSyntaxModelAfterListAddition(element, observableProperty, nodeList, index, nodeAdded); - return Difference.calculate(original, after); + return DifferenceElementCalculator.calculate(original, after); } Difference calculateListReplacementDifference(ObservableProperty observableProperty, NodeList nodeList, int index, Node newValue) { @@ -107,7 +107,7 @@ Difference calculateListReplacementDifference(ObservableProperty observablePrope CsmElement element = ConcreteSyntaxModel.forClass(container.getClass()); CalculatedSyntaxModel original = calculatedSyntaxModelForNode(element, container); CalculatedSyntaxModel after = calculatedSyntaxModelAfterListReplacement(element, observableProperty, nodeList, index, newValue); - return Difference.calculate(original, after); + return DifferenceElementCalculator.calculate(original, after); } public void calculatePropertyChange(NodeText nodeText, Node observedNode, ObservableProperty property, Object oldValue, Object newValue) { @@ -117,7 +117,7 @@ public void calculatePropertyChange(NodeText nodeText, Node observedNode, Observ CsmElement element = ConcreteSyntaxModel.forClass(observedNode.getClass()); CalculatedSyntaxModel original = calculatedSyntaxModelForNode(element, observedNode); CalculatedSyntaxModel after = calculatedSyntaxModelAfterPropertyChange(element, observedNode, property, oldValue, newValue); - Difference difference = Difference.calculate(original, after); + Difference difference = DifferenceElementCalculator.calculate(original, after); difference.apply(nodeText, observedNode); }