diff --git a/src/main/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTCrossoverLocation.java b/src/main/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTCrossoverLocation.java deleted file mode 100644 index 95d620afa..000000000 --- a/src/main/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTCrossoverLocation.java +++ /dev/null @@ -1,115 +0,0 @@ -package jp.kusumotolab.kgenprog.project.jdt; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; - -/** - * JDT AST の単一ノードを示すオブジェクト 交叉で個体を生成するときの Operation のターゲットに利用する. - */ -public class JDTASTCrossoverLocation extends JDTASTLocation { - - public JDTASTCrossoverLocation(final JDTASTLocation location) { - super(location.getSourcePath(), location.getNode(), location.getGeneratedAST()); - } - - /** - * @param otherASTRoot 探索対象の別 AST のルート - * @return 探索に成功したとき,その AST ノード.探索対象のAST ノードが存在しないとき null. - */ - @Override - public ASTNode locate(final ASTNode otherASTRoot) { - - final List treePaths = makePath(node); - treePaths.remove(0); // remove compilationUnit - - List candidateNodes = new ArrayList<>(); - candidateNodes.add(new TreePathElement(otherASTRoot)); - - for (final TreePathElement path : treePaths) {//これと比べる.これが正解. - final List nextCandidateNodes = new ArrayList<>(); - for (final TreePathElement current : candidateNodes) { - getChildren(current.getNode()).stream() - .filter(path::isSameElementType) - .forEach(nextCandidateNodes::add); - } - candidateNodes = nextCandidateNodes; - } - - candidateNodes.removeIf(e -> !isSameSourceCode(node, e.getNode())); - - //解が複数存在するときは,とりあえず最初のものを返している. - //TODO: 解が複数存在するときの適切な振る舞いを考える. - return candidateNodes.isEmpty() ? null : candidateNodes.get(0) - .getNode(); - } - - private List makePath(final ASTNode dest) { - final List treePaths = new ArrayList<>(); - ASTNode currentNode = dest; - while (currentNode != null) { - treePaths.add(new TreePathElement(currentNode)); - currentNode = currentNode.getParent(); - } - - Collections.reverse(treePaths); - return treePaths; - } - - private List getChildren(final ASTNode node) { - final List children = new ArrayList<>(); - for (final Object o : node.structuralPropertiesForType()) { - final Object childOrChildren = node.getStructuralProperty((StructuralPropertyDescriptor) o); - if (childOrChildren instanceof ASTNode) { - children.add(new TreePathElement((ASTNode) childOrChildren)); - } else if (childOrChildren instanceof List) { - @SuppressWarnings("unchecked") // このとき,List の要素は必ず ASTNode - final List c = (List) childOrChildren; - c.stream() - .map(TreePathElement::new) - .forEach(children::add); - } - } - return children; - } - - - private boolean isSameSourceCode(final ASTNode a, final ASTNode b) { - return a.toString() - .compareTo(b.toString()) == 0; - } - - private static class TreePathElement { - - private final ASTNode node; - private final StructuralPropertyDescriptor descriptor; - - public TreePathElement(final ASTNode node) { - this(node, node.getLocationInParent()); - } - - public TreePathElement(final ASTNode node, final StructuralPropertyDescriptor descriptor) { - this.node = node; - this.descriptor = descriptor; - } - - public boolean isSameElementType(final TreePathElement t) { - return isSameDescriptor(this, t) - && isSameNodeType(this.getNode(), t.getNode()); - } - - private boolean isSameNodeType(final ASTNode a, final ASTNode b) { - return a.getClass() == b.getClass(); - } - - private boolean isSameDescriptor(final TreePathElement a, final TreePathElement b) { - return a.descriptor == b.descriptor; - } - - public ASTNode getNode() { - return node; - } - } -} diff --git a/src/main/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTLocation.java b/src/main/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTLocation.java index a4327eefc..c43e6b804 100644 --- a/src/main/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTLocation.java +++ b/src/main/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTLocation.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; @@ -36,66 +37,73 @@ public JDTASTLocation(final SourcePath sourcePath, final ASTNode node, * 具体的には,このLocationオブジェクトを起点とした親への木構造を取り出し,別ASTから同形部分を探索する. * * @param otherASTRoot 探索対象の別ASTのルート - * @return + * @return 探索に成功したとき,その AST ノード.探索対象のAST ノードが存在しないとき null. */ public ASTNode locate(final ASTNode otherASTRoot) { - final List treePaths = new ArrayList<>(); - ASTNode currentNode = node; - while (true) { - final StructuralPropertyDescriptor locationInParent = currentNode.getLocationInParent(); - if (locationInParent == null) { - break; - } - - final ASTNode parent = currentNode.getParent(); - int idx = TreePathElement.NOT_LIST; + final List treePaths = makePath(node); + treePaths.remove(0); // remove compilationUnit - if (locationInParent.isChildListProperty()) { - // Listの場合、indexも覚えておく - final List children = (List) parent.getStructuralProperty(locationInParent); - idx = children.indexOf(currentNode); - } + final List candidates = locateByNodeDepthAndType(treePaths, otherASTRoot); - treePaths.add(new TreePathElement(locationInParent, idx)); + //解が複数存在するときは,とりあえず最初のものを返している. + //TODO: 解が複数存在するときの適切な振る舞いを考える. + return candidates.isEmpty() ? null : candidates.get(0); + } - currentNode = parent; + private List locateByNodeDepthAndType(final List treePaths, + final ASTNode otherASTRoot) { + List candidateNodes = new ArrayList<>(); + candidateNodes.add(new TreePathElement(otherASTRoot)); + + for (final TreePathElement path : treePaths) {//これと比べる.これが正解. + final List nextCandidateNodes = new ArrayList<>(); + for (final TreePathElement current : candidateNodes) { + getChildren(current.getNode()).stream() + .filter(path::isSameElementType) + .forEach(nextCandidateNodes::add); + } + candidateNodes = nextCandidateNodes; } - Collections.reverse(treePaths); - - currentNode = otherASTRoot; - for (final TreePathElement path : treePaths) { - currentNode = path.moveToChild(currentNode); - } + candidateNodes.removeIf(e -> !isSameSourceCode(node, e.getNode())); - return currentNode; + return candidateNodes.stream() + .map(TreePathElement::getNode) + .collect(Collectors.toList()); } - private static class TreePathElement { - - public static final int NOT_LIST = -1; - - StructuralPropertyDescriptor descriptor; - int idx; - - public TreePathElement(final StructuralPropertyDescriptor descriptor, final int idx) { - this.descriptor = descriptor; - this.idx = idx; + private List makePath(final ASTNode dest) { + final List treePaths = new ArrayList<>(); + ASTNode currentNode = dest; + while (currentNode != null) { + treePaths.add(new TreePathElement(currentNode)); + currentNode = currentNode.getParent(); } - public ASTNode moveToChild(final ASTNode current) { - final Object child = current.getStructuralProperty(descriptor); - if (idx == NOT_LIST) { - return (ASTNode) child; - } else { - return (ASTNode) ((List) child).get(idx); + Collections.reverse(treePaths); + return treePaths; + } + + private List getChildren(final ASTNode node) { + final List children = new ArrayList<>(); + for (final Object o : node.structuralPropertiesForType()) { + final Object childOrChildren = node.getStructuralProperty((StructuralPropertyDescriptor) o); + if (childOrChildren instanceof ASTNode) { + children.add(new TreePathElement((ASTNode) childOrChildren)); + } else if (childOrChildren instanceof List) { + @SuppressWarnings("unchecked") // このとき,List の要素は必ず ASTNode + final List c = (List) childOrChildren; + c.stream() + .map(TreePathElement::new) + .forEach(children::add); } } + return children; } - @Override - public SourcePath getSourcePath() { - return sourcePath; + private static boolean isSameSourceCode(final ASTNode a, final ASTNode b) { + return a.toString() + .compareTo(b.toString()) == 0; } @Override @@ -115,6 +123,11 @@ public LineNumberRange inferLineNumbers() { return new LineNumberRange(start, end); } + @Override + public SourcePath getSourcePath() { + return sourcePath; + } + @Override public GeneratedJDTAST getGeneratedAST() { return generatedAST; @@ -131,7 +144,6 @@ public int hashCode() { @Override public boolean equals(final Object o) { - if (null == o) { return false; } @@ -158,4 +170,36 @@ public boolean isStatement() { public boolean isExpression() { return node instanceof Expression; } + + private static class TreePathElement { + + private final ASTNode node; + StructuralPropertyDescriptor descriptor; + + public TreePathElement(final ASTNode node) { + this(node, node.getLocationInParent()); + } + + public TreePathElement(final ASTNode node, final StructuralPropertyDescriptor descriptor) { + this.node = node; + this.descriptor = descriptor; + } + + private static boolean isSameNodeType(final ASTNode a, final ASTNode b) { + return a.getClass() == b.getClass(); + } + + private static boolean isSameDescriptor(final TreePathElement a, final TreePathElement b) { + return a.descriptor == b.descriptor; + } + + public boolean isSameElementType(final TreePathElement t) { + return isSameDescriptor(this, t) + && isSameNodeType(this.node, t.node); + } + + public ASTNode getNode() { + return node; + } + } } diff --git a/src/test/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTCrossoverLocationTest.java b/src/test/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTCrossoverLocationTest.java deleted file mode 100644 index 036190b90..000000000 --- a/src/test/java/jp/kusumotolab/kgenprog/project/jdt/JDTASTCrossoverLocationTest.java +++ /dev/null @@ -1,300 +0,0 @@ -package jp.kusumotolab.kgenprog.project.jdt; - -import static jp.kusumotolab.kgenprog.project.jdt.ASTNodeAssert.assertThat; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import org.eclipse.jdt.core.dom.ASTNode; -import org.junit.Test; -import jp.kusumotolab.kgenprog.project.ASTLocations; -import jp.kusumotolab.kgenprog.project.ProductSourcePath; - -public class JDTASTCrossoverLocationTest { - - @Test - public void testLocateForTheSameAst01() { - final String source = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 1;" // target - + " i = 2;" - + " }" - + "}"; - final GeneratedJDTAST ast = createAst(source); - - // extract target location - final JDTASTLocation location = getLocation(ast, 1); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try locate() for the same ast root - final ASTNode node = cLocation.locate(ast.getRoot()); - - // of course, target node and located node are the same - assertThat(node).isSameSourceCodeAs("i=1;"); - assertThat(node.getRoot()).isSameRootClassAs(ast.getRoot()); - } - - @Test - public void testLocateForTheSameAst02() { - final String source = "class A {" - + " public void a(int i) {" - + " i = 1;" // target - + " i = 1;" - + " i = 1;" - + " }" - + "}"; - final GeneratedJDTAST ast = createAst(source); - - // extract target location - final JDTASTLocation location = getLocation(ast, 0); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try locate() for the same ast root - final ASTNode node = cLocation.locate(ast.getRoot()); - - // of course, target node and located node are the same instance - assertThat(node).isSameAs(location.getNode()); - assertThat(node.getRoot()).isSameRootClassAs(ast.getRoot()); - } - - @Test - public void testLocateForTheSameAst03() { - final String source = "class A {" - + " public void a(int i) {" - + " i = 1;" - + " i = 1;" // target - + " i = 1;" - + " }" - + "}"; - final GeneratedJDTAST ast = createAst(source); - - // extract target location - final JDTASTLocation location = getLocation(ast, 1); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try locate() for the same ast root - final ASTNode node = cLocation.locate(ast.getRoot()); - - // there are the same nodes as target node, so located node is not target node but first one - assertThat(node).isNotSameAs(location.getNode()); - assertThat(node).isSameAs(getLocation(ast, 0).getNode()); - assertThat(node.getRoot()).isSameRootClassAs(ast.getRoot()); - } - - @Test - public void testLocateForTheSameAst04() { - final String source = "class A {" - + " public void a(int i) {" - + " if (true) {" - + " i = 1;" // target - + " if (true) {" - + " i = 1;" // target - + " } else {" - + " i = 1;" // target - + " }" - + " } else {" - + " i = 1;" // target - + " if (true) {" - + " i = 1;" // target - + " } else {" - + " i = 1;" // target - + " }" - + " }" - + "}"; - final GeneratedJDTAST ast = createAst(source); - - final List ids = Arrays.asList(1, 2, 3, 6, 7, 8); // These nodes have i=1 - - for (int i : ids) { - // extract target location - final JDTASTLocation location = getLocation(ast, i); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try locate() for the same ast root - final ASTNode node = cLocation.locate(ast.getRoot()); - - // located node is the same instance as target node - assertThat(node).isSameAs(location.getNode()); - assertThat(node.getRoot()).isSameRootClassAs(ast.getRoot()); - } - } - - @Test - public void testLocateForSameContentAst() { - final String source = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 1;" // target - + " i = 2;" - + " }" - + "}"; - - // generate two asts (contents are the same but they are different instances) - final GeneratedJDTAST ast1 = createAst(source); - final GeneratedJDTAST ast2 = createAst(source); - - // extract target location - final JDTASTLocation location = getLocation(ast1, 1); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try loc1.locate() - final ASTNode node = cLocation.locate(ast2.getRoot()); - - // located node is the same as target node - assertThat(node).isSameSourceCodeAs("i=1;"); - assertThat(node).isSameRootClassAs(ast2.getRoot()); - } - - @Test - public void testLocateForDifferentAst01() { - final String source1 = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 1;" // target - + " i = 2;" - + " }" - + "}"; - final String source2 = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 2;" - + " i = 1;" // target - + " }" - + "}"; - - // generate two asts - final GeneratedJDTAST ast1 = createAst(source1); - final GeneratedJDTAST ast2 = createAst(source2); - - // extract target location - final JDTASTLocation location = getLocation(ast1, 1); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try loc1.locate() - final ASTNode node = cLocation.locate(ast2.getRoot()); - - // located node is the same as target node - assertThat(node).isSameSourceCodeAs("i=1;"); - assertThat(node).isSameRootClassAs(ast2.getRoot()); - } - - @Test - public void testLocateForDifferentAst02() { - final String source1 = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 1;" // target - + " i = 2;" - + " }" - + "}"; - final String source2 = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 1;" // target - + " if (true) {" - + " i = 2;" - + " }" - + " }" - + "}"; - - // generate two asts - final GeneratedJDTAST ast1 = createAst(source1); - final GeneratedJDTAST ast2 = createAst(source2); - - // extract target location - final JDTASTLocation location = getLocation(ast1, 1); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try loc1.locate() - final ASTNode node = cLocation.locate(ast2.getRoot()); - - // located node is the same as target node - assertThat(node).isSameSourceCodeAs("i=1;"); - assertThat(node).isSameRootClassAs(ast2.getRoot()); - } - - @Test - public void testLocateForDifferentAst03() { - final String source1 = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 1;" // target - + " i = 2;" - + " }" - + "}"; - final String source2 = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " if (true) {" - + " i = 1;" // target - + " }" - + " i = 2;" - + " }" - + "}"; - - // generate two asts - final GeneratedJDTAST ast1 = createAst(source1); - final GeneratedJDTAST ast2 = createAst(source2); - - // extract target location - final JDTASTLocation location = getLocation(ast1, 1); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try loc1.locate() - final ASTNode node = cLocation.locate(ast2.getRoot()); - - // failed to locate - assertThat(node).isNull(); - } - - @Test - public void testLocateForDifferentAst04() { - final String source1 = "class A {" - + " public void a(int i) {" - + " i = 0;" - + " i = 1;" // target - + " i = 2;" - + " }" - + "}"; - final String source2 = "class A {" - + " public void a(int i) {" - + " }" - + "}"; - - // generate two asts - final GeneratedJDTAST ast1 = createAst(source1); - final GeneratedJDTAST ast2 = createAst(source2); - - // extract target location - final JDTASTLocation location = getLocation(ast1, 1); - final JDTASTCrossoverLocation cLocation = new JDTASTCrossoverLocation(location); - assertThat(cLocation.getNode()).isSameSourceCodeAs("i=1;"); - - // try loc1.locate() - final ASTNode node = cLocation.locate(ast2.getRoot()); - - // failed to locate - assertThat(node).isNull(); - } - - private GeneratedJDTAST createAst(final String source) { - final String fname = source.hashCode() + ".java"; // dummy file name - final ProductSourcePath path = new ProductSourcePath(Paths.get("."), Paths.get(fname)); - final JDTASTConstruction constructor = new JDTASTConstruction(); - return constructor.constructAST(path, source); - } - - private JDTASTLocation getLocation(GeneratedJDTAST ast, int idx) { - final ASTLocations locs = ast.createLocations(); - return (JDTASTLocation) locs.getAll() - .get(idx); - } -} diff --git a/src/test/java/jp/kusumotolab/kgenprog/project/jdt/JDTLocationTest.java b/src/test/java/jp/kusumotolab/kgenprog/project/jdt/JDTLocationTest.java index 30fc6230f..30cda3b8a 100644 --- a/src/test/java/jp/kusumotolab/kgenprog/project/jdt/JDTLocationTest.java +++ b/src/test/java/jp/kusumotolab/kgenprog/project/jdt/JDTLocationTest.java @@ -3,12 +3,16 @@ import static org.assertj.core.api.Assertions.assertThat; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Statement; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.junit.Test; import jp.kusumotolab.kgenprog.project.ASTLocation; +import jp.kusumotolab.kgenprog.project.ASTLocations; import jp.kusumotolab.kgenprog.project.GeneratedSourceCode; import jp.kusumotolab.kgenprog.project.LineNumberRange; import jp.kusumotolab.kgenprog.project.ProductSourcePath; @@ -19,6 +23,297 @@ public class JDTLocationTest { + @Test + public void testLocateForTheSameAst01() { + final String source = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 1;" // target + + " i = 2;" + + " }" + + "}"; + final GeneratedJDTAST ast = createAst(source); + + // extract target location + final JDTASTLocation location = getLocation(ast, 1); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try locate() for the same ast root + final ASTNode node = location.locate(ast.getRoot()); + + // of course, target node and located node are the same + ASTNodeAssert.assertThat(node) + .isSameSourceCodeAs("i=1;"); + ASTNodeAssert.assertThat(node.getRoot()) + .isSameRootClassAs(ast.getRoot()); + } + + @Test + public void testLocateForTheSameAst02() { + final String source = "class A {" + + " public void a(int i) {" + + " i = 1;" // target + + " i = 1;" + + " i = 1;" + + " }" + + "}"; + final GeneratedJDTAST ast = createAst(source); + + // extract target location + final JDTASTLocation location = getLocation(ast, 0); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try locate() for the same ast root + final ASTNode node = location.locate(ast.getRoot()); + + // of course, target node and located node are the same instance + ASTNodeAssert.assertThat(node) + .isSameAs(location.getNode()); + ASTNodeAssert.assertThat(node.getRoot()) + .isSameRootClassAs(ast.getRoot()); + } + + @Test + public void testLocateForTheSameAst03() { + final String source = "class A {" + + " public void a(int i) {" + + " i = 1;" + + " i = 1;" // target + + " i = 1;" + + " }" + + "}"; + final GeneratedJDTAST ast = createAst(source); + + // extract target location + final JDTASTLocation location = getLocation(ast, 1); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try locate() for the same ast root + final ASTNode node = location.locate(ast.getRoot()); + + // there are the same nodes as target node, so located node is not target node but first one + ASTNodeAssert.assertThat(node) + .isNotSameAs(location.getNode()); + ASTNodeAssert.assertThat(node) + .isSameAs(getLocation(ast, 0).getNode()); + ASTNodeAssert.assertThat(node.getRoot()) + .isSameRootClassAs(ast.getRoot()); + } + + @Test + public void testLocateForTheSameAst04() { + final String source = "class A {" + + " public void a(int i) {" + + " if (true) {" + + " i = 1;" // target + + " if (true) {" + + " i = 1;" // target + + " } else {" + + " i = 1;" // target + + " }" + + " } else {" + + " i = 1;" // target + + " if (true) {" + + " i = 1;" // target + + " } else {" + + " i = 1;" // target + + " }" + + " }" + + "}"; + final GeneratedJDTAST ast = createAst(source); + + final List ids = Arrays.asList(1, 2, 3, 6, 7, 8); // These nodes have i=1 + + for (int i : ids) { + // extract target location + final JDTASTLocation location = getLocation(ast, i); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try locate() for the same ast root + final ASTNode node = location.locate(ast.getRoot()); + + // located node is the same instance as target node + ASTNodeAssert.assertThat(node) + .isSameAs(location.getNode()); + ASTNodeAssert.assertThat(node.getRoot()) + .isSameRootClassAs(ast.getRoot()); + } + } + + @Test + public void testLocateForSameContentAst() { + final String source = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 1;" // target + + " i = 2;" + + " }" + + "}"; + + // generate two asts (contents are the same but they are different instances) + final GeneratedJDTAST ast1 = createAst(source); + final GeneratedJDTAST ast2 = createAst(source); + + // extract target location + final JDTASTLocation location = getLocation(ast1, 1); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try loc1.locate() + final ASTNode node = location.locate(ast2.getRoot()); + + // located node is the same as target node + ASTNodeAssert.assertThat(node) + .isSameSourceCodeAs("i=1;"); + ASTNodeAssert.assertThat(node) + .isSameRootClassAs(ast2.getRoot()); + } + + @Test + public void testLocateForDifferentAst01() { + final String source1 = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 1;" // target + + " i = 2;" + + " }" + + "}"; + final String source2 = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 2;" + + " i = 1;" // target + + " }" + + "}"; + + // generate two asts + final GeneratedJDTAST ast1 = createAst(source1); + final GeneratedJDTAST ast2 = createAst(source2); + + // extract target location + final JDTASTLocation location = getLocation(ast1, 1); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try loc1.locate() + final ASTNode node = location.locate(ast2.getRoot()); + + // located node is the same as target node + ASTNodeAssert.assertThat(node) + .isSameSourceCodeAs("i=1;"); + ASTNodeAssert.assertThat(node) + .isSameRootClassAs(ast2.getRoot()); + } + + @Test + public void testLocateForDifferentAst02() { + final String source1 = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 1;" // target + + " i = 2;" + + " }" + + "}"; + final String source2 = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 1;" // target + + " if (true) {" + + " i = 2;" + + " }" + + " }" + + "}"; + + // generate two asts + final GeneratedJDTAST ast1 = createAst(source1); + final GeneratedJDTAST ast2 = createAst(source2); + + // extract target location + final JDTASTLocation location = getLocation(ast1, 1); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try loc1.locate() + final ASTNode node = location.locate(ast2.getRoot()); + + // located node is the same as target node + ASTNodeAssert.assertThat(node) + .isSameSourceCodeAs("i=1;"); + ASTNodeAssert.assertThat(node) + .isSameRootClassAs(ast2.getRoot()); + } + + @Test + public void testLocateForDifferentAst03() { + final String source1 = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 1;" // target + + " i = 2;" + + " }" + + "}"; + final String source2 = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " if (true) {" + + " i = 1;" // target + + " }" + + " i = 2;" + + " }" + + "}"; + + // generate two asts + final GeneratedJDTAST ast1 = createAst(source1); + final GeneratedJDTAST ast2 = createAst(source2); + + // extract target location + final JDTASTLocation location = getLocation(ast1, 1); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try loc1.locate() + final ASTNode node = location.locate(ast2.getRoot()); + + // failed to locate + ASTNodeAssert.assertThat(node) + .isNull(); + } + + @Test + public void testLocateForDifferentAst04() { + final String source1 = "class A {" + + " public void a(int i) {" + + " i = 0;" + + " i = 1;" // target + + " i = 2;" + + " }" + + "}"; + final String source2 = "class A {" + + " public void a(int i) {" + + " }" + + "}"; + + // generate two asts + final GeneratedJDTAST ast1 = createAst(source1); + final GeneratedJDTAST ast2 = createAst(source2); + + // extract target location + final JDTASTLocation location = getLocation(ast1, 1); + ASTNodeAssert.assertThat(location.getNode()) + .isSameSourceCodeAs("i=1;"); + + // try loc1.locate() + final ASTNode node = location.locate(ast2.getRoot()); + + // failed to locate + ASTNodeAssert.assertThat(node) + .isNull(); + } + @Test public void testInferLineNumbers() { final Path rootPath = Paths.get("example/BuildSuccess01"); @@ -50,4 +345,17 @@ public void testInferLineNumbers() { assertThat(location2.inferLineNumbers()).isEqualTo(new LineNumberRange(10, 10)); } + private GeneratedJDTAST createAst(final String source) { + final String fname = source.hashCode() + ".java"; // dummy file name + final ProductSourcePath path = new ProductSourcePath(Paths.get("."), Paths.get(fname)); + final JDTASTConstruction constructor = new JDTASTConstruction(); + return constructor.constructAST(path, source); + } + + private JDTASTLocation getLocation(GeneratedJDTAST ast, int idx) { + final ASTLocations locs = ast.createLocations(); + return (JDTASTLocation) locs.getAll() + .get(idx); + } + }