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.dialect.core.CoreOp;
32 import org.junit.jupiter.api.Assertions;
33 import org.junit.jupiter.api.Test;
34
35 import java.lang.reflect.Method;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.Optional;
39 import java.util.stream.Stream;
40
41 import static java.lang.System.out;
42
43 public class TestAncestors {
44
45 // Model with sufficient nested structure
46 @CodeReflection
47 static void f() {
48 out.println("X");
49 {
50 out.println("X");
51 {
52 out.println("X");
53 }
54 out.println("X");
55 {
56 out.println("X");
57 }
58 out.println("X");
59 }
60 out.println("X");
61 {
62 out.println("X");
63 {
64 out.println("X");
65 }
66 out.println("X");
67 {
68 out.println("X");
69 }
70 out.println("X");
71 }
72 out.println("X");
73 }
74
75 @Test
76 public void test() {
77 CoreOp.FuncOp f = getFuncOp("f");
78 out.println(f.toText());
79
80 List<List<CodeElement<?, ?>>> paths = new ArrayList<>();
81 // path has pattern of [op, body, block, ... ,body, block, op]
82 computedPaths(paths,List.of(), f);
83
84 testPathPrefix(paths.getFirst());
85 paths.forEach(TestAncestors::testPathAncestors);
86 }
87
88 static void testPathPrefix(List<CodeElement<?, ?>> path) {
89 for (int i = 0; i < 3; i++) {
90 CodeElement<?, ?> a = path.get(i);
91 testTopElements(a);
92 }
93 }
94
95 static void testTopElements(CodeElement<?, ?> a) {
96 switch (a) {
97 case Op op -> {
98 Assertions.assertNull(op.ancestorOp());
99 Assertions.assertNull(op.ancestorBody());
100 Assertions.assertNull(op.ancestorBlock());
101 }
102 case Body body -> {
103 Assertions.assertNotNull(body.ancestorOp());
104 Assertions.assertNull(body.ancestorBody());
105 Assertions.assertNull(body.ancestorBlock());
106 }
107 case Block block -> {
108 Assertions.assertNotNull(block.ancestorOp());
109 Assertions.assertNotNull(block.ancestorBody());
110 Assertions.assertNull(block.ancestorBlock());
111 }
112 }
113 }
114
115 static void testPathAncestors(List<CodeElement<?, ?>> path) {
116 Assertions.assertTrue(path.size() > 3);
117 for (int i = 0; i < 3; i++) {
118 CodeElement<?, ?> a = path.get(i);
119 int size = path.size() - 1;
120 for (int j = size; j > size - 3; j--) {
121 if (j < i) {
122 continue;
123 }
124
125 CodeElement<?, ?> e = path.get(j);
126 testAncestors(a, e);
127 }
128 }
129 }
130
131 static void testAncestors(CodeElement<?, ?> a, CodeElement<?, ?> e) {
132 Assertions.assertTrue(isSameOrAncestorUsingParent(e, a));
133 if (a != e) {
134 Assertions.assertTrue(a.isAncestorOf(e));
135 }
136
137 switch (a) {
138 case Op op -> {
139 Assertions.assertTrue(isSameOrAncestorOfOp(op, e));
140 }
141 case Body body -> {
142 Assertions.assertTrue(isSameOrAncestorOfBody(body, e));
143 }
144 case Block block -> {
145 Assertions.assertTrue(isSameOrAncestorOfBlock(block, e));
146 }
147 }
148 }
149
150 static boolean isSameOrAncestorUsingParent(CodeElement<?, ?> e, CodeElement<?, ?> a) {
151 while (e != null && e != a) {
152 e = e.parent();
153 }
154 return e != null;
155 }
156
157 static boolean isSameOrAncestorOfOp(Op a, CodeElement<?, ?> e) {
158 while (e != null && e != a) {
159 e = e.ancestorOp();
160 }
161 return e != null;
162 }
163
164 static boolean isSameOrAncestorOfBody(Body a, CodeElement<?, ?> e) {
165 while (e != null && e != a) {
166 e = e.ancestorBody();
167 }
168 return e != null;
169 }
170
171 static boolean isSameOrAncestorOfBlock(Block a, CodeElement<?, ?> e) {
172 while (e != null && e != a) {
173 e = e.ancestorBlock();
174 }
175 return e != null;
176 }
177
178 static void computedPaths(List<List<CodeElement<?, ?>>> paths, List<CodeElement<?, ?>> path, CodeElement<?, ?> e) {
179 ArrayList<CodeElement<?, ?>> p = new ArrayList<>(path);
180 p.add(e);
181
182 if (e.children().isEmpty()) {
183 paths.add(p);
184 return;
185 }
186
187 for (CodeElement<?, ?> child : e.children()) {
188 computedPaths(paths, p, child);
189 }
190 }
191
192 static CoreOp.FuncOp getFuncOp(String name) {
193 Optional<Method> om = Stream.of(TestAncestors.class.getDeclaredMethods())
194 .filter(m -> m.getName().equals(name))
195 .findFirst();
196
197 Method m = om.get();
198 return Op.ofMethod(m).get();
199 }
200 }