Skip to content

Commit 24647ec

Browse files
committed
ASTDiff: Introduction of LeftRightAware Matcher
1 parent 5007cdb commit 24647ec

File tree

4 files changed

+163
-10
lines changed

4 files changed

+163
-10
lines changed

src/main/java/org/refactoringminer/astDiff/matchers/statement/BasicTreeMatcher.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.github.gumtreediff.matchers.Mapping;
44
import com.github.gumtreediff.matchers.MappingStore;
5+
import com.github.gumtreediff.tree.FakeTree;
56
import com.github.gumtreediff.tree.Tree;
67
import com.github.gumtreediff.utils.Pair;
78
import org.refactoringminer.astDiff.matchers.*;
@@ -39,13 +40,20 @@ private void basicMatcher(Tree src, Tree dst, ExtendedMultiMappingStore mappingS
3940
}
4041

4142
public MappingStore process(Tree src, Tree dst) {
42-
MappingStore match = new CustomTopDownMatcher(minP).match(src, dst);
43-
new CustomBottomUpMatcher().match(src, dst, match);
44-
optimizeMappings(match);
43+
MappingStore match = new MappingStore(src, dst);
44+
List<Pair<Tree, Tree>> pairs = LRAUtils.LRAify(src, dst, match);
45+
for (Pair<Tree, Tree> pair : pairs) {
46+
MappingStore mappings = new CustomTopDownMatcher(minP).match(pair.first, pair.second);
47+
new CustomBottomUpMatcher().match(pair.first, pair.second, mappings);
48+
optimizeMappings(mappings);
49+
for (Mapping mapping : mappings) {
50+
match.addMapping(mapping.first, mapping.second);
51+
}
52+
}
4553
return match;
4654
}
4755

