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 }