From a1bf88c09b09a5c9a788f7e86fbe44bb6837f1c0 Mon Sep 17 00:00:00 2001 From: Ivan Kniazkov Date: Wed, 26 Jun 2024 18:50:12 +0300 Subject: [PATCH] 'Pattern' class --- .../core/algorithms/PatternBuilder.java | 7 +-- .../org/cqfn/astranaut/core/base/Pattern.java | 53 +++++++++++++++++++ .../cqfn/astranaut/core/base/PatternNode.java | 2 +- .../core/algorithms/PatternBuilderTest.java | 12 ++--- .../core/algorithms/patching/PatcherTest.java | 16 ++---- .../patching/PatternMatcherTest.java | 10 ++-- 6 files changed, 70 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/cqfn/astranaut/core/base/Pattern.java diff --git a/src/main/java/org/cqfn/astranaut/core/algorithms/PatternBuilder.java b/src/main/java/org/cqfn/astranaut/core/algorithms/PatternBuilder.java index 78caeff..252fa66 100644 --- a/src/main/java/org/cqfn/astranaut/core/algorithms/PatternBuilder.java +++ b/src/main/java/org/cqfn/astranaut/core/algorithms/PatternBuilder.java @@ -27,6 +27,7 @@ import java.util.Map; import org.cqfn.astranaut.core.base.DiffNode; import org.cqfn.astranaut.core.base.Node; +import org.cqfn.astranaut.core.base.Pattern; import org.cqfn.astranaut.core.base.PatternNode; /** @@ -65,8 +66,8 @@ public PatternBuilder(final DiffNode diff) { * Returns root of resulting pattern. * @return Root node of pattern */ - public PatternNode getRoot() { - return this.root; + public Pattern getPattern() { + return new Pattern(this.root); } /** @@ -118,7 +119,7 @@ private static void buildNodeInfoMap(final Map map, final Patter * Some additional information about each node needed to make holes. * So far there's only a parent node here, but we may need something else. * - * @since 1.1.0 + * @since 1.1.5 */ private static final class NodeInfo { /** diff --git a/src/main/java/org/cqfn/astranaut/core/base/Pattern.java b/src/main/java/org/cqfn/astranaut/core/base/Pattern.java new file mode 100644 index 0000000..42605a3 --- /dev/null +++ b/src/main/java/org/cqfn/astranaut/core/base/Pattern.java @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ivan Kniazkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cqfn.astranaut.core.base; + +/** + * Represents a pattern which is a syntax tree containing actions, similar to a difference tree, + * but with some nodes that can be replaced by "holes". + * A pattern is a somewhat generalized difference tree. The presence of holes allows the + * pattern's tree to be overlaid on subtrees of another syntax tree (a process called matching) + * and then replace (add, delete) nodes in the processed syntax tree according to the actions + * specified in the pattern (a process called patching or applying the pattern). + * Using the pattern mechanism enables transferring changes made in one syntax tree + * (i.e., the source code from which this syntax tree was derived) to another, unrelated + * syntax tree. One possible application of such a mechanism is the detection and automatic + * correction of errors in source code. + * + * @since 2.0.0 + */ +public final class Pattern extends Tree { + /** + * Constructor. + * @param root Root node the difference tree + */ + public Pattern(final PatternNode root) { + super(root); + } + + @Override + public PatternNode getRoot() { + return (PatternNode) super.getRoot(); + } +} diff --git a/src/main/java/org/cqfn/astranaut/core/base/PatternNode.java b/src/main/java/org/cqfn/astranaut/core/base/PatternNode.java index 41a1bb1..17d439d 100644 --- a/src/main/java/org/cqfn/astranaut/core/base/PatternNode.java +++ b/src/main/java/org/cqfn/astranaut/core/base/PatternNode.java @@ -34,7 +34,7 @@ */ public final class PatternNode implements PatternItem { /** - * The prototype node, i.e. 'ordinary', non-difference original node. + * The prototype node, i.e. 'ordinary', non-pattern original node. */ private final Node prototype; diff --git a/src/test/java/org/cqfn/astranaut/core/algorithms/PatternBuilderTest.java b/src/test/java/org/cqfn/astranaut/core/algorithms/PatternBuilderTest.java index cdd7a7a..a13d499 100644 --- a/src/test/java/org/cqfn/astranaut/core/algorithms/PatternBuilderTest.java +++ b/src/test/java/org/cqfn/astranaut/core/algorithms/PatternBuilderTest.java @@ -26,12 +26,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.Optional; -import org.cqfn.astranaut.core.base.Builder; -import org.cqfn.astranaut.core.base.DiffNode; -import org.cqfn.astranaut.core.base.DraftNode; -import org.cqfn.astranaut.core.base.Hole; -import org.cqfn.astranaut.core.base.Node; -import org.cqfn.astranaut.core.base.PatternNode; + +import org.cqfn.astranaut.core.base.*; import org.cqfn.astranaut.core.example.green.Addition; import org.cqfn.astranaut.core.example.green.ExpressionStatement; import org.cqfn.astranaut.core.example.green.IntegerLiteral; @@ -68,9 +64,9 @@ void creatingPatternWithHole() { final Node stmt = ctor.createNode(); final PatternBuilder builder = new PatternBuilder(new DiffNode(stmt)); builder.makeHole(first, 1); - final PatternNode pattern = builder.getRoot(); + final Pattern pattern = builder.getPattern(); Assertions.assertNotNull(pattern); - final DeepTraversal traversal = new DeepTraversal(pattern); + final DeepTraversal traversal = new DeepTraversal(pattern.getRoot()); final Optional hole = traversal.findFirst(node -> node instanceof Hole); Assertions.assertTrue(hole.isPresent()); Assertions.assertEquals("#1", hole.get().getData()); diff --git a/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatcherTest.java b/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatcherTest.java index 1c1fd08..11dd674 100644 --- a/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatcherTest.java +++ b/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatcherTest.java @@ -30,13 +30,7 @@ import java.util.TreeMap; import org.cqfn.astranaut.core.algorithms.DiffTreeBuilder; import org.cqfn.astranaut.core.algorithms.PatternBuilder; -import org.cqfn.astranaut.core.base.Builder; -import org.cqfn.astranaut.core.base.DiffNode; -import org.cqfn.astranaut.core.base.DraftNode; -import org.cqfn.astranaut.core.base.Insertion; -import org.cqfn.astranaut.core.base.Node; -import org.cqfn.astranaut.core.base.PatternNode; -import org.cqfn.astranaut.core.base.Tree; +import org.cqfn.astranaut.core.base.*; import org.cqfn.astranaut.core.example.green.Addition; import org.cqfn.astranaut.core.example.green.ExpressionStatement; import org.cqfn.astranaut.core.example.green.IntegerLiteral; @@ -133,8 +127,8 @@ void patchPatternWithHole() { ctor.setChildrenList(Collections.singletonList(assignment)); final Node stmt = ctor.createNode(); final Patcher patcher = new DefaultPatcher(); - final PatternNode pattern = PatcherTest.createPatternWithHole(); - final Tree patched = patcher.patch(new Tree(stmt), pattern); + final Pattern pattern = PatcherTest.createPatternWithHole(); + final Tree patched = patcher.patch(new Tree(stmt), pattern.getRoot()); ctor = new Variable.Constructor(); ctor.setData("a"); first = ctor.createNode(); @@ -173,7 +167,7 @@ void patchWithPatternThatDoesNotMatch() { * Creates pattern with a hole. * @return A pattern */ - private static PatternNode createPatternWithHole() { + private static Pattern createPatternWithHole() { Builder ctor = new Variable.Constructor(); ctor.setData("w"); final Node first = ctor.createNode(); @@ -190,7 +184,7 @@ private static PatternNode createPatternWithHole() { dtbld.replaceNode(second, replacement); final PatternBuilder pbld = new PatternBuilder(dtbld.getDiffTree().getRoot()); pbld.makeHole(first, 0); - final PatternNode pattern = pbld.getRoot(); + final Pattern pattern = pbld.getPattern(); Assertions.assertNotNull(pattern); return pattern; } diff --git a/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatternMatcherTest.java b/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatternMatcherTest.java index 590e28c..826f53d 100644 --- a/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatternMatcherTest.java +++ b/src/test/java/org/cqfn/astranaut/core/algorithms/patching/PatternMatcherTest.java @@ -28,11 +28,7 @@ import java.util.TreeMap; import org.cqfn.astranaut.core.algorithms.DiffTreeBuilder; import org.cqfn.astranaut.core.algorithms.PatternBuilder; -import org.cqfn.astranaut.core.base.DiffNode; -import org.cqfn.astranaut.core.base.DraftNode; -import org.cqfn.astranaut.core.base.Insertion; -import org.cqfn.astranaut.core.base.Node; -import org.cqfn.astranaut.core.base.PatternNode; +import org.cqfn.astranaut.core.base.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -130,10 +126,10 @@ void findPatternWithHoleInATree() { final PatternBuilder pbuilder = new PatternBuilder(dtbuilder.getDiffTree().getRoot()); final boolean flag = pbuilder.makeHole(nodes.get("D").iterator().next(), 0); Assertions.assertTrue(flag); - final PatternNode pattern = pbuilder.getRoot(); + final Pattern pattern = pbuilder.getPattern(); final Node tree = DraftNode.create("X(Y,A(B,D<\"11\">),Z)"); final PatternMatcher matcher = new PatternMatcher(tree); - final Set found = matcher.match(pattern); + final Set found = matcher.match(pattern.getRoot()); Assertions.assertEquals(1, found.size()); final Node node = found.iterator().next(); Assertions.assertEquals("A", node.getTypeName());