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 }