1 /* 2 * Copyright (c) 2020, 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 * @build JextractApiTestBase 27 * @run testng/othervm -ea --enable-native-access=jdk.incubator.jextract TestTypedef 28 */ 29 30 import java.util.Set; 31 import java.util.Optional; 32 import java.util.function.Consumer; 33 import jdk.incubator.jextract.Declaration; 34 import jdk.incubator.jextract.Type; 35 36 import org.testng.annotations.BeforeClass; 37 import org.testng.annotations.Test; 38 39 import static org.testng.Assert.assertEquals; 40 import static org.testng.Assert.assertNotEquals; 41 import static org.testng.Assert.assertTrue; 42 import static org.testng.Assert.fail; 43 44 public class TestTypedef extends JextractApiTestBase { 45 Declaration.Scoped root; 46 47 @BeforeClass 48 public void parse() { 49 root = parse("testTypedef.h"); 50 System.out.println(root); 51 } 52 53 private Declaration[] findAllWithName(Declaration.Scoped scope, String name) { 54 return scope.members().stream().filter(byName(name)).toArray(Declaration[]::new); 55 } 56 57 public static Type getTypedefType(Declaration.Scoped scope, String name) { 58 Declaration.Typedef d = findDecl(scope, name, Declaration.Typedef.class); 59 Type type = d.type(); 60 // Typedef declaration should return canonical type 61 if (type instanceof Type.Delegated) { 62 assertNotEquals(((Type.Delegated) type).kind(), Type.Delegated.Kind.TYPEDEF); 63 } 64 return d.type(); 65 } 66 67 private Declaration.Scoped assertDeclaredTypedef(Declaration.Typedef decl) { 68 Type type = decl.type(); 69 assertTrue(type instanceof Type.Declared, "Expecting Type.Declared, got " + type.getClass()); 70 return ((Type.Declared) type).tree(); 71 } 72 73 private Declaration.Scoped assertAnonymousRecord(Declaration.Scoped scope, String name) { 74 Declaration[] ar = findAllWithName(scope, name); 75 assertEquals(ar.length, 1); 76 assertTrue(ar[0] instanceof Declaration.Typedef, "Expectint Declaration.Typedef, but got " + ar[0].getClass()); 77 Declaration.Scoped record = assertDeclaredTypedef((Declaration.Typedef) ar[0]); 78 return record; 79 } 80 81 private Declaration.Scoped assertNamedRecord(Declaration.Scoped scope, String name) { 82 Declaration[] ar = findAllWithName(scope, name); 83 assertEquals(ar.length, 1); 84 assertTrue(ar[0] instanceof Declaration.Scoped, "Expectint Declaration.Scoped, but got " + ar[0].getClass()); 85 return (Declaration.Scoped) ar[0]; 86 } 87 88 @Test 89 public void NoDuplicateSameNameTypedef() { 90 // When typedef a named record with the same name, present the scoped 91 // declaration and ignore the typedef 92 Declaration.Scoped s = assertNamedRecord(root, "Point3D"); 93 assertEquals(s.kind(), Declaration.Scoped.Kind.STRUCT); 94 checkNames(s.members(), "i", "j", "k"); 95 96 s = assertNamedRecord(root, "SIZE"); 97 assertEquals(s.kind(), Declaration.Scoped.Kind.ENUM); 98 checkNames(s.members(), "XS", "S", "M", "L", "XL"); 99 } 100 101 @Test 102 public void TypedefReferences() { 103 // When reference to a typedef, the Type should be Type.Delegated 104 // With the type to be the referenced type 105 Declaration.Scoped pt3d = checkStruct(root, "Point3D", "i", "j", "k"); 106 Declaration.Function drawParamid = findDecl(root, "drawParamid", Declaration.Function.class); 107 Type.Function fnType = drawParamid.type(); 108 // Array in function argument is lowered to pointer 109 Type type = TypeUnwrapper.of(fnType.argumentTypes().get(0)) 110 .unwrapPointer().unwrapTypedef().get(); 111 assertEquals(type, Type.declared(pt3d)); 112 113 Declaration.Function do_ops = findDecl(root, "do_ops", Declaration.Function.class); 114 fnType = do_ops.type(); 115 type = unwrapTypedefType(fnType.returnType()); 116 assertEquals(type, getTypedefType(root, "op_sequence")); 117 type = fnType.argumentTypes().get(0); 118 type = unwrapTypedefType(type); 119 assertEquals(type, getTypedefType(root, "int_op")); 120 type = fnType.argumentTypes().get(1); 121 type = unwrapTypedefType(type); 122 assertEquals(type, getTypedefType(root, "count_t")); 123 } 124 125 @Test 126 public void TypedefsToSameType() { 127 // For typedef declaration, the type will be the canonical type 128 // Which means, the type will not be another typedef 129 // However, it can be other delegated type or an array 130 Declaration.Scoped pt = checkStruct(root, "Point", "i", "j"); 131 Type.Declared type = Type.declared(pt); 132 assertEquals(getTypedefType(root, "POINT"), type); 133 assertEquals(getTypedefType(root, "point_t"), type); 134 135 Type canonical = TypeUnwrapper.of(getTypedefType(root, "rectangle")) 136 .unwrapArray(4) 137 // FIXME? If we would like to generate array using typedef type 138 // then we need to use typedef as array element type and 139 // requires following line to pass the test. 140 // .unwrapTypedef() 141 .get(); 142 assertEquals(canonical, type); 143 144 Declaration.Variable canvas = findDecl(root, "canvas", Declaration.Variable.class); 145 assertEquals(canvas.kind(), Declaration.Variable.Kind.GLOBAL); 146 Type ref = TypeUnwrapper.of(canvas.type()) 147 .unwrapTypedef() 148 .unwrapArray(4) 149 .get(); 150 assertEquals(ref, type); 151 152 getTypedefType(root, "count_t"); 153 } 154 155 @Test 156 public void TypedefsArrays() { 157 Type intType = getTypedefType(root, "cordinate_t"); 158 159 // As noted earlier, we currently have canonical array element type from typedef 160 Type type = getTypedefType(root, "location2D"); 161 Type elementType = unwrapArrayType(type, 2); 162 assertEquals(elementType, intType); 163 164 Type count_t = getTypedefType(root, "count_t"); 165 type = getTypedefType(root, "dimensions"); 166 elementType = unwrapArrayType(type); 167 assertEquals(elementType, count_t); 168 type = getTypedefType(root, "count_ptr"); 169 assertEquals(type, Type.pointer(count_t)); 170 } 171 172 @Test 173 public void AnonymousRecordTypedef() { 174 // For anonymous typedef, present the typedef declaration and 175 // the Scope declaration can be obtained via Variable.type() 176 Declaration.Scoped record = assertAnonymousRecord(root, "op_sequence"); 177 assertEquals(record.kind(), Declaration.Scoped.Kind.STRUCT); 178 checkNames(record.members(), "times", "op"); 179 180 record = assertAnonymousRecord(root, "IntOrFloat"); 181 assertEquals(record.kind(), Declaration.Scoped.Kind.UNION); 182 checkNames(record.members(), "i", "f"); 183 184 record = assertAnonymousRecord(root, "codetype_t"); 185 assertEquals(record.kind(), Declaration.Scoped.Kind.ENUM); 186 checkNames(record.members(), "Java", "C", "CPP", "Python", "Ruby"); 187 } 188 189 @Test 190 public void CheckAnonyousDeclarations() { 191 // Should we expunge anonymous declaration? 192 // They only needed if referenced as a field or gloabal variable 193 // Exception enum, as they can be used as pleased, so we need to 194 // elevate them into constants. 195 // Anyhow, current implementation pass through enum, not elevate them. 196 // So we just check that 197 Declaration[] ar = findAllWithName(root, ""); 198 assertEquals(ar.length, 2); 199 Declaration.Scoped e = (Declaration.Scoped) ar[0]; 200 assertEquals(e.kind(), Declaration.Scoped.Kind.ENUM); 201 checkNames(e.members(), "RED", "GREEN", "BLUE"); 202 e = (Declaration.Scoped) ar[1]; 203 assertEquals(e.kind(), Declaration.Scoped.Kind.ENUM); 204 checkNames(e.members(), "Java", "C", "CPP", "Python", "Ruby"); 205 } 206 207 @Test 208 public void CheckFunctionPointers() { 209 Type intType = getTypedefType(root, "cordinate_t"); 210 Type intOpType = getTypedefType(root, "int_op"); 211 assertEquals(intOpType, Type.pointer(Type.function(false, intType, intType))); 212 Type intOp2Type = getTypedefType(root, "int_op2"); 213 assertEquals(intOp2Type, Type.pointer(Type.function(false, intType, intType, intType))); 214 215 checkGlobal(root, "another_int_op", intOpType); 216 217 Declaration.Function getFn = findDecl(root, "getFn", Declaration.Function.class); 218 assertEquals(getFn.parameters().size(), 0); 219 Type.Delegated retType = (Type.Delegated) getFn.type().returnType(); 220 assertTrue(retType.kind() == Type.Delegated.Kind.POINTER); 221 Type.Function fnType = (Type.Function) retType.type(); 222 assertEquals(fnType.returnType(), Type.void_()); 223 assertEquals(fnType.argumentTypes().get(1), 224 Type.typedef("count_t", getTypedefType(root, "count_t"))); 225 } 226 }