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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 * 25 */ 26 27 package jdk.internal.clang; 28 29 import jdk.incubator.foreign.MemorySegment; 30 import jdk.incubator.foreign.ResourceScope; 31 import jdk.incubator.foreign.SegmentAllocator; 32 import jdk.internal.clang.libclang.CXType; 33 import jdk.internal.clang.libclang.Index_h; 34 35 import static jdk.internal.clang.LibClang.IMPLICIT_ALLOCATOR; 36 37 public final class Type { 38 private final MemorySegment type; 39 Type(MemorySegment type) { 40 this.type = type; 41 } 42 43 public boolean isInvalid() { 44 return kind() == TypeKind.Invalid; 45 } 46 47 // Function Types 48 public boolean isVariadic() { 49 return Index_h.clang_isFunctionTypeVariadic(type) != 0; 50 } 51 public Type resultType() { 52 return new Type(Index_h.clang_getResultType(IMPLICIT_ALLOCATOR, type)); 53 } 54 public int numberOfArgs() { 55 return Index_h.clang_getNumArgTypes(type); 56 } 57 public Type argType(int idx) { 58 return new Type(Index_h.clang_getArgType(IMPLICIT_ALLOCATOR, type, idx)); 59 } 60 private int getCallingConvention0() { 61 return Index_h.clang_getFunctionTypeCallingConv(type); 62 } 63 64 public CallingConvention getCallingConvention() { 65 int v = getCallingConvention0(); 66 return CallingConvention.valueOf(v); 67 } 68 69 public boolean isPointer() { 70 var kind = kind(); 71 return kind == TypeKind.Pointer || 72 kind == TypeKind.BlockPointer || kind == TypeKind.MemberPointer; 73 } 74 75 public boolean isReference() { 76 var kind = kind(); 77 return kind == TypeKind.LValueReference || kind == TypeKind.RValueReference; 78 } 79 80 public boolean isArray() { 81 var kind = kind(); 82 return kind == TypeKind.ConstantArray || 83 kind == TypeKind.IncompleteArray || 84 kind == TypeKind.VariableArray || 85 kind == TypeKind.DependentSizedArray; 86 } 87 88 // Pointer type 89 public Type getPointeeType() { 90 return new Type(Index_h.clang_getPointeeType(IMPLICIT_ALLOCATOR, type)); 91 } 92 93 // array/vector type 94 public Type getElementType() { 95 return new Type(Index_h.clang_getElementType(IMPLICIT_ALLOCATOR, type)); 96 } 97 98 public long getNumberOfElements() { 99 return Index_h.clang_getNumElements(type); 100 } 101 102 // Struct/RecordType 103 private long getOffsetOf0(String fieldName) { 104 try (ResourceScope scope = ResourceScope.newConfinedScope()) { 105 var allocator = SegmentAllocator.nativeAllocator(scope); 106 MemorySegment cfname = allocator.allocateUtf8String(fieldName); 107 return Index_h.clang_Type_getOffsetOf(type, cfname); 108 } 109 } 110 111 public long getOffsetOf(String fieldName) { 112 long res = getOffsetOf0(fieldName); 113 if(TypeLayoutError.isError(res)) { 114 throw new TypeLayoutError(res, String.format("type: %s, fieldName: %s", this, fieldName)); 115 } 116 return res; 117 } 118 119 // Typedef 120 /** 121 * Return the canonical type for a Type. 122 * 123 * Clang's type system explicitly models typedefs and all the ways 124 * a specific type can be represented. The canonical type is the underlying 125 * type with all the "sugar" removed. For example, if 'T' is a typedef 126 * for 'int', the canonical type for 'T' would be 'int'. 127 */ 128 public Type canonicalType() { 129 return new Type(Index_h.clang_getCanonicalType(IMPLICIT_ALLOCATOR, type)); 130 } 131 132 /** 133 * Determine whether a Type has the "const" qualifier set, 134 * without looking through typedefs that may have added "const" at a 135 * different level. 136 */ 137 public boolean isConstQualifierdType() { 138 return Index_h.clang_isConstQualifiedType(type) != 0; 139 } 140 141 /** 142 * Determine whether a Type has the "volatile" qualifier set, 143 * without looking through typedefs that may have added "volatile" at 144 * a different level. 145 */ 146 public boolean isVolatileQualified() { 147 return Index_h.clang_isVolatileQualifiedType(type) != 0; 148 } 149 150 public String spelling() { 151 return LibClang.CXStrToString(allocator -> 152 Index_h.clang_getTypeSpelling(allocator, type)); 153 } 154 155 public int kind0() { 156 return CXType.kind$get(type); 157 } 158 159 private long size0() { 160 return Index_h.clang_Type_getSizeOf(type); 161 } 162 163 public long size() { 164 long res = size0(); 165 if(TypeLayoutError.isError(res)) { 166 throw new TypeLayoutError(res, String.format("type: %s", this)); 167 } 168 return res; 169 } 170 171 public TypeKind kind() { 172 int v = kind0(); 173 TypeKind rv = TypeKind.valueOf(v); 174 // TODO: Atomic type doesn't work 175 return rv; 176 } 177 178 public Cursor getDeclarationCursor() { 179 return new Cursor(Index_h.clang_getTypeDeclaration(IMPLICIT_ALLOCATOR, type)); 180 } 181 182 public boolean equalType(Type other) { 183 return Index_h.clang_equalTypes(type, other.type) != 0; 184 } 185 186 @Override 187 public boolean equals(Object other) { 188 if (this == other) { 189 return true; 190 } 191 if (!(other instanceof Type)) { 192 return false; 193 } 194 return equalType((Type) other); 195 } 196 197 @Override 198 public int hashCode() { 199 return spelling().hashCode(); 200 } 201 }