1 /*
2 * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @modules jdk.incubator.code
27 * @run junit TestAncestors
28 */
29
30 import jdk.incubator.code.*;
31 import jdk.incubator.code.Reflect;
32 import jdk.incubator.code.dialect.core.CoreOp;
33 import org.junit.jupiter.api.Assertions;
34 import org.junit.jupiter.api.Test;
35
36 import java.lang.reflect.Method;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Optional;
40 import java.util.stream.Stream;
41
42 import static java.lang.System.out;
43
44 public class TestAncestors {
45
46 // Model with sufficient nested structure
47 @Reflect
48 static void f() {
49 out.println("X");
50 {
51 out.println("X");
52 {
53 out.println("X");
54 }
55 out.println("X");
56 {
57 out.println("X");
58 }
59 out.println("X");
60 }
61 out.println("X");
62 {
63 out.println("X");
64 {
65 out.println("X");
66 }
67 out.println("X");
68 {
69 out.println("X");
70 }
71 out.println("X");
72 }
73 out.println("X");
74 }
75
76 @Test
77 public void test() {
78 CoreOp.FuncOp f = getFuncOp("f");
79 out.println(f.toText());
80
81 List<List<CodeElement<?, ?>>> paths = new ArrayList<>();
82 // path has pattern of [op, body, block, ... ,body, block, op]
83 computedPaths(paths,List.of(), f);
84
85 testPathPrefix(paths.getFirst());
86 paths.forEach(TestAncestors::testPathAncestors);
87 }
88
89 static void testPathPrefix(List<CodeElement<?, ?>> path) {
90 for (int i = 0; i < 3; i++) {
91 CodeElement<?, ?> a = path.get(i);
92 testTopElements(a);
93 }
94 }
95
96 static void testTopElements(CodeElement<?, ?> a) {
97 switch (a) {
98 case Op op -> {
99 Assertions.assertNull(op.ancestorOp());
100 Assertions.assertNull(op.ancestorBody());
101 Assertions.assertNull(op.ancestorBlock());
102 }
103 case Body body -> {
104 Assertions.assertNotNull(body.ancestorOp());
105 Assertions.assertNull(body.ancestorBody());
106 Assertions.assertNull(body.ancestorBlock());
107 }
108 case Block block -> {
109 Assertions.assertNotNull(block.ancestorOp());
110 Assertions.assertNotNull(block.ancestorBody());
111 Assertions.assertNull(block.ancestorBlock());
112 }
113 }
114 }
115
116 static void testPathAncestors(List<CodeElement<?, ?>> path) {
117 Assertions.assertTrue(path.size() > 3);
118 for (int i = 0; i < 3; i++) {
119 CodeElement<?, ?> a = path.get(i);
120 int size = path.size() - 1;
121 for (int j = size; j > size - 3; j--) {
122 if (j < i) {
123 continue;
124 }
125
126 CodeElement<?, ?> e = path.get(j);
127 testAncestors(a, e);
128 }
129 }
130 }
131
132 static void testAncestors(CodeElement<?, ?> a, CodeElement<?, ?> e) {
133 Assertions.assertTrue(isSameOrAncestorUsingParent(e, a));
134 if (a != e) {
135 Assertions.assertTrue(a.isAncestorOf(e));
136 }
137
138 switch (a) {
139 case Op op -> {
140 Assertions.assertTrue(isSameOrAncestorOfOp(op, e));
141 }
142 case Body body -> {
143 Assertions.assertTrue(isSameOrAncestorOfBody(body, e));
144 }
145 case Block block -> {
146 Assertions.assertTrue(isSameOrAncestorOfBlock(block, e));
147 }
148 }
149 }
150
151 static boolean isSameOrAncestorUsingParent(CodeElement<?, ?> e, CodeElement<?, ?> a) {
152 while (e != null && e != a) {
153 e = e.parent();
154 }
155 return e != null;
156 }
157
158 static boolean isSameOrAncestorOfOp(Op a, CodeElement<?, ?> e) {
159 while (e != null && e != a) {
160 e = e.ancestorOp();
161 }
162 return e != null;
163 }
164
165 static boolean isSameOrAncestorOfBody(Body a, CodeElement<?, ?> e) {
166 while (e != null && e != a) {
167 e = e.ancestorBody();
168 }
169 return e != null;
170 }
171
172 static boolean isSameOrAncestorOfBlock(Block a, CodeElement<?, ?> e) {
173 while (e != null && e != a) {
174 e = e.ancestorBlock();
175 }
176 return e != null;
177 }
178
179 static void computedPaths(List<List<CodeElement<?, ?>>> paths, List<CodeElement<?, ?>> path, CodeElement<?, ?> e) {
180 ArrayList<CodeElement<?, ?>> p = new ArrayList<>(path);
181 p.add(e);
182
183 if (e.children().isEmpty()) {
184 paths.add(p);
185 return;
186 }
187
188 for (CodeElement<?, ?> child : e.children()) {
189 computedPaths(paths, p, child);
190 }
191 }
192
193 static CoreOp.FuncOp getFuncOp(String name) {
194 Optional<Method> om = Stream.of(TestAncestors.class.getDeclaredMethods())
195 .filter(m -> m.getName().equals(name))
196 .findFirst();
197
198 Method m = om.get();
199 return Op.ofMethod(m).get();
200 }
201 }