Skip to content

Commit

Permalink
Merge pull request #35 from kniazkov/master
Browse files Browse the repository at this point in the history
MOS-1864: Fix partial pattern application in matcher
  • Loading branch information
kniazkov authored Dec 3, 2024
2 parents 55332f6 + 927daa1 commit bd907ff
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ Set<Node> match(final Pattern pattern) {
);
final Set<Node> set = new HashSet<>();
for (final Node node : preset) {
final boolean matches = this.checkNode(node, null, head);
final ActionList applicants = new ActionList();
final boolean matches = Matcher.checkNode(node, head, applicants);
if (matches) {
set.add(node);
this.actions.merge(applicants);
}
}
return set;
Expand All @@ -97,12 +99,12 @@ Set<Node> match(final Pattern pattern) {
/**
* Checks if the node of the original tree matches the pattern node.
* @param node Node of the original tree
* @param parent Parent node of the node being checked.
* @param pattern Node of the difference tree (i.e. pattern)
* @param actions List of actions to be performed to apply the pattern
* @return Matching result ({@code true} if matches)
*/
@SuppressWarnings("PMD.UnusedFormalParameter")
private boolean checkNode(final Node node, final Node parent, final Node pattern) {
private static boolean checkNode(
final Node node, final Node pattern, final ActionList actions) {
final Node sample;
final Action action = Action.toAction(pattern);
if (action instanceof Replace || action instanceof Delete) {
Expand All @@ -113,12 +115,13 @@ private boolean checkNode(final Node node, final Node parent, final Node pattern
boolean result = node.getTypeName().equals(sample.getTypeName());
if (!(pattern instanceof Hole)) {
result = result && node.getData().equals(sample.getData());
result = result && (node.getChildCount() == 0 || this.checkChildren(node, sample));
result = result && (node.getChildCount() == 0
|| Matcher.checkChildren(node, sample, actions));
}
if (result && action instanceof Replace) {
this.actions.replaceNode(node, action.getAfter());
actions.replaceNode(node, action.getAfter());
} else if (result & action instanceof Delete) {
this.actions.deleteNode(node);
actions.deleteNode(node);
}
return result;
}
Expand All @@ -128,12 +131,15 @@ private boolean checkNode(final Node node, final Node parent, final Node pattern
* matches the children of the pattern node.
* @param node Node of the original tree
* @param sample Node of the difference tree (i.e. pattern)
* @param actions List of actions to be performed to apply the pattern
* @return Matching result ({@code true} if matches)
*/
private boolean checkChildren(final Node node, final Node sample) {
private static boolean checkChildren(
final Node node, final Node sample, final ActionList actions) {
final int left = node.getChildCount();
final int right = sample.getChildCount();
boolean result = false;
final ActionList applicants = new ActionList();
for (int index = 0; !result && index < left; index = index + 1) {
result = true;
final Iterator<Node> iterator = sample.getIteratorOverChildren();
Expand All @@ -143,20 +149,23 @@ private boolean checkChildren(final Node node, final Node sample) {
final Node child = iterator.next();
final Action action = Action.toAction(child);
if (action instanceof Insert) {
this.actions.insertNodeAfter(action.getAfter(), node, current);
applicants.insertNodeAfter(action.getAfter(), node, current);
} else if (index + offset >= left) {
result = false;
} else {
current = node.getChild(index + offset);
result = this.checkNode(
result = Matcher.checkNode(
current,
node,
child
child,
applicants
);
offset = offset + 1;
}
}
}
if (result) {
actions.merge(applicants);
}
return result;
}
}
17 changes: 14 additions & 3 deletions src/main/java/org/cqfn/astranaut/core/base/ActionList.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
*/
package org.cqfn.astranaut.core.base;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
Expand All @@ -33,14 +35,13 @@

/**
* List of actions to be added to the tree after deserialization to produce a difference tree.
*
* @since 1.1.0
*/
public final class ActionList {
/**
* Collection of nodes to be inserted.
*/
private final Set<Insertion> insert;
private final List<Insertion> insert;

/**
* Collection of nodes to be replaced (node before changes -> node after changes).
Expand All @@ -56,7 +57,7 @@ public final class ActionList {
* Constructor.
*/
public ActionList() {
this.insert = new HashSet<>();
this.insert = new ArrayList<>(0);
this.replace = new HashMap<>();
this.delete = new HashSet<>();
}
Expand Down Expand Up @@ -109,6 +110,16 @@ public void deleteNode(final Node node) {
this.delete.add(node);
}

/**
* Adds actions from another list to the current list.
* @param other Another action list
*/
public void merge(final ActionList other) {
this.insert.addAll(other.insert);
this.replace.putAll(other.replace);
this.delete.addAll(other.delete);
}

/**
* Converts the tree to a difference tree using the list of actions.
* @param tree Source tree
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@
import java.util.Set;
import java.util.TreeMap;
import org.cqfn.astranaut.core.algorithms.DiffTreeBuilder;
import org.cqfn.astranaut.core.algorithms.PatternBuilder;
import org.cqfn.astranaut.core.algorithms.mapping.Mapper;
import org.cqfn.astranaut.core.algorithms.mapping.TopDownMapper;
import org.cqfn.astranaut.core.base.Builder;
import org.cqfn.astranaut.core.base.DiffNode;
import org.cqfn.astranaut.core.base.DiffTree;
import org.cqfn.astranaut.core.base.DraftNode;
import org.cqfn.astranaut.core.base.Insertion;
import org.cqfn.astranaut.core.base.Node;
Expand Down Expand Up @@ -186,4 +190,26 @@ void patchWithPatternThatDoesNotMatch() {
result = patcher.patch(tree, third);
Assertions.assertTrue(tree.deepCompare(result));
}

@Test
void mineAndPatch() {
final Node before = DraftNode.create("X(A,C(D(F(G(H)))))");
final Node after = DraftNode.create("X(A,B,C(D(F(G(I)))))");
final Mapper mapper = TopDownMapper.INSTANCE;
final DiffTreeBuilder diffbuilder = new DiffTreeBuilder(before);
diffbuilder.build(after, mapper);
final DiffTree diff = diffbuilder.getDiffTree();
Assertions.assertTrue(before.deepCompare(diff.getBefore().getRoot()));
Assertions.assertTrue(after.deepCompare(diff.getAfter().getRoot()));
final Pattern pattern = new PatternBuilder(diff).getPattern();
final Tree original = Tree.createDraft(
"Y(X(A,C(D(F(G(J,K))))),X(A,C(D(F(G(L))))),X(A,C(D(F(G(H))))))"
);
final Patcher patcher = DefaultPatcher.INSTANCE;
final Tree patched = patcher.patch(original, pattern);
final Tree expected = Tree.createDraft(
"Y(X(A,C(D(F(G(J,K))))),X(A,C(D(F(G(L))))),X(A,B,C(D(F(G(I))))))"
);
Assertions.assertEquals(expected.toString(), patched.toString());
}
}

0 comments on commit bd907ff

Please sign in to comment.