48-
private static void optimizeMappings(MappingStore match) {
56+
private static void optimizeMappings(MappingStore match) {
4957
List<Pair<Tree, Tree>> removeList = new ArrayList<>();
5058
List<Pair<Tree, Tree>> incorrectMethodExpressionReferenceSimpleName = new ArrayList<>();
5159
for (Mapping mapping : match) {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.refactoringminer.astDiff.matchers.statement;
2+
3+
import com.github.gumtreediff.matchers.MappingStore;
4+
import com.github.gumtreediff.tree.FakeTree;
5+
import com.github.gumtreediff.tree.Tree;
6+
import com.github.gumtreediff.utils.Pair;
7+
import org.refactoringminer.astDiff.utils.Constants;
8+
import org.refactoringminer.astDiff.utils.TreeUtilFunctions;
9+
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
import java.util.function.BiPredicate;
13+
14+
public enum LRAScenarios {
15+
VARIABLE_DECLARATION_STATEMENT(
16+
(src, dst) -> TreeUtilFunctions.areBothFromThisType(src, dst, Constants.VARIABLE_DECLARATION_STATEMENT)) {
17+
@Override
18+
List<Pair<Tree, Tree>> makePairs(Tree src, Tree dst, MappingStore match ) {
19+
List<Pair<Tree,Tree>> pairs = new ArrayList<>();
20+
Tree srcVarDeclFragment = TreeUtilFunctions.findChildByType(src, Constants.VARIABLE_DECLARATION_FRAGMENT);
21+
if (srcVarDeclFragment == null) return pairs;
22+
int indexOfSrcVarDeclFragment = srcVarDeclFragment.positionInParent();
23+
24+
Tree dstVarDeclFragment = TreeUtilFunctions.findChildByType(dst, Constants.VARIABLE_DECLARATION_FRAGMENT);
25+
if (dstVarDeclFragment == null) return pairs;
26+
int indexOfDstVarDeclFragment = dstVarDeclFragment.positionInParent();
27+
28+
FakeTree fake_src1 = new FakeTree();
29+
FakeTree fake_src2 = new FakeTree();
30+
FakeTree fake_dst1 = new FakeTree();
31+
FakeTree fake_dst2 = new FakeTree();
32+
33+
makeSegments(src, indexOfSrcVarDeclFragment, fake_src1, fake_src2);
34+
makeSegments(dst, indexOfDstVarDeclFragment, fake_dst1, fake_dst2);
35+
pairs.add(new Pair<>(fake_src2, fake_dst2));
36+
pairs.add(new Pair<>(fake_src1, fake_dst1));
37+
match.addMapping(src, dst);
38+
return pairs;
39+
}
40+
},
41+
ExpressionStatementWithAssignment(
42+
(src, dst) -> TreeUtilFunctions.areBothFromThisType(src, dst, Constants.EXPRESSION_STATEMENT)
43+
//And both having first child (if they have)
44+
&& (!src.getChildren().isEmpty() && !dst.getChildren().isEmpty())
45+
//and che first child be the assignment
46+
&& (TreeUtilFunctions.areBothFromThisType(src.getChild(0), dst.getChild(0), Constants.ASSIGNMENT))
47+
) {
48+
@Override
49+
List<Pair<Tree, Tree>> makePairs(Tree src, Tree dst, MappingStore match) {
50+
Tree srcAssignment = src.getChild(0);
51+
Tree dstAssignment = dst.getChild(0);
52+
if (srcAssignment.getChildren().size() == 3 && dstAssignment.getChildren().size() == 3) {
53+
match.addMapping(srcAssignment, dstAssignment);
54+
return List.of(
55+
new Pair<>(srcAssignment.getChild(0), dstAssignment.getChild(0)), // left-hand side
56+
new Pair<>(srcAssignment.getChild(1), dstAssignment.getChild(1)), // =
57+
new Pair<>(srcAssignment.getChild(2), dstAssignment.getChild(2)) // right-hand side
58+
);
59+
}
60+
else
61+
return List.of(new Pair<>(src, dst));
62+
}
63+
};
64+
65+
final BiPredicate<Tree, Tree> condition;
66+
abstract List<Pair<Tree,Tree>> makePairs(Tree src, Tree dst, MappingStore match);
67+
68+
LRAScenarios(BiPredicate<Tree, Tree> condition) {
69+
this.condition = condition;
70+
71+
}
72+
73+
private static void makeSegments(Tree src, int indexOfSrcVarDeclFragment, FakeTree fake_src1, FakeTree fake_src2) {
74+
for(int i = 0; i < src.getChildren().size(); i++) {
75+
if (i < indexOfSrcVarDeclFragment) {
76+
Tree child = src.getChild(i);
77+
fake_src1.addChild(child);
78+
} else {
79+
Tree child = src.getChild(i);
80+
fake_src2.addChild(child);
81+
}
82+
}
83+
}
84+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.refactoringminer.astDiff.matchers.statement;
2+
3+
import com.github.gumtreediff.matchers.MappingStore;
4+
import com.github.gumtreediff.tree.Tree;
5+
import com.github.gumtreediff.utils.Pair;
6+
7+
import java.util.List;
8+
9+
//LeftRightAware
10+
public class LRAUtils {
11+
//LeftRightAware + ify
12+
13+
//Technically it should not be necessarily to the pass the existing match to LRAify,
14+
//However breaking the whole tree, into left and right, prevents some matches (i.e. the entire Assignment statement)
15+
//For such instances, match can be passed and further optimized during the LRAify process.
16+
17+
public static List<Pair<Tree, Tree>> LRAify(Tree src, Tree dst, MappingStore match) {
18+
for (LRAScenarios value : LRAScenarios.values()) {
19+
if (value.condition.test(src, dst)) {
20+
return value.makePairs(src, dst, match);
21+
}
22+
}
23+
return List.of(new Pair<>(src, dst)); // Fallback case if no scenario matches
24+
}
25+
}
26+

src/main/java/org/refactoringminer/astDiff/matchers/statement/LeafMatcher.java

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
import org.refactoringminer.astDiff.utils.TreeUtilFunctions;
1313

1414
import java.util.HashMap;
15+
import java.util.List;
1516
import java.util.Map;
17+
18+
import static org.refactoringminer.astDiff.matchers.statement.LRAUtils.LRAify;
19+
1620
/**
1721
* @author Pourya Alikhani Fard pouryafard75@gmail.com
1822
*/
@@ -32,12 +36,13 @@ public void match(Tree src, Tree dst, ExtendedMultiMappingStore mappingStore) {
3236
Map<Tree,Tree> dstCopy = new HashMap<>();
3337
Pair<Tree, Tree> prunedPair = pruneTrees(src, dst, srcCopy, dstCopy);
3438
MappingStore match;
35-
try {
39+
try
40+
{
3641
if (prunedPair.first.isIsoStructuralTo(prunedPair.second))
3742
{
3843
if (!TreeUtilFunctions.isIsomorphicTo(prunedPair.first,prunedPair.second))
3944
{
40-
match = new MoveOptimizedIsomorphic().match(prunedPair.first, prunedPair.second);
45+
match = new LRAMoveOptimizedIsomorphic().match(prunedPair.first, prunedPair.second);
4146
}
4247
else{
4348
match = new MappingStore(src, dst);
@@ -54,9 +59,9 @@ public void match(Tree src, Tree dst, ExtendedMultiMappingStore mappingStore) {
5459
}
5560
catch (Exception exception)
5661
{
57-
//TODO: ADD ERR LOGGING
58-
// logger.error("Error in LeafMatcher", exception);
59-
}
62+
// TODO: ADD ERR LOGGING
63+
System.out.println(exception.getMessage());
64+
}
6065
}
6166
public Pair<Tree,Tree> pruneTrees(Tree src, Tree dst, Map<Tree,Tree> srcCopy, Map<Tree,Tree> dstCopy) {
6267
Tree prunedSrc = TreeUtilFunctions.deepCopyWithMapPruning(src,srcCopy);
@@ -152,9 +157,39 @@ public MoveOptimizedIsomorphic() {
152157
, new UnmappedLeavesMatcherThetaC()
153158
, new InnerNodesMatcherThetaD()
154159
, new LeafMoveMatcherThetaE()
155-
, new CrossMoveMatcherThetaF()
160+
, new SafeCrossMoveMatcherThetaF()
156161
);
157162
}
158163
}
164+
165+
//LeftRightAware (LRA) matcher version of MTD
166+
static class LRAMoveOptimizedIsomorphic extends MoveOptimizedIsomorphic {
167+
@Override
168+
public MappingStore match(Tree src, Tree dst) {
169+
return match(src, dst, new MappingStore(src, dst));
170+
}
171+
172+
@Override
173+
public MappingStore match(Tree src, Tree dst, MappingStore mappings) {
174+
List<Pair<Tree, Tree>> pairs = LRAify(src, dst, mappings);
175+
for (Pair<Tree, Tree> pair : pairs) {
176+
super.match(pair.first, pair.second, mappings);
177+
}
178+
return mappings;
179+
}
180+
}
181+
static class SafeCrossMoveMatcherThetaF extends CrossMoveMatcherThetaF {
182+
@Override
183+
public MappingStore match(Tree src, Tree dst, MappingStore mappings) {
184+
try {
185+
return super.match(src, dst, mappings);
186+
}
187+
catch (Exception e) {
188+
// Handle the exception gracefully, e.g., log it or ignore it
189+
return mappings;
190+
}
191+
}
192+
}
193+
159194
}
160195

0 commit comments

Comments
 (0)