From 93397adecaf55e64d21979d89ba213cb008cee60 Mon Sep 17 00:00:00 2001 From: Benjamin Moosherr Date: Sun, 30 Oct 2022 19:00:10 +0100 Subject: [PATCH 01/11] Generalize before and after methods using `Time` --- .../diffdetective/diff/DiffLineNumber.java | 30 +- .../diff/difftree/DiffGraph.java | 7 +- .../diffdetective/diff/difftree/DiffNode.java | 522 +++++------------- .../diffdetective/diff/difftree/DiffTree.java | 18 +- .../diffdetective/diff/difftree/Time.java | 11 + .../diff/difftree/serialize/Format.java | 11 +- .../serialize/edgeformat/EdgeLabelFormat.java | 13 +- .../CollapseNestedNonEditedAnnotations.java | 17 +- .../transform/CutNonEditedSubtrees.java | 7 +- .../NaiveMovedArtifactDetection.java | 7 +- .../diff/difftree/transform/Starfold.java | 2 +- .../editclass/proposed/AddToPC.java | 4 +- .../editclass/proposed/AddWithMapping.java | 4 +- .../editclass/proposed/Generalization.java | 7 +- .../proposed/ProposedEditClasses.java | 11 +- .../editclass/proposed/Reconfiguration.java | 7 +- .../editclass/proposed/Refactoring.java | 7 +- .../editclass/proposed/RemFromPC.java | 4 +- .../editclass/proposed/RemWithMapping.java | 4 +- .../editclass/proposed/Specialization.java | 7 +- .../editclass/proposed/Untouched.java | 7 +- .../mining/RunningExampleFinder.java | 6 +- .../elementary/FeatureContextOfAddToPC.java | 4 +- .../FeatureContextOfAddWithMapping.java | 4 +- .../elementary/FeatureContextOfRemFromPC.java | 4 +- .../FeatureContextOfRemWithMapping.java | 4 +- .../pattern/semantic/AddIfdefElif.java | 6 +- .../pattern/semantic/AddIfdefElse.java | 4 +- .../pattern/semantic/AddIfdefWrapElse.java | 4 +- .../pattern/semantic/AddIfdefWrapThen.java | 4 +- .../pattern/semantic/MoveElse.java | 8 +- src/test/java/MarlinDebug.java | 7 +- src/test/java/PCTest.java | 6 +- src/test/java/TestLineNumbers.java | 7 +- 34 files changed, 300 insertions(+), 475 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/diff/DiffLineNumber.java b/src/main/java/org/variantsync/diffdetective/diff/DiffLineNumber.java index bd103243f..048a845cf 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/DiffLineNumber.java +++ b/src/main/java/org/variantsync/diffdetective/diff/DiffLineNumber.java @@ -1,6 +1,7 @@ package org.variantsync.diffdetective.diff; import org.variantsync.diffdetective.diff.difftree.DiffType; +import org.variantsync.diffdetective.diff.difftree.Time; import java.util.Objects; @@ -77,6 +78,15 @@ public DiffLineNumber as(final DiffType diffType) { ); } + /** + * Returns the line number at the given time. + * @param time the time at which to return the line range + * @return {@code beforeEdit} or {@code afterEdit}, depending on {@code time} + */ + public int atTime(Time time) { + return time.match(beforeEdit, afterEdit); + } + @Override public String toString() { return "(old: " + beforeEdit + ", diff: " + inDiff + ", new:" + afterEdit + ")"; @@ -107,24 +117,14 @@ public static Lines rangeInDiff(final DiffLineNumber from, final DiffLineNumber } /** - * Returns the range between two line numbers before the edit. - * @see DiffLineNumber#inDiff - * @param from The start line number. - * @param to The end line number. - * @return [from.beforeEdit, to.beforeEdit) - */ - public static Lines rangeBeforeEdit(final DiffLineNumber from, final DiffLineNumber to) { - return Lines.FromInclToExcl(from.beforeEdit, to.beforeEdit); - } - - /** - * Returns the range between two line numbers before the edit. + * Returns the range between two line numbers at a given time. * @see DiffLineNumber#inDiff * @param from The start line number. * @param to The end line number. - * @return [from.afterEdit, to.afterEdit) + * @param time The time at which to return the line range. + * @return [from.beforeEdit, to.beforeEdit) or [from.afterEdit, to.afterEdit) */ - public static Lines rangeAfterEdit(final DiffLineNumber from, final DiffLineNumber to) { - return Lines.FromInclToExcl(from.afterEdit, to.afterEdit); + public static Lines rangeAtTime(final DiffLineNumber from, final DiffLineNumber to, Time time) { + return Lines.FromInclToExcl(from.atTime(time), to.atTime(time)); } } diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffGraph.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffGraph.java index 94709153d..40068d658 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffGraph.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffGraph.java @@ -2,6 +2,9 @@ import java.util.Collection; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Generalisation of DiffTrees to arbitrary change graphs with variability information. * The DiffGraph class currently does not model a graph itself but rather @@ -33,8 +36,8 @@ public static DiffTree fromNodes(final Collection nodes, final DiffTre .filter(DiffNode::isRoot) .forEach(n -> n.diffType.matchBeforeAfter( - () -> newRoot.addBeforeChild(n), - () -> newRoot.addAfterChild(n) + () -> newRoot.addChild(n, BEFORE), + () -> newRoot.addChild(n, AFTER) )); return new DiffTree(newRoot, source); } diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java index 4d16761b1..a6c34112d 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java @@ -9,9 +9,10 @@ import org.variantsync.diffdetective.util.fide.FixTrueFalse; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; import static org.variantsync.diffdetective.util.fide.FormulaUtils.negate; /** @@ -45,29 +46,22 @@ public class DiffNode { private List lines; /** - * The parent {@link DiffNode} before the edit. + * The parents {@link DiffNode} before and after the edit. + * This array has to be indexed by {@code Time.ordinal()} * - * Invariant: Iff {@code beforeParent != null} then - * {@code beforeParent.childOrder.contains(this)}. + * Invariant: Iff {@code getParent(time) != null} then + * {@code getParent(time).childOrder.contains(this)}. */ - private DiffNode beforeParent; - - /** - * The parent {@link DiffNode} after the edit. - * - * Invariant: Iff {@code afterParent != null} then - * {@code afterParent.childOrder.contains(this)}. - */ - private DiffNode afterParent; + private DiffNode[] parents = new DiffNode[2]; /** * We use a list for children to maintain order. * * Invariant: Iff {@code childOrder.contains(child)} then - * {@code child.beforeParent == this || child.afterParent == this}. + * {@code child.getParent(BEFORE) == this || child.getParent(AFTER) == this}. * * Note that it's explicitly allowed to have - * {@code child.beforeParent == this && child.afterParent == this}. + * {@code child.getParent(BEFORE) == this && child.getParent(AFTER) == this}. */ private final List childOrder; @@ -169,87 +163,47 @@ public void setLabel(String label) { } /** - * Gets the first if node in the path following the before parent - * @return The first if node in the path following the before parent + * Gets the first {@code if} node in the path from the root to this node at the time + * {@code time}. + * @return The first {@code if} node in the path to the root at the time {@code time} */ - public DiffNode getBeforeIfNode() { + public DiffNode getIfNode(Time time) { if (isIf()) { return this; } if (isRoot()) { return null; } - return beforeParent.getBeforeIfNode(); + return getParent(time).getIfNode(time); } /** - * Gets the first if node in the path following the after parent - * @return The first if node in the path following the after parent + * Gets the number of annotations in the path from the root to this node at the time + * {@code time}. + * @return the number of annotations above this node at the time {@code time} */ - public DiffNode getAfterIfNode() { - if (isIf()) { - return this; - } - if (isRoot()) { - return null; - } - return afterParent.getAfterIfNode(); - } - - /** - * Gets the depth of the diff tree following the before parent - * @return the depth of the diff tree following the before parent - */ - public int getBeforeAnnotationDepth(){ + public int getAnnotationDepth(Time time) { if (isRoot()) { return 0; } if (isIf()) { - return beforeParent.getBeforeAnnotationDepth() + 1; + return getParent(time).getAnnotationDepth(time) + 1; } - return beforeParent.getBeforeAnnotationDepth(); + return getParent(time).getAnnotationDepth(time); } /** - * Gets the depth of the diff tree following the after parent - * @return the depth of the diff tree following the after parent + * Gets the length of the path from the root to this node at the time {@code time}. + * @return the depth of the this node in the diff tree at the time {@code time} */ - public int getAfterAnnotationDepth(){ + public int getDepth(Time time) { if (isRoot()) { return 0; } - if (isIf()) { - return afterParent.getAfterAnnotationDepth() + 1; - } - - return afterParent.getAfterAnnotationDepth(); - } - - /** - * Gets the depth of the diff tree following the before parent - * @return the depth of the diff tree following the before parent - */ - public int getBeforeDepth(){ - if (isRoot()) { - return 0; - } - - return beforeParent.getBeforeDepth() + 1; - } - - /** - * Gets the depth of the diff tree following the after parent - * @return the depth of the diff tree following the after parent - */ - public int getAfterDepth(){ - if (isRoot()) { - return 0; - } - - return afterParent.getAfterDepth() + 1; + return getParent(time).getDepth(time) + 1; } /** @@ -257,13 +211,13 @@ public int getAfterDepth(){ * are the very same. */ public boolean beforePathEqualsAfterPath() { - if (beforeParent == afterParent) { - if (beforeParent == null) { + if (getParent(BEFORE) == getParent(AFTER)) { + if (getParent(BEFORE) == null) { // root return true; } - return beforeParent.beforePathEqualsAfterPath(); + return getParent(BEFORE).beforePathEqualsAfterPath(); } return false; @@ -277,59 +231,36 @@ public int getTotalNumberOfChildren() { } /** - * Gets the amount of nodes with diff type REM in the path following the before parent - * @return the amount of nodes with diff type REM in the path following the before parent + * Gets the amount of nodes on the path from the root to this node which only exist at the time + * {@code time}. */ - public int getRemAmount() { + public int getChangeAmount(Time time) { if (isRoot()) { return 0; } - if (isIf() && diffType.equals(DiffType.REM)) { - return beforeParent.getRemAmount() + 1; + var changeType = DiffType.thatExistsOnlyAt(time); + + if (isIf() && diffType.equals(changeType)) { + return getParent(time).getChangeAmount(time) + 1; } - if ((isElif() || isElse()) && diffType.equals(DiffType.REM)) { + if ((isElif() || isElse()) && diffType.equals(changeType)) { // if this is a removed elif or else we do not want to count the other branches of // this annotation // we thus go up the tree until we get the next if and continue with the parent of it - return beforeParent.getBeforeIfNode().beforeParent.getRemAmount() + 1; + return getParent(time).getIfNode(time).getParent(time).getChangeAmount(time) + 1; } - return beforeParent.getRemAmount(); + return getParent(time).getChangeAmount(time); } /** - * Gets the amount of nodes with diff type ADD in the path following the after parent - * @return the amount of nodes with diff type ADD in the path following the after parent + * Sets the parent at {@code time} checking that this node doesn't currently have a parent. */ - public int getAddAmount() { - if (isRoot()) { - return 0; - } - - if (isIf() && diffType.equals(DiffType.ADD)) { - return afterParent.getAddAmount() + 1; - } - - if ((isElif() || isElse()) && diffType.equals(DiffType.ADD)) { - // if this is an added elif or else we do not want to count the other branches of - // this annotation - // we thus go up the tree until we get the next if and continue with the parent of it - return afterParent.getAfterIfNode().afterParent.getAddAmount() + 1; - } - - return afterParent.getAddAmount(); - } - - private void setBeforeParent(final DiffNode newBeforeParent) { - Assert.assertTrue(beforeParent == null); - this.beforeParent = newBeforeParent; - } - - private void setAfterParent(final DiffNode newAfterParent) { - Assert.assertTrue(afterParent == null); - this.afterParent = newAfterParent; + private void setParent(final DiffNode newParent, Time time) { + Assert.assertTrue(getParent(time) == null); + parents[time.ordinal()] = newParent; } /** @@ -342,10 +273,10 @@ private void setAfterParent(final DiffNode newAfterParent) { public boolean addBelow(final DiffNode newBeforeParent, final DiffNode newAfterParent) { boolean success = false; if (newBeforeParent != null) { - success |= newBeforeParent.addBeforeChild(this); + success |= newBeforeParent.addChild(this, BEFORE); } if (newAfterParent != null) { - success |= newAfterParent.addAfterChild(this); + success |= newAfterParent.addChild(this, AFTER); } return success; } @@ -355,22 +286,20 @@ public boolean addBelow(final DiffNode newBeforeParent, final DiffNode newAfterP * Inverse of addBelow. */ public void drop() { - if (beforeParent != null) { - beforeParent.removeBeforeChild(this); + if (getParent(BEFORE) != null) { + getParent(BEFORE).removeChild(this, BEFORE); } - if (afterParent != null) { - afterParent.removeAfterChild(this); + if (getParent(AFTER) != null) { + getParent(AFTER).removeChild(this, AFTER); } } - private void dropBeforeChild(final DiffNode child) { - Assert.assertTrue(child.beforeParent == this); - child.beforeParent = null; - } - - private void dropAfterChild(final DiffNode child) { - Assert.assertTrue(child.afterParent == this); - child.afterParent = null; + /** + * Remove this as the parent of {@code child}. + */ + private void dropChild(final DiffNode child, Time time) { + Assert.assertTrue(child.getParent(time) == this); + child.parents[time.ordinal()] = null; } /** @@ -382,132 +311,59 @@ public int indexOfChild(final DiffNode child) { } /** - * Adds the given node for the given time at the given index as the child. - * @param child The new child to add. This node should not be a child of another node for the given time. - * @param index The index at which the node should be inserted into the children list. - * @param time The time at which this node should be the parent of this node. - * For example, if the time is BEFORE, then this node will become the before parent of the given node. - * @return True iff the insertion was successful. False iff the child could not be added. - * @see DiffNode#insertBeforeChild - * @see DiffNode#insertAfterChild + * Insert {@code child} as child at the time {@code time} at the position {@code index}. */ - public boolean insertChildAt(final DiffNode child, int index, Time time) { - return switch (time) { - case BEFORE -> insertBeforeChild(child, index); - case AFTER -> insertAfterChild(child, index); - }; - } - - /** - * The same as {@link DiffNode#insertChildAt} but the time fixed to BEFORE. - */ - public boolean insertBeforeChild(final DiffNode child, int index) { - if (!child.isAdd()) { + public boolean insertChild(final DiffNode child, int index, Time time) { + if (child.getDiffType().existsAtTime(time)) { if (!isChild(child)) { childOrder.add(index, child); } - child.setBeforeParent(this); + child.setParent(this, time); return true; } return false; } /** - * The same as {@link DiffNode#insertChildAt} but the time fixed to AFTER. - */ - public boolean insertAfterChild(final DiffNode child, int index) { - if (!child.isRem()) { - if (!isChild(child)) { - childOrder.add(index, child); - } - child.setAfterParent(this); - return true; - } - return false; - } - - /** - * The same as {@link DiffNode#insertBeforeChild} but puts the node at the end of the children - * list instead of inserting it at a specific index. - */ - public boolean addBeforeChild(final DiffNode child) { - if (!child.isAdd()) { - if (child.beforeParent != null) { - throw new IllegalArgumentException("Given child " + child + " already has a before parent (" + child.beforeParent + ")!"); - } - - if (!isChild(child)) { - childOrder.add(child); - } - child.setBeforeParent(this); - return true; - } - return false; - } - - /** - * The same as {@link DiffNode#insertAfterChild} but puts the node at the end of the children + * The same as {@link DiffNode#insertChild} but puts the node at the end of the children * list instead of inserting it at a specific index. */ - public boolean addAfterChild(final DiffNode child) { - if (!child.isRem()) { - if (child.afterParent != null) { - throw new IllegalArgumentException("Given child " + child + " already has an after parent (" + child.afterParent + ")!"); + public boolean addChild(final DiffNode child, Time time) { + if (child.getDiffType().existsAtTime(time)) { + if (child.getParent(time) != null) { + throw new IllegalArgumentException("Given child " + child + " already has a before parent (" + child.getParent(time) + ")!"); } if (!isChild(child)) { childOrder.add(child); } - child.setAfterParent(this); + child.setParent(this, time); return true; } return false; } /** - * Adds all given nodes as before children using {@link DiffNode#addBeforeChild}. - * @param beforeChildren Nodes to add as children before the edit. + * Adds all given nodes at the time {@code time} as children using {@link DiffNode#addChild}. + * @param children Nodes to add as children. + * @param time whether to add {@code children} before or after the edit */ - public void addBeforeChildren(final Collection beforeChildren) { - for (final DiffNode beforeChild : beforeChildren) { - addBeforeChild(beforeChild); + public void addChildren(final Collection children, Time time) { + for (final DiffNode child : children) { + addChild(child, time); } } /** - * Adds all given nodes as after children using {@link DiffNode#addAfterChild}. - * @param afterChildren Nodes to add as children after the edit. + * Removes the given node from this node's children before or after the edit. + * The node might still remain a child after or before the edit. + * @param child the child to remove + * @param time whether {@code child} should be removed before or after the edit + * @return True iff the child was removed, false iff it's not a child at {@code time}. */ - public void addAfterChildren(final Collection afterChildren) { - for (final DiffNode afterChild : afterChildren) { - addAfterChild(afterChild); - } - } - - /** - * Removes the given node from this node's children before the edit. - * The node might still remain a child after the edit. - * @param child The child to remove before the edit. - * @return True iff the child was removed, false iff it was no before child. - */ - public boolean removeBeforeChild(final DiffNode child) { - if (isBeforeChild(child)) { - dropBeforeChild(child); - removeFromCache(child); - return true; - } - return false; - } - - /** - * Removes the given node from this node's children after the edit. - * The node might still remain a child before the edit. - * @param child The child to remove after the edit. - * @return True iff the child was removed, false iff it was no after child. - */ - public boolean removeAfterChild(final DiffNode child) { - if (isAfterChild(child)) { - dropAfterChild(child); + public boolean removeChild(final DiffNode child, Time time) { + if (isChild(child, time)) { + dropChild(child, time); removeFromCache(child); return true; } @@ -521,53 +377,30 @@ public boolean removeAfterChild(final DiffNode child) { */ public void removeChildren(final Collection childrenToRemove) { for (final DiffNode childToRemove : childrenToRemove) { - removeBeforeChild(childToRemove); - removeAfterChild(childToRemove); + removeChild(childToRemove, BEFORE); + removeChild(childToRemove, AFTER); } } /** - * Removes all children before the edit. + * Removes all children before or after the edit. * Afterwards, this node will have no before children. - * @return All removed before children. + * @param time whether to remove all children before or after the edit + * @return All removed children. */ - public List removeBeforeChildren() { + public List removeChildren(Time time) { final List orphans = new ArrayList<>(); // Note that the following method call can't be written using a foreach loop reusing // {@code removeBeforeChild} because lists can't be modified during traversal. childOrder.removeIf(child -> { - if (!isBeforeChild(child)) { + if (!isChild(child, time)) { return false; } orphans.add(child); - dropBeforeChild(child); - return !isAfterChild(child); - }); - - return orphans; - } - - - /** - * Removes all children after the edit. - * Afterwards, this node will have no after children. - * @return All removed after children. - */ - public List removeAfterChildren() { - final List orphans = new ArrayList<>(); - - // Note that the following method call can't be written using a foreach loop reusing - // {@code removeAfterChild} because lists can't be modified during traversal. - childOrder.removeIf(child -> { - if (!isAfterChild(child)) { - return false; - } - - orphans.add(child); - dropAfterChild(child); - return !isBeforeChild(child); + dropChild(child, time); + return !isChild(child, time.other()); }); return orphans; @@ -593,22 +426,15 @@ private void removeFromCache(final DiffNode child) { * @param other The node whose children should be stolen. */ public void stealChildrenOf(final DiffNode other) { - addBeforeChildren(other.removeBeforeChildren()); - addAfterChildren(other.removeAfterChildren()); - } - - /** - * Returns the parent of this node before the edit. - */ - public DiffNode getBeforeParent() { - return beforeParent; + addChildren(other.removeChildren(BEFORE), BEFORE); + addChildren(other.removeChildren(AFTER), AFTER); } /** - * Returns the parent of this node after the edit. + * Returns the parent of this node before or after the edit. */ - public DiffNode getAfterParent() { - return afterParent; + public DiffNode getParent(Time time) { + return parents[time.ordinal()]; } /** @@ -643,19 +469,11 @@ public Lines getLinesInDiff() { } /** - * Returns the range of line numbers of this node's corresponding source code before the edit. - * @see DiffLineNumber#rangeBeforeEdit - */ - public Lines getLinesBeforeEdit() { - return DiffLineNumber.rangeBeforeEdit(from, to); - } - - /** - * Returns the range of line numbers of this node's corresponding source code after the edit. - * @see DiffLineNumber#rangeAfterEdit + * Returns the range of line numbers of this node's corresponding source code before or after + * the edit. */ - public Lines getLinesAfterEdit() { - return DiffLineNumber.rangeAfterEdit(from, to); + public Lines getLinesAtTime(Time time) { + return DiffLineNumber.rangeAtTime(from, to, time); } /** @@ -689,14 +507,12 @@ public List getAllChildren() { * The feature mapping of {@link NodeType#ELSE} and {@link NodeType#ELIF} nodes is determined by all formulas in the respective if-elif-else chain. * The feature mapping of an {@link NodeType#ARTIFACT artifact} node is the feature mapping of its parent. * See Equation (1) in our paper (+ its extension to time for variation tree diffs described in Section 3.1). - * @param parentOf Function that returns the parent of a node. - * This function decides whether the before or after parent should be visited. - * It thus decides whether to compute the feature mapping before or after the edit. + * @param time Whether to return the feature mapping clauses before or after the edit. * @return The feature mapping of this node for the given parent edges. * The returned list represents a conjunction (i.e., all clauses should be combined with boolean AND). */ - private List getFeatureMappingClauses(final Function parentOf) { - final DiffNode parent = parentOf.apply(this); + private List getFeatureMappingClauses(Time time) { + final DiffNode parent = getParent(time); if (isElse() || isElif()) { List and = new ArrayList<>(); @@ -714,95 +530,57 @@ private List getFeatureMappingClauses(final Function p throw new RuntimeException("Expected If or Elif above Else or Elif but got " + ancestor.nodeType + " from " + ancestor); // Assert.assertTrue(ancestor.isArtifact()); } - ancestor = parentOf.apply(ancestor); + ancestor = ancestor.getParent(time); } and.add(negate(ancestor.getDirectFeatureMapping())); return and; } else if (isArtifact()) { - return parent.getFeatureMappingClauses(parentOf); + return parent.getFeatureMappingClauses(time); } return List.of(getDirectFeatureMapping()); } /** - * Same as {@link DiffNode#getFeatureMappingClauses} but conjuncts the returned clauses to a single formula. + * Depending on the given time, returns either the feature mapping before or after the edit. */ - private Node getFeatureMapping(Function parentOf) { - final List fmClauses = getFeatureMappingClauses(parentOf); + public Node getFeatureMapping(Time time) { + final List fmClauses = getFeatureMappingClauses(time); if (fmClauses.size() == 1) { return fmClauses.get(0); } return new And(fmClauses); } - /** - * Returns the full feature mapping formula of this node before the edit. - * The feature mapping of an {@link NodeType#IF} node is its {@link DiffNode#getDirectFeatureMapping direct feature mapping}. - * The feature mapping of {@link NodeType#ELSE} and {@link NodeType#ELIF} nodes is determined by all formulas in the respective if-elif-else chain. - * The feature mapping of an {@link NodeType#ARTIFACT artifact} node is the feature mapping of its parent. - * See Equation (1) in our paper (+ its extension to time for variation tree diffs described in Section 3.1). - * @return The feature mapping of this node for the given parent edges. - */ - public Node getBeforeFeatureMapping() { - return getFeatureMapping(DiffNode::getBeforeParent); - } - - /** - * Returns the full feature mapping formula of this node after the edit. - * The feature mapping of an {@link NodeType#IF} node is its {@link DiffNode#getDirectFeatureMapping direct feature mapping}. - * The feature mapping of {@link NodeType#ELSE} and {@link NodeType#ELIF} nodes is determined by all formulas in the respective if-elif-else chain. - * The feature mapping of an {@link NodeType#ARTIFACT artifact} node is the feature mapping of its parent. - * See Equation (1) in our paper (+ its extension to time for variation tree diffs described in Section 3.1). - * @return The feature mapping of this node for the given parent edges. - */ - public Node getAfterFeatureMapping() { - return getFeatureMapping(DiffNode::getAfterParent); - } - - /** - * Depending on the given time, returns either the - * {@link DiffNode#getBeforeFeatureMapping() before feature mapping} or - * {@link DiffNode#getAfterFeatureMapping() after feature mapping}. - */ - public Node getFeatureMapping(Time time) { - return time.match( - this::getBeforeFeatureMapping, - this::getAfterFeatureMapping - ); - } - /** * Returns the presence condition of this node for the respective time. * See Equation (2) in our paper (+ its extension to time for variation tree diffs described in Section 3.1). - * @param parentOf Function that returns the parent of a node. - * This function decides whether the before or after parent should be visited. - * It thus decides whether to compute the feature mapping before or after the edit. + * @param time Whether to return the presence condition clauses before or after the edit. * @return The presence condition of this node for the given parent edges. * The returned list represents a conjunction (i.e., all clauses should be combined with boolean AND). */ - private List getPresenceCondition(Function parentOf) { - final DiffNode parent = parentOf.apply(this); + private List getPresenceConditionClauses(Time time) { + final DiffNode parent = getParent(time); if (isElse() || isElif()) { - final List clauses = new ArrayList<>(getFeatureMappingClauses(parentOf)); + final List clauses = new ArrayList<>(getFeatureMappingClauses(time)); // Find corresponding if DiffNode correspondingIf = parent; while (!correspondingIf.isIf()) { - correspondingIf = parentOf.apply(correspondingIf); + correspondingIf = correspondingIf.getParent(time); } // If this elif-else-chain was again nested in another annotation, add its pc. - final DiffNode outerNesting = parentOf.apply(correspondingIf); + final DiffNode outerNesting = correspondingIf.getParent(time); if (outerNesting != null) { - clauses.addAll(outerNesting.getPresenceCondition(parentOf)); + clauses.addAll(outerNesting.getPresenceConditionClauses(time)); } return clauses; } else if (isArtifact()) { - return parent.getPresenceCondition(parentOf); + return parent.getPresenceConditionClauses(time); } // this is mapping or root @@ -810,76 +588,38 @@ private List getPresenceCondition(Function parentOf) { if (parent == null) { clauses = new ArrayList<>(1); } else { - clauses = parent.getPresenceCondition(parentOf); + clauses = parent.getPresenceConditionClauses(time); } clauses.add(featureMapping); return clauses; } /** - * Returns the presence condition of this node before the edit. - * See Equation (2) in our paper (+ its extension to time for variation tree diffs described in Section 3.1). - * @return The presence condition of this node for the given parent edges. - */ - public Node getBeforePresenceCondition() { - if (diffType.existsBefore()) { - return new And(getPresenceCondition(DiffNode::getBeforeParent)); - } else { - throw new WrongTimeException("Cannot determine before PC of added node " + this); - } - } - - /** - * Returns the presence condition of this node after the edit. + * Returns the presence condition of this node before or after the edit. * See Equation (2) in our paper (+ its extension to time for variation tree diffs described in Section 3.1). + * @param time Whether to return the presence condition before or after the edit. * @return The presence condition of this node for the given parent edges. */ - public Node getAfterPresenceCondition() { - if (diffType.existsAfter()) { - return new And(getPresenceCondition(DiffNode::getAfterParent)); + public Node getPresenceCondition(Time time) { + if (diffType.existsAtTime(time)) { + return new And(getPresenceConditionClauses(time)); } else { throw new WrongTimeException("Cannot determine after PC of removed node " + this); } } - /** - * Depending on the given time, returns either the - * {@link DiffNode#getBeforePresenceCondition() before presence condition} or - * {@link DiffNode#getAfterPresenceCondition() after presence condition}. - */ - public Node getPresenceCondition(Time time) { - return time.match( - this::getBeforePresenceCondition, - this::getAfterPresenceCondition - ); - } - - /** - * Returns true iff this node is the before parent of the given node. - */ - public boolean isBeforeChild(DiffNode child) { - return child.beforeParent == this; - } - - /** - * Returns true iff this node is the after parent of the given node. - */ - public boolean isAfterChild(DiffNode child) { - return child.afterParent == this; - } - /** * Returns true iff this node is the before or after parent of the given node. */ public boolean isChild(DiffNode child) { - return isBeforeChild(child) || isAfterChild(child); + return isChild(child, BEFORE) || isChild(child, AFTER); } /** * Returns true iff this node is the parent of the given node at the given time. */ public boolean isChild(DiffNode child, Time time) { - return time.match(isBeforeChild(child), isAfterChild(child)); + return child.getParent(time) == this; } /** @@ -956,7 +696,7 @@ public boolean isElse() { * Returns true if this node is a root node (has no parents). */ public boolean isRoot() { - return getBeforeParent() == null && getAfterParent() == null; + return getParent(BEFORE) == null && getParent(AFTER) == null; } /** @@ -1026,33 +766,33 @@ public void assertConsistency() { // check consistency of children lists and edges for (final DiffNode c : childOrder) { Assert.assertTrue(isChild(c), () -> "Child " + c + " of " + this + " is neither a before nor an after child!"); - if (c.getBeforeParent() != null) { - Assert.assertTrue(c.getBeforeParent().isBeforeChild(c), () -> "The beforeParent of " + c + " doesn't contain that node as child"); + if (c.getParent(BEFORE) != null) { + Assert.assertTrue(c.getParent(BEFORE).isChild(c, BEFORE), () -> "The parent before the edit of " + c + " doesn't contain that node as child"); } - if (c.getAfterParent() != null) { - Assert.assertTrue(c.getAfterParent().isAfterChild(c), () -> "The afterParent of " + c + " doesn't contain that node as child"); + if (c.getParent(AFTER) != null) { + Assert.assertTrue(c.getParent(AFTER).isChild(c, AFTER), () -> "The parent after the edit of " + c + " doesn't contain that node as child"); } } // a node with exactly one parent was edited - if (beforeParent == null && afterParent != null) { + if (getParent(BEFORE) == null && getParent(AFTER) != null) { Assert.assertTrue(isAdd()); } - if (beforeParent != null && afterParent == null) { + if (getParent(BEFORE) != null && getParent(AFTER) == null) { Assert.assertTrue(isRem()); } // a node with exactly two parents was not edited - if (beforeParent != null && afterParent != null) { + if (getParent(BEFORE) != null && getParent(AFTER) != null) { Assert.assertTrue(isNon()); } // Else and Elif nodes have an If or Elif as parent. if (this.isElse() || this.isElif()) { - if (beforeParent != null) { - Assert.assertTrue(beforeParent.isIf() || beforeParent.isElif(), "Before parent " + beforeParent + " of " + this + " is neither IF nor ELIF!"); + if (getParent(BEFORE) != null) { + Assert.assertTrue(getParent(BEFORE).isIf() || getParent(BEFORE).isElif(), "Before parent " + getParent(BEFORE) + " of " + this + " is neither IF nor ELIF!"); } - if (afterParent != null) { - Assert.assertTrue(afterParent.isIf() || afterParent.isElif(), "After parent " + afterParent + " of " + this + " is neither IF nor ELIF!"); + if (getParent(AFTER) != null) { + Assert.assertTrue(getParent(AFTER).isIf() || getParent(AFTER).isElif(), "After parent " + getParent(AFTER) + " of " + this + " is neither IF nor ELIF!"); } } diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java index ed27cc7cd..a6123548f 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java @@ -31,6 +31,8 @@ import java.util.function.Consumer; import java.util.function.Predicate; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; import static org.variantsync.functjonal.Functjonal.when; /** @@ -338,16 +340,16 @@ public boolean isEmpty() { public void removeNode(DiffNode node) { Assert.assertTrue(node != root); - final DiffNode beforeParent = node.getBeforeParent(); + final DiffNode beforeParent = node.getParent(BEFORE); if (beforeParent != null) { - beforeParent.removeBeforeChild(node); - beforeParent.addBeforeChildren(node.removeBeforeChildren()); + beforeParent.removeChild(node, BEFORE); + beforeParent.addChildren(node.removeChildren(BEFORE), BEFORE); } - final DiffNode afterParent = node.getAfterParent(); + final DiffNode afterParent = node.getParent(AFTER); if (afterParent != null) { - afterParent.removeAfterChild(node); - afterParent.addAfterChildren(node.removeAfterChildren()); + afterParent.removeChild(node, AFTER); + afterParent.addChildren(node.removeChildren(AFTER), AFTER); } } @@ -394,8 +396,8 @@ public boolean test(final DiffNode d) { // The stranger is now known. cache.putIfAbsent(id, VisitStatus.VISITED); - final DiffNode b = d.getBeforeParent(); - final DiffNode a = d.getAfterParent(); + final DiffNode b = d.getParent(BEFORE); + final DiffNode a = d.getParent(AFTER); if (a == null && b == null) { // We found a second root node which is invalid. yield false; diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java index 98306052e..df55931f1 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java @@ -49,4 +49,15 @@ public T match(final T before, final T after) { case AFTER -> after; }; } + + /** + * Returns the complement of this time. + * @return {@code BEFORE} if {@code this == AFTER} or {@code AFTER} if {@code this == BEFORE} + */ + public Time other() { + return switch (this) { + case BEFORE -> AFTER; + case AFTER -> BEFORE; + }; + } } diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/Format.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/Format.java index 66b5fb156..121a9a063 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/Format.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/Format.java @@ -7,6 +7,9 @@ import org.variantsync.diffdetective.diff.difftree.serialize.edgeformat.EdgeLabelFormat; import org.variantsync.diffdetective.diff.difftree.serialize.nodeformat.DiffNodeLabelFormat; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Format used for exporting a {@link DiffTree}. * For easy reusability this class is composed of separate node and edge formats. @@ -84,8 +87,8 @@ public void forEachEdge(DiffTree diffTree, Consumer callback) { */ public void forEachUniqueEdge(DiffTree diffTree, Consumer> callback) { diffTree.forAll((node) -> { - var beforeParent = node.getBeforeParent(); - var afterParent = node.getAfterParent(); + var beforeParent = node.getParent(BEFORE); + var afterParent = node.getParent(AFTER); // Are both parent edges the same? if (beforeParent != null && afterParent != null && beforeParent == afterParent) { @@ -108,7 +111,7 @@ public void forEachUniqueEdge(DiffTree diffTree, Consumer> call * of {@link getEdgeFormat()}. */ protected StyledEdge beforeEdge(DiffNode node) { - return sortedEdgeWithLabel(node, node.getBeforeParent(), StyledEdge.BEFORE); + return sortedEdgeWithLabel(node, node.getParent(BEFORE), StyledEdge.BEFORE); } /** @@ -118,7 +121,7 @@ protected StyledEdge beforeEdge(DiffNode node) { * of {@link getEdgeFormat()}. */ protected StyledEdge afterEdge(DiffNode node) { - return sortedEdgeWithLabel(node, node.getAfterParent(), StyledEdge.AFTER); + return sortedEdgeWithLabel(node, node.getParent(AFTER), StyledEdge.AFTER); } /** diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/edgeformat/EdgeLabelFormat.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/edgeformat/EdgeLabelFormat.java index 3ab75ce95..5b9c10925 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/edgeformat/EdgeLabelFormat.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/serialize/edgeformat/EdgeLabelFormat.java @@ -10,6 +10,9 @@ import java.util.List; import java.util.Map; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Reads and writes edges between {@link DiffNode DiffNodes} from and to line graph. * @@ -83,7 +86,7 @@ public Direction getEdgeDirection() { /** * Adds the given child node as the child of the given parent node for all times described by the given label - * (via {@link DiffNode#addBeforeChild(DiffNode)} and {@link DiffNode#addAfterChild(DiffNode)}) + * (via {@link DiffNode#addChild(DiffNode, Time)}) * In particular, this method checks if the given edge label starts with * {@link LineGraphConstants#BEFORE_PARENT}, {@link LineGraphConstants#AFTER_PARENT}, or * {@link LineGraphConstants#BEFORE_AND_AFTER_PARENT} and connects both nodes accordingly. @@ -95,14 +98,14 @@ public Direction getEdgeDirection() { protected void connectAccordingToLabel(final DiffNode child, final DiffNode parent, final String edgeLabel) { if (edgeLabel.startsWith(LineGraphConstants.BEFORE_AND_AFTER_PARENT)) { // Nothing has been changed. The child-parent relationship remains the same - Assert.assertTrue(parent.addAfterChild(child)); - Assert.assertTrue(parent.addBeforeChild(child)); + Assert.assertTrue(parent.addChild(child, AFTER)); + Assert.assertTrue(parent.addChild(child, BEFORE)); } else if (edgeLabel.startsWith(LineGraphConstants.BEFORE_PARENT)) { // The child DiffNode lost its parent DiffNode (an orphan DiffNode) - Assert.assertTrue(parent.addBeforeChild(child)); + Assert.assertTrue(parent.addChild(child, BEFORE)); } else if (edgeLabel.startsWith(LineGraphConstants.AFTER_PARENT)) { // The parent DiffNode has a new child DiffNode - Assert.assertTrue(parent.addAfterChild(child)); + Assert.assertTrue(parent.addChild(child, AFTER)); } else { throw new IllegalArgumentException("Syntax error. Invalid name in edge label " + edgeLabel); } diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CollapseNestedNonEditedAnnotations.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CollapseNestedNonEditedAnnotations.java index 737840218..9fbf5760d 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CollapseNestedNonEditedAnnotations.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CollapseNestedNonEditedAnnotations.java @@ -13,6 +13,9 @@ import java.util.List; import java.util.Stack; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Collapses chains of nested non-edited annotations. * Imagine a annotation node that is unchanged and has the same parent before and after the edit @@ -72,7 +75,7 @@ private void findChains(DiffTreeTraversal traversal, DiffNode subtree) { s.push(subtree); chainCandidates.add(s); } else if (inChainTail(subtree)) { - final DiffNode parent = subtree.getBeforeParent(); // == after parent + final DiffNode parent = subtree.getParent(BEFORE); // == after parent Stack pushedTo = null; for (final Stack s : chainCandidates) { @@ -104,9 +107,9 @@ private static void collapseChain(Stack chain) { switch (lastPopped.nodeType) { case IF -> - featureMappings.add(lastPopped.getAfterFeatureMapping()); + featureMappings.add(lastPopped.getFeatureMapping(AFTER)); case ELSE, ELIF -> { - featureMappings.add(lastPopped.getAfterFeatureMapping()); + featureMappings.add(lastPopped.getFeatureMapping(AFTER)); // Pop all previous ELIF cases and the final IF (if present) as we accounted // for their features mappings already. while (!lastPopped.isIf() && !chain.isEmpty()) { @@ -120,8 +123,8 @@ private static void collapseChain(Stack chain) { Assert.assertTrue(head == lastPopped); - final DiffNode beforeParent = head.getBeforeParent(); - final DiffNode afterParent = head.getAfterParent(); + final DiffNode beforeParent = head.getParent(BEFORE); + final DiffNode afterParent = head.getParent(AFTER); ArrayList lines = new ArrayList(); lines.add("$Collapsed Nested Annotations$"); @@ -158,14 +161,14 @@ private static boolean hasExactlyOneChild(DiffNode d) { * @return True iff d is in the tail of a chain. */ private static boolean inChainTail(DiffNode d) { - return d.getBeforeParent() == d.getAfterParent() && hasExactlyOneChild(d.getBeforeParent()); + return d.getParent(BEFORE) == d.getParent(AFTER) && hasExactlyOneChild(d.getParent(BEFORE)); } /** * @return True iff d is the head of a chain. */ private static boolean isHead(DiffNode d) { - return (!inChainTail(d) || d.getBeforeParent().isRoot()) && !isEnd(d); + return (!inChainTail(d) || d.getParent(BEFORE).isRoot()) && !isEnd(d); } /** diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CutNonEditedSubtrees.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CutNonEditedSubtrees.java index cdc954813..f99d3dc44 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CutNonEditedSubtrees.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/CutNonEditedSubtrees.java @@ -7,6 +7,9 @@ import java.util.ArrayList; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * This transformer removes all subtrees from a DiffTree that are non-edited. * A subtree is unedited, if all nodes in it are unchanged and all nodes have the same @@ -49,8 +52,8 @@ public void visit(final DiffTreeTraversal traversal, final DiffNode subtree) { */ if ( child.getAllChildren().isEmpty() - && child.getAfterParent() == subtree - && child.getBeforeParent() == subtree) + && child.getParent(AFTER) == subtree + && child.getParent(BEFORE) == subtree) { collapsableChildren.add(child); } diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/NaiveMovedArtifactDetection.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/NaiveMovedArtifactDetection.java index 492f17be8..f7ea12ea5 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/NaiveMovedArtifactDetection.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/NaiveMovedArtifactDetection.java @@ -9,6 +9,9 @@ import java.util.ArrayList; import java.util.List; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Finds artifact nodes whose label is exactly equal. If one of those nodes was added and the other one was removed, * NaiveMovedArtifactDetection merges them and interprets this edit as a move instead of separate insertion and deletion. @@ -34,8 +37,8 @@ public void transform(final DiffTree diffTree) { removed = twin.first(); } - final DiffNode afterParent = added.getAfterParent(); - final DiffNode beforeParent = removed.getBeforeParent(); + final DiffNode afterParent = added.getParent(AFTER); + final DiffNode beforeParent = removed.getParent(BEFORE); final DiffNode mergedNode = merge(added, removed); added.drop(); diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/Starfold.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/Starfold.java index 1baae6711..3ab175db1 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/Starfold.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/transform/Starfold.java @@ -89,7 +89,7 @@ private void mergeArms(final DiffNode starRoot, Time time, final DiffType target if (starArms.size() > 1) { final int targetIndex = starRoot.indexOfChild(starArms.get(0)); starRoot.removeChildren(starArms); - starRoot.insertChildAt( + starRoot.insertChild( DiffNode.createArtifact( targetDiffType, DiffLineNumber.Invalid(), diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddToPC.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddToPC.java index 75eeb9dad..0cc723a52 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddToPC.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddToPC.java @@ -4,6 +4,8 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + /** * Our AddToPC edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -15,6 +17,6 @@ final class AddToPC extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode node) { - return !node.getAfterParent().isAdd(); + return !node.getParent(AFTER).isAdd(); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddWithMapping.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddWithMapping.java index 679a0255e..264bc4fb7 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddWithMapping.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/AddWithMapping.java @@ -4,6 +4,8 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + /** * Our AddWithMapping edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -15,6 +17,6 @@ final class AddWithMapping extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - return artifactNode.getAfterParent().isAdd(); + return artifactNode.getParent(AFTER).isAdd(); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Generalization.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Generalization.java index 8cfb6e4aa..d91c23d13 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Generalization.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Generalization.java @@ -6,6 +6,9 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Our Generalization edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -17,8 +20,8 @@ final class Generalization extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - final Node pcb = artifactNode.getBeforeFeatureMapping(); - final Node pca = artifactNode.getAfterFeatureMapping(); + final Node pcb = artifactNode.getFeatureMapping(BEFORE); + final Node pca = artifactNode.getFeatureMapping(AFTER); return SAT.implies(pcb, pca) && !SAT.implies(pca, pcb); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/ProposedEditClasses.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/ProposedEditClasses.java index f8a3f278a..c26b479a4 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/ProposedEditClasses.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/ProposedEditClasses.java @@ -10,6 +10,9 @@ import java.util.*; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * The catalog of edit classes proposed in our ESEC/FSE'22 paper. * @author Paul Bittner @@ -76,13 +79,13 @@ public EditClass match(DiffNode node) } if (node.isAdd()) { - if (node.getAfterParent().isAdd()) { + if (node.getParent(AFTER).isAdd()) { return AddWithMapping; } else { return AddToPC; } } else if (node.isRem()) { - if (node.getBeforeParent().isRem()) { + if (node.getParent(BEFORE).isRem()) { return RemWithMapping; } else { return RemFromPC; @@ -90,8 +93,8 @@ public EditClass match(DiffNode node) } else { Assert.assertTrue(node.isNon()); - final Node pcb = node.getBeforePresenceCondition(); - final Node pca = node.getAfterPresenceCondition(); + final Node pcb = node.getPresenceCondition(BEFORE); + final Node pca = node.getPresenceCondition(AFTER); final boolean beforeVariantsSubsetOfAfterVariants; final boolean afterVariantsSubsetOfBeforeVariants; diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Reconfiguration.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Reconfiguration.java index cbe7de735..385494a95 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Reconfiguration.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Reconfiguration.java @@ -6,6 +6,9 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Our Reconfiguration edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -17,8 +20,8 @@ final class Reconfiguration extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - final Node pcb = artifactNode.getBeforeFeatureMapping(); - final Node pca = artifactNode.getAfterFeatureMapping(); + final Node pcb = artifactNode.getFeatureMapping(BEFORE); + final Node pca = artifactNode.getFeatureMapping(AFTER); return !SAT.implies(pcb, pca) && !SAT.implies(pca, pcb); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Refactoring.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Refactoring.java index e2a2c82ca..66ee3300d 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Refactoring.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Refactoring.java @@ -6,6 +6,9 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Our Refactoring edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -17,8 +20,8 @@ final class Refactoring extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - final Node pcb = artifactNode.getBeforeFeatureMapping(); - final Node pca = artifactNode.getAfterFeatureMapping(); + final Node pcb = artifactNode.getFeatureMapping(BEFORE); + final Node pca = artifactNode.getFeatureMapping(AFTER); return SAT.equivalent(pcb, pca) && !artifactNode.beforePathEqualsAfterPath(); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemFromPC.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemFromPC.java index 436684ccc..e82594c0e 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemFromPC.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemFromPC.java @@ -4,6 +4,8 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Our RemFromPC edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -15,6 +17,6 @@ final class RemFromPC extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - return !artifactNode.getBeforeParent().isRem(); + return !artifactNode.getParent(BEFORE).isRem(); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemWithMapping.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemWithMapping.java index a527e7f9d..9f803bb94 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemWithMapping.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/RemWithMapping.java @@ -4,6 +4,8 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Our RemWithMapping edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -15,6 +17,6 @@ final class RemWithMapping extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - return artifactNode.getBeforeParent().isRem(); + return artifactNode.getParent(BEFORE).isRem(); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Specialization.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Specialization.java index 0ef55ac55..0be909f11 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Specialization.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Specialization.java @@ -6,6 +6,9 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Our Specialization edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -17,8 +20,8 @@ final class Specialization extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - final Node pcb = artifactNode.getBeforeFeatureMapping(); - final Node pca = artifactNode.getAfterFeatureMapping(); + final Node pcb = artifactNode.getFeatureMapping(BEFORE); + final Node pca = artifactNode.getFeatureMapping(AFTER); return !SAT.implies(pcb, pca) && SAT.implies(pca, pcb); } } diff --git a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Untouched.java b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Untouched.java index a5bef0e7e..bf7ef41b7 100644 --- a/src/main/java/org/variantsync/diffdetective/editclass/proposed/Untouched.java +++ b/src/main/java/org/variantsync/diffdetective/editclass/proposed/Untouched.java @@ -6,6 +6,9 @@ import org.variantsync.diffdetective.diff.difftree.DiffType; import org.variantsync.diffdetective.editclass.EditClass; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + /** * Our Untouched edit class from the ESEC/FSE'22 paper. * @author Paul Bittner, Sören Viegener @@ -17,8 +20,8 @@ final class Untouched extends EditClass { @Override protected boolean matchesArtifactNode(DiffNode artifactNode) { - final Node pcb = artifactNode.getBeforeFeatureMapping(); - final Node pca = artifactNode.getAfterFeatureMapping(); + final Node pcb = artifactNode.getFeatureMapping(BEFORE); + final Node pca = artifactNode.getFeatureMapping(AFTER); return SAT.equivalent(pcb, pca) && artifactNode.beforePathEqualsAfterPath(); } } diff --git a/src/main/java/org/variantsync/diffdetective/mining/RunningExampleFinder.java b/src/main/java/org/variantsync/diffdetective/mining/RunningExampleFinder.java index 15367bc4d..ed909ee05 100644 --- a/src/main/java/org/variantsync/diffdetective/mining/RunningExampleFinder.java +++ b/src/main/java/org/variantsync/diffdetective/mining/RunningExampleFinder.java @@ -19,6 +19,8 @@ import java.nio.file.Path; import java.util.Optional; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + public class RunningExampleFinder { public static final Path DefaultExamplesDirectory = Path.of("examples"); public static final int DefaultMaxDiffLineCount = 20; @@ -77,8 +79,8 @@ private static boolean hasAnnotatedMacros(final DiffTree diffTree) { private static boolean hasNestingBeforeEdit(final DiffTree diffTree) { return diffTree.anyMatch(n -> !n.isAdd() - && n.getBeforeDepth() > 2 - && !(n.getBeforeParent().isElse() || n.getBeforeParent().isElif()) + && n.getDepth(BEFORE) > 2 + && !(n.getParent(BEFORE).isElse() || n.getParent(BEFORE).isElif()) ); } diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddToPC.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddToPC.java index d88b2a11b..0af139088 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddToPC.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddToPC.java @@ -9,6 +9,8 @@ import org.variantsync.diffdetective.preliminary.evaluation.FeatureContext; import org.variantsync.diffdetective.preliminary.pattern.FeatureContextReverseEngineering; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + @Deprecated public final class FeatureContextOfAddToPC implements FeatureContextReverseEngineering { @Override @@ -18,7 +20,7 @@ public Pattern getPattern() { @Override public PatternMatch createMatch(DiffNode codeNode) { - final Node fm = codeNode.getAfterParent().getAfterFeatureMapping(); + final Node fm = codeNode.getParent(AFTER).getFeatureMapping(AFTER); final Lines diffLines = codeNode.getLinesInDiff(); return new PatternMatch<>(this, diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddWithMapping.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddWithMapping.java index 883ec9177..7a54a1f90 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddWithMapping.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfAddWithMapping.java @@ -9,6 +9,8 @@ import org.variantsync.diffdetective.preliminary.evaluation.FeatureContext; import org.variantsync.diffdetective.preliminary.pattern.FeatureContextReverseEngineering; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + @Deprecated public final class FeatureContextOfAddWithMapping implements FeatureContextReverseEngineering { @Override @@ -18,7 +20,7 @@ public Pattern getPattern() { @Override public PatternMatch createMatch(DiffNode codeNode) { - final Node fm = codeNode.getAfterParent().getAfterFeatureMapping(); + final Node fm = codeNode.getParent(AFTER).getFeatureMapping(AFTER); final Lines diffLines = codeNode.getLinesInDiff(); return new PatternMatch<>(this, diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemFromPC.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemFromPC.java index d8ab176fe..ff2b1d7f8 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemFromPC.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemFromPC.java @@ -9,6 +9,8 @@ import org.variantsync.diffdetective.preliminary.evaluation.FeatureContext; import org.variantsync.diffdetective.preliminary.pattern.FeatureContextReverseEngineering; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + @Deprecated public final class FeatureContextOfRemFromPC implements FeatureContextReverseEngineering { @Override @@ -18,7 +20,7 @@ public Pattern getPattern() { @Override public PatternMatch createMatch(DiffNode codeNode) { - final Node fm = codeNode.getBeforeParent().getBeforeFeatureMapping(); + final Node fm = codeNode.getParent(BEFORE).getFeatureMapping(BEFORE); final Lines diffLines = codeNode.getLinesInDiff(); return new PatternMatch<>(this, diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemWithMapping.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemWithMapping.java index af21ac27e..bcccd6a3c 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemWithMapping.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/elementary/FeatureContextOfRemWithMapping.java @@ -9,6 +9,8 @@ import org.variantsync.diffdetective.preliminary.evaluation.FeatureContext; import org.variantsync.diffdetective.preliminary.pattern.FeatureContextReverseEngineering; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + @Deprecated public final class FeatureContextOfRemWithMapping implements FeatureContextReverseEngineering { @Override @@ -18,7 +20,7 @@ public Pattern getPattern() { @Override public PatternMatch createMatch(DiffNode codeNode) { - final Node fm = codeNode.getBeforeParent().getBeforeFeatureMapping(); + final Node fm = codeNode.getParent(BEFORE).getFeatureMapping(BEFORE); final Lines diffLines = codeNode.getLinesInDiff(); return new PatternMatch<>(this, diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElif.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElif.java index f649a2c23..e1b77da16 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElif.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElif.java @@ -10,6 +10,8 @@ import java.util.List; import java.util.Optional; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + @Deprecated class AddIfdefElif extends SemanticPattern { AddIfdefElif() { @@ -40,7 +42,7 @@ public Optional> match(DiffNode annotationNode) { } List mappings = new ArrayList<>(); - mappings.add(annotationNode.getAfterFeatureMapping()); + mappings.add(annotationNode.getFeatureMapping(AFTER)); if(elifNode == null || !addedCodeInIf || !isValidElif(elifNode, mappings)){ return Optional.empty(); } @@ -68,7 +70,7 @@ private boolean isValidElif(DiffNode elifNode, List mappings) { } } if(addedCode && nextNode != null){ - mappings.add(elifNode.getAfterFeatureMapping()); + mappings.add(elifNode.getFeatureMapping(AFTER)); return isValidElif(nextNode, mappings); } diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElse.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElse.java index e7552cb6d..ae6f93a40 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElse.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefElse.java @@ -7,6 +7,8 @@ import java.util.Optional; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + @Deprecated class AddIfdefElse extends SemanticPattern { AddIfdefElse() { @@ -55,7 +57,7 @@ public Optional> match(DiffNode annotationNode) { return Optional.of(new PatternMatch<>(this, annotationNode.getLinesInDiff().getFromInclusive(), elseNode.getLinesInDiff().getToExclusive(), - annotationNode.getAfterFeatureMapping() + annotationNode.getFeatureMapping(AFTER) )); } diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapElse.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapElse.java index de0746ee1..b9df7a38e 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapElse.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapElse.java @@ -6,6 +6,8 @@ import java.util.Optional; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + @Deprecated class AddIfdefWrapElse extends SemanticPattern { public AddIfdefWrapElse() { @@ -54,7 +56,7 @@ public Optional> match(DiffNode annotationNode) { return Optional.of(new PatternMatch<>(this, annotationNode.getLinesInDiff().getFromInclusive(), elseNode.getLinesInDiff().getToExclusive(), - annotationNode.getAfterFeatureMapping() + annotationNode.getFeatureMapping(AFTER) )); } diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapThen.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapThen.java index ab673caae..3d279540d 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapThen.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/AddIfdefWrapThen.java @@ -7,6 +7,8 @@ import java.util.Optional; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + @Deprecated class AddIfdefWrapThen extends SemanticPattern { AddIfdefWrapThen() { @@ -55,7 +57,7 @@ public Optional> match(DiffNode annotationNode) { return Optional.of(new PatternMatch<>(this, annotationNode.getLinesInDiff().getFromInclusive(), elseNode.getLinesInDiff().getToExclusive(), - annotationNode.getAfterFeatureMapping() + annotationNode.getFeatureMapping(AFTER) )); } diff --git a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/MoveElse.java b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/MoveElse.java index 7b4659b75..54bb10b00 100644 --- a/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/MoveElse.java +++ b/src/main/java/org/variantsync/diffdetective/preliminary/pattern/semantic/MoveElse.java @@ -7,6 +7,8 @@ import java.util.Collection; import java.util.Optional; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; + @Deprecated class MoveElse extends SemanticPattern { MoveElse() { @@ -24,7 +26,7 @@ public Optional> match(DiffNode annotationNode) { if(annotationNode.isAdd() && annotationNode.isElse()){ DiffNode removedElse = null; - for(DiffNode parentsChild : annotationNode.getAfterParent().getAllChildren()){ + for(DiffNode parentsChild : annotationNode.getParent(AFTER).getAllChildren()){ if(parentsChild.isElse() && parentsChild.isRem()){ removedElse = parentsChild; break; @@ -36,10 +38,10 @@ public Optional> match(DiffNode annotationNode) { } Collection commonAddElse = annotationNode.getAllChildren(); - commonAddElse.retainAll(annotationNode.getAfterParent().getAllChildren()); + commonAddElse.retainAll(annotationNode.getParent(AFTER).getAllChildren()); Collection commonRemElse = removedElse.getAllChildren(); - commonRemElse.retainAll(annotationNode.getAfterParent().getAllChildren()); + commonRemElse.retainAll(annotationNode.getParent(AFTER).getAllChildren()); if(commonAddElse.isEmpty() && commonRemElse.isEmpty()){ return Optional.empty(); diff --git a/src/test/java/MarlinDebug.java b/src/test/java/MarlinDebug.java index 9357e7f78..b38218e94 100644 --- a/src/test/java/MarlinDebug.java +++ b/src/test/java/MarlinDebug.java @@ -31,6 +31,9 @@ import java.nio.file.Paths; import java.util.List; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + @Deprecated @Disabled public class MarlinDebug { @@ -110,8 +113,8 @@ public static void testCommit(final RepoInspection repoInspection, final String //LineGraphExportOptions.RenderError().accept(patch, e); Logger.error(e); Logger.info("Died at node {}", node.toString()); - Logger.info(" before parent: {}", node.getBeforeParent()); - Logger.info(" after parent: {}", node.getBeforeParent()); + Logger.info(" before parent: {}", node.getParent(BEFORE)); + Logger.info(" after parent: {}", node.getParent(AFTER)); Logger.info("isAdd: {}", node.isAdd()); Logger.info("isRem: {}", node.isRem()); Logger.info("isNon: {}", node.isNon()); diff --git a/src/test/java/PCTest.java b/src/test/java/PCTest.java index cb5c3d0b7..6969ed687 100644 --- a/src/test/java/PCTest.java +++ b/src/test/java/PCTest.java @@ -14,6 +14,8 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; import static org.variantsync.diffdetective.util.fide.FormulaUtils.negate; public class PCTest { @@ -75,11 +77,11 @@ public void test(final TestCase testCase) throws IOException, DiffParseException final String text = node.getLabel().trim(); final ExpectedPC expectedPC = testCase.expectedResult.getOrDefault(text, null); if (expectedPC != null) { - Node pc = node.getBeforePresenceCondition(); + Node pc = node.getPresenceCondition(BEFORE); assertTrue( SAT.equivalent(pc, expectedPC.before), errorAt(text, "before", pc, expectedPC.before)); - pc = node.getAfterPresenceCondition(); + pc = node.getPresenceCondition(AFTER); assertTrue( SAT.equivalent(pc, expectedPC.after), errorAt(text, "after", pc, expectedPC.after)); diff --git a/src/test/java/TestLineNumbers.java b/src/test/java/TestLineNumbers.java index 7bcb95552..3c4917271 100644 --- a/src/test/java/TestLineNumbers.java +++ b/src/test/java/TestLineNumbers.java @@ -14,6 +14,9 @@ import java.util.Map; import java.util.function.Function; +import static org.variantsync.diffdetective.diff.difftree.Time.AFTER; +import static org.variantsync.diffdetective.diff.difftree.Time.BEFORE; + public class TestLineNumbers { private static final Path resDir = Constants.RESOURCE_DIR.resolve("diffs/linenumbers"); private record TestCase(String filename, Map> expectedLineNumbers) { } @@ -69,9 +72,9 @@ private static void printLineNumbers(final DiffTree diffTree) { + " " + node.nodeType + " \"" + node.getLabel().trim() + " with ID " + node.getID() - + "\" old: " + node.getLinesBeforeEdit() + + "\" old: " + node.getLinesAtTime(BEFORE) + ", diff: " + node.getLinesInDiff() - + ", new: " + node.getLinesAfterEdit()) + + ", new: " + node.getLinesAtTime(AFTER)) ); System.out.println(); } From 4fe668ef3aefbf35f9fe8d38d4b766cc4b4407c6 Mon Sep 17 00:00:00 2001 From: Benjamin Moosherr Date: Sun, 30 Oct 2022 20:53:51 +0100 Subject: [PATCH 02/11] Use Time.forAll where appropriate --- .../diffdetective/diff/difftree/DiffNode.java | 39 ++++++++----------- .../diffdetective/diff/difftree/DiffTree.java | 18 ++++----- .../diffdetective/diff/difftree/Time.java | 2 +- .../serialize/edgeformat/EdgeLabelFormat.java | 4 +- .../diff/difftree/transform/Starfold.java | 2 +- 5 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java index a6c34112d..004cdd793 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffNode.java @@ -286,12 +286,11 @@ public boolean addBelow(final DiffNode newBeforeParent, final DiffNode newAfterP * Inverse of addBelow. */ public void drop() { - if (getParent(BEFORE) != null) { - getParent(BEFORE).removeChild(this, BEFORE); - } - if (getParent(AFTER) != null) { - getParent(AFTER).removeChild(this, AFTER); - } + Time.forAll(time -> { + if (getParent(time) != null) { + getParent(time).removeChild(this, time); + } + }); } /** @@ -377,8 +376,7 @@ public boolean removeChild(final DiffNode child, Time time) { */ public void removeChildren(final Collection childrenToRemove) { for (final DiffNode childToRemove : childrenToRemove) { - removeChild(childToRemove, BEFORE); - removeChild(childToRemove, AFTER); + Time.forAll(time -> removeChild(childToRemove, time)); } } @@ -426,8 +424,7 @@ private void removeFromCache(final DiffNode child) { * @param other The node whose children should be stolen. */ public void stealChildrenOf(final DiffNode other) { - addChildren(other.removeChildren(BEFORE), BEFORE); - addChildren(other.removeChildren(AFTER), AFTER); + Time.forAll(time -> addChildren(other.removeChildren(time), time)); } /** @@ -766,12 +763,11 @@ public void assertConsistency() { // check consistency of children lists and edges for (final DiffNode c : childOrder) { Assert.assertTrue(isChild(c), () -> "Child " + c + " of " + this + " is neither a before nor an after child!"); - if (c.getParent(BEFORE) != null) { - Assert.assertTrue(c.getParent(BEFORE).isChild(c, BEFORE), () -> "The parent before the edit of " + c + " doesn't contain that node as child"); - } - if (c.getParent(AFTER) != null) { - Assert.assertTrue(c.getParent(AFTER).isChild(c, AFTER), () -> "The parent after the edit of " + c + " doesn't contain that node as child"); - } + Time.forAll(time -> { + if (c.getParent(time) != null) { + Assert.assertTrue(c.getParent(time).isChild(c, time), () -> "The parent " + time.toString().toLowerCase() + " the edit of " + c + " doesn't contain that node as child"); + } + }); } // a node with exactly one parent was edited @@ -788,12 +784,11 @@ public void assertConsistency() { // Else and Elif nodes have an If or Elif as parent. if (this.isElse() || this.isElif()) { - if (getParent(BEFORE) != null) { - Assert.assertTrue(getParent(BEFORE).isIf() || getParent(BEFORE).isElif(), "Before parent " + getParent(BEFORE) + " of " + this + " is neither IF nor ELIF!"); - } - if (getParent(AFTER) != null) { - Assert.assertTrue(getParent(AFTER).isIf() || getParent(AFTER).isElif(), "After parent " + getParent(AFTER) + " of " + this + " is neither IF nor ELIF!"); - } + Time.forAll(time -> { + if (getParent(time) != null) { + Assert.assertTrue(getParent(time).isIf() || getParent(time).isElif(), time + " parent " + getParent(time) + " of " + this + " is neither IF nor ELIF!"); + } + }); } // Only if and elif nodes have a formula diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java index a6123548f..d9e0b47b9 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/DiffTree.java @@ -340,17 +340,13 @@ public boolean isEmpty() { public void removeNode(DiffNode node) { Assert.assertTrue(node != root); - final DiffNode beforeParent = node.getParent(BEFORE); - if (beforeParent != null) { - beforeParent.removeChild(node, BEFORE); - beforeParent.addChildren(node.removeChildren(BEFORE), BEFORE); - } - - final DiffNode afterParent = node.getParent(AFTER); - if (afterParent != null) { - afterParent.removeChild(node, AFTER); - afterParent.addChildren(node.removeChildren(AFTER), AFTER); - } + Time.forAll(time -> { + final DiffNode parent = node.getParent(time); + if (parent != null) { + parent.removeChild(node, time); + parent.addChildren(node.removeChildren(time), time); + } + }); } /** diff --git a/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java b/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java index df55931f1..21a18f1b9 100644 --- a/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java +++ b/src/main/java/org/variantsync/diffdetective/diff/difftree/Time.java @@ -15,7 +15,7 @@ public enum Time { * Invoke the given function for each time value (i.e., each value in this enum). * @param f callback */ - public static void forall(final Consumer