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 testng TestAncestors
 28  */
 29 
 30 import jdk.incubator.code.*;
 31 import jdk.incubator.code.dialect.core.CoreOp;
 32 import org.testng.Assert;
 33 import org.testng.annotations.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                 Assert.assertNull(op.ancestorOp());
 99                 Assert.assertNull(op.ancestorBody());
100                 Assert.assertNull(op.ancestorBlock());
101             }
102             case Body body -> {
103                 Assert.assertNotNull(body.ancestorOp());
104                 Assert.assertNull(body.ancestorBody());
105                 Assert.assertNull(body.ancestorBlock());
106             }
107             case Block block -> {
108                 Assert.assertNotNull(block.ancestorOp());
109                 Assert.assertNotNull(block.ancestorBody());
110                 Assert.assertNull(block.ancestorBlock());
111             }
112         }
113     }
114 
115     static void testPathAncestors(List<CodeElement<?, ?>> path) {
116         Assert.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         Assert.assertTrue(isSameOrAncestorUsingParent(e, a));
133         if (a != e) {
134             Assert.assertTrue(a.isAncestorOf(e));
135         }
136 
137         switch (a) {
138             case Op op -> {
139                 Assert.assertTrue(isSameOrAncestorOfOp(op, e));
140             }
141             case Body body -> {
142                 Assert.assertTrue(isSameOrAncestorOfBody(body, e));
143             }
144             case Block block -> {
145                 Assert.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 